Vue 使用 slot(插槽) 分发内容

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xukongjing1/article/details/86030307

当需要让组件组合使用,混合父组件的内容与子组件的模板时,就会用到 slot,这个过程叫做内容分发(transclusion)。它有两个特点:

  • 组件不知道它的挂载点会有什么内容。挂载点的内容是由它的的父组件决定的。
  • 组件很可能有它自己的模板。

props传递数据、events触发事件和 slot 内容分发就构成了 Vue 组件的3个 API 来源,再复杂的组件也是由这3部分构成的。

1.单个slot

在子组件内使用特殊的<slot>元素就可以为这个子组件开启一个 slot (插槽),在父组件模板里,插入在子组件内的所有内容将替代子组件 <slot> 标签以及它的内容。示例代码如下:

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    <child-component>
      <p>分发的内容</p>
      <p>更多分发的内容</p>
    </child-component>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('child-component', {
  template: `
    <div>
      <slot>
        <p>如果父组件没有插入内容,我将作为默认出现</p>
      </slot>
    </div>
  `,
  data(){
    return{
      message: '子组件内容'
    }
  }
})
var app = new Vue({
  el: '#app',
}) 
</script> 
 </body>
</html>

 

子组件 child-component 的模板内定义了一个 <slot> 元素,并且用一个 <p>作为默认的内容,在父组件没有使用 slot 时,会渲染这段默认的文本;如果写入了 slot,那就会替换整个 <slot> 。

2.具名 slot

给 <slot> 元素指定一个 name 后可以分发多个内容,具名Slot 可以与单个 Slot 共存。

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    <child-component>
      <h2 slot='header'>标题</h2>
      <p>正文内容</p>
      <p>更多的正文内容</p>
      <div slot="footer">底部信息</div>
    </child-component>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('child-component', {
  template: `
    <div class="container">
      <div class="header">
        <slot name="header"></slot>
      </div>
      <div class="main">
        <slot></slot>
      </div>
      <div class="footer">
        <slot name="footer"></slot>
      </div>
    </div>
  `,
  data(){
    return{
      message: '子组件内容'
    }
  }
})
var app = new Vue({
  el: '#app',
}) 
</script> 
 </body>
</html>

子组件声明了3个 <slot> 元素,其中在<div class="main">内的<slot>没有使用name特性,它将作为默认 slot 出现,父组件没有使用 slot 特性的元素与内容都将出现在这里。 

如果没有指定默认的匿名 slot,父组件内多余的内容片断都将被抛弃。

3.作用域插槽 

作用域插槽是一种特殊的 slot ,使用一个可以复用的模板替换已渲染元素。

作用域插槽具代表性的是列表组件,允许组件自定义应该如何渲染列表每一项。

扫描二维码关注公众号,回复: 4995971 查看本文章
<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    <child-component>
      <template scope="props">
        <p>来自父组件的内容</p>
        <p>{{props.msg}}</p>
      </template>
    </child-component>
    <br/>
    <my-list :books="books">
      <template slot="book" scope="props">
        <li>{{props.bookName}}</li>
      </template>
    </my-list>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('child-component', {
  template: `
    <div class="container">
      <slot msg="来自子组件的内容"></slot>
    </div>
  `,
  data(){
    return{
      message: '子组件内容'
    }
  }
})
Vue.component('my-list', {
  props:{
    books:{
      type: Array,
      default: function(){
        return [];
      }
    },
  },
  template: `
    <ul>
      <slot name="book" v-for="book in books" :book-name="book.name">
      <!--这里也可以写默认slot 内容-->
      </slot>
    </ul>
  `,
})
var app = new Vue({
  el: '#app',
  data:{
    books:[
      { name: '《Vue.js 实战》'},
      { name: '《JavaScript 语言精辟》'},
      { name: '《JavaScript 高级程序设计》'}
    ]
  }
}) 
</script> 
 </body>
</html>

子组件 my-list 接收一个来自父级的 props 数组 books,并且将它在 name 为 book 的 slot 上使用 v-for 指令循环,同时暴露一个变量 bookName。 

4.访问 slot 

Vue.js 2.x 提供了用来访问被 slot 分发的内容的方法 $slots。

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    <child-component>
      <h2 slot="header">标题</h2>
      <p>正文内容</p>
      <p>更多正文内容</p>
      <div slot="footer">底部信息</div>
    </child-component>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('child-component', {
  template: `
    <div class="container">
      <div class="header">
        <slot name="header"></slot>
      </div>
      <div class="main">
        <slot></slot>
      </div>
      <div class="footer">
        <slot name="footer"></slot>
      </div>
    </div>
  `,
  mounted(){
    var header = this.$slots.header;
    var main = this.$slots.default;
    var footer = this.$slots.footer;
    console.log('footer',footer);
    console.log(footer[0].elm.innerHTML);
    console.log('main',main);
  }
})
var app = new Vue({
  el: '#app',
}) 
</script> 
 </body>
</html>

 

通过 $slots 可以访问某个具名 slot,this.$slots.default 包括了所有没有被包含在具名 slot 中的节点。

猜你喜欢

转载自blog.csdn.net/xukongjing1/article/details/86030307