(深入Vue组件)6.slot插槽+作用域插槽

(深入Vue组件)6.slot插槽+作用域插槽

关键词:插槽、具名插槽、作用域插槽

一、什么时候用到slot

父组件要传递内容给子组件

  • 方式:属性形式,向子组件传值
<body>
  <div id="root">
    <child content='<p>miya</p>'></child>
  </div>
  <script>
    Vue.component('child',{
       props: ['content'],
       template: `<div>
                     <p>hello</p>
                     <div v-html="this.content"></div>
                  </div>`
    })

    var vm = new Vue({
      el: "#root"
    })
  </script>
</body>

你可以对照源代码看到,事实上父组件向子组件传值之后,子组件接收了父组件的属性传值,html的页面代码,如图所示:

二、父组件向子组件优雅地传递dom结构

  • 现实需求:当子组件部分内容是根据父组件传递过来的内容显示时(会出现这样的状况:父组件传递内容给子组件含有较多内容),就无法只用一个 div 进行包裹
  • 问题出现:在父组件的子组件里插入一些内容,子组件如何使用插槽中的内容?
  • 解决方法:Vue内置语法 : slotslot 里插入父组件向子组件插入的内容

代码如下:

<body>
  <div id="root">
    <child>
        <p>miya</p>
    </child>
  </div>
  <script>
    Vue.component('child',{
       template: `<div>
                    <p>Hello</p>
                    <slot></slot> //重点在这
                  </div>`
    })

    var vm = new Vue({
      el: "#root"
    })
  </script>
</body>

试一下吧,传递的内容就能正常显示出来,出现“hello miya”

1、替换插入的一些dom标签都是没有问题

 <div id="root">
   <child>
       <h1>miya</h1>   //重点在这
   </child>
 </div>
 
<script>
 Vue.component('child',{
     template: `<div>
                 <p>Hello</p>
                 <slot></slot> //重点在这
                </div>`
  })
 </script>

试一下吧,“miya”会是大标题的字体样式

2、slot插槽也可以定义默认值 父组件如果不传递内容,子组件所传递的slot插槽内容就会被显示

 <div id="root">
   <child>
   </child>
 </div>
 
 <script>
  Vue.component('child',{
     props: ['content'],
     template: `<div>
                  <p>Hello</p>
                  <slot>默认内容</slot> //重点在这
               </div>`
   })
 </script>

试一下吧,父组件不传递内容,slot就会显示默认值

三、具名插槽的使用

1、出现问题:如果没定义父组件插入子组件的内容的唯一性,那么子组件接收多个插入内容,就会被一个slot同时占用并使用,如图显示:

2、解决办法:使用 具名插槽,给插槽起一个名字,对传递内容进行唯一性的标识

代码如下:分别命名父组件和子组件的插槽名

 <div id="root">
    <body-content>
        <div class="header" slot="header">header</div> //重点在这
        <div class="footer" slot="footer">footer</div> //重点在这
    </body-content> 
  </div>

  <script>
    Vue.component('body-content',{
       template: `<div>
                    <slot name="header"></slot>   //重点在这
                    <div class='content'>content</div>
                    <slot name="footer"></slot>   //重点在这
                  </div>`
    })

    var vm = new Vue({
      el: "#root"
    })
  </script>

3、具名插槽的默认性

调用父组件的时候没有传递插槽,那么如何传递插槽的默认值,如下:

 <div id="root">
   <body-content>     
      <div class="footer" slot="footer">footer</div> //重点在这,去掉了header部分的插槽
   </body-content>
 </div>
 <script>
    Vue.component('body-content',{
       template: `<div>
                    <slot name="header">default header</slot> //重点在这,默认值
                    <div class='content'>content</div>
                    <slot name="footer"></slot>
                  </div>`
    })

    var vm = new Vue({
      el: "#root"
    })
 </script>

试一下吧,父组件没传递header部分插槽的,子组件定义默认值,页面上相应地展示定义默认值。当然在子组件的插槽下,可以修改一些页面标签。

四、作用域插槽

子组件做循环显示列表 某一部分由外部传递进来 时,则使用 作用域插槽

<body>
     <div id="root">
         <child>
           <template slot-scope="props">
               <h1>{{props.item}}</h1>
	   </template>
         </child>
     </div>

   <script>
     Vue.component('child', {
       data: function(){
          return {
	    list: [1, 2, 3, 4]
	   }
       },
       template: `<div>
                    <ul>
                     <slot 
                        v-for="item of list"
                        :item=item
                     ></slot>
                   </ul>
                 </div>`
	})
		
	var vm = new Vue({
	   el:'#root'
	})
    </script>
</body>

子组件向父组件插槽里传数据,如 :item=item

父组件接收数据并需在外层使用 作用域插槽(必须用) <template></template>,同时声明属性名 接收子组件传递的数据,如 slot-scope="props" , 然后在dom标签使用该数据,通常用插值表达式接收具体数据。

编辑于 2019-02-26 09:48