vue组件的内分发

定义

  1. 为了让组件可以组合,需要一种方式来混合父组件的内容与子组件自己的模板,这个过程称为内容分发。Vue.js实现了一个内容分发API,使用特殊的slot元素作为原始内容的插槽。
  2. 可以理解为slot就是个插槽,要分发的内容将要插到这个在子组件里预留好的插槽内(替换slot标签)。
  3. 插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示,以及怎样显示是由父组件来决定,最核心问题就是显不显示怎样显示。
  4. 插槽模板是slot,它是一个空壳子,因为它的显示隐藏以及最后用什么样的HTML模板显示由父组件控制的,但是插槽显示的位置却由子组件自身决定,slot写在组件template的什么位置,父组件传过来的模板就来就显示什么位置。

编译作用域

父组件模板的内容在父组件作用域内编译;

子组件模板的内容在子组件作用域内编译;

<child-tem>
   {{ message }}
</child-tem>

message应该绑定到父组件的数据;

下面这个错误是将父组件的一个指令绑定到子组件的属性方法:

<!-- childProperty是子组件的属性,上例不会如期那样工作,父组件不应该知道子组件的状态 -->
<child-component v-show='childProperty'></child-component>

如果要绑定作用域内的指令到一个组件的根节点,你应当在自己的模板上做:

Vue.component('child-component',{
   // 这才是正确的作用域内
   template:'<div v-show='childProperty'>child</div>'
   data:function(){
     return{
        childProperty:true
     }
})

单个slot

子组件至少要有一个 ‘slot’插口,不然父组件的内容将会被丢弃(被slot标签的内容替换)。如果子组件模板只有一个没有属性的slot时,父组件整个内容片段将插入到‘slot’所在DOM位置。并替换掉slot标签本身。

最初在‘slot’标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入内容是才显示备用内容。

<div id='app'>
   <h1>我是父组件的标题</h1>
   <my-component>
      <p>初始内容</p>
      <p>初始内容</p>
   </my-component> 
</div>
Vue.component('my-component',{
  template:'
    <div>
        <h2>我是子组件标题</h2>
        <slot>只有在没有要分发的内容时才显示</slot>
    </div>',
})

new Vue({
  el:'#app'
})

子组件slot的位置就是要分发的‘初始内容的2个p标签’


<div id='app'>
    <h1>我是父组件的标题</h1>
    <!-- 测试这个组件里没有要奋发的内容 -->
    <my-component><my-component>
</div>

具名slot

slot元素可以用一个特殊的属性name来配置如何分发内容。多个slot可以有不同名字,具名slot将匹配内容片段中对应slot特性元素

也可以有一个匿名slot,默认是slot,作为找不到匹配的内容片段的备用插槽。如果没有默认的slot,这些找不到匹配的内容片段将会被抛弃。

<div id='app'>
   <my-component>
       <h1 slot='header'>这是标题</h1>
       <p>第一个段落</p>
       <p>第二个段落</p>
       <p slot='footer'>联系信息</p>
   </my-component>
</div>
Vue.component('my-component',{
  template:'
  <div class='container'>
      <header>
          <slot name='header'></slot>
      </header>
      <main>
          <slot></slot>
      </main>
      <footer>
          <slot name='footer'></slot>
      </footer>   
  </div>',
})

new Vue({
  el:'#app'
})


作用域插槽

  1. 作用域是一种特殊类型的插槽,使用一个可重用模板替换已渲染元素。在子组件中,只需将数据传递到插槽,就像你将props传递给组件一样
  2. 也称作是带数据的插槽
<div id='app'>
   <my-component>
       <template scope='props'>
           <p>hello form parent</p>
           <p>{{ prosp.text }}</p>
       </template>
   </my-component>
</div>
Vue.commponent('my-component',{
   template:'
       <div class='child'>
           <slot text='hello'></slot>
        </div>
    ',
    props:['text']  
})

new Vue({
   el:'#app'
})


在父级中,具有特殊属性的scope的<template>元素必须存在,表示它是作用域插槽的模板。scope的值对应一个临时变量名,此变量接收从子组件中传递的props对象。

作用域插槽实现列表组件

    <div id="app">
        <h1>我是父组件的标题</h1>
        <my-component :items="items">
            <template scope="props" slot="item">
                <li>{{ props.text }}</li>
            </template>
        </my-component>
    </div>
  Vue.component('my-component',{
            template:'<ul><slot name="item" v-for="item in items" :text="item.text"></slot></ul>',
            props:[ 'text','items']
        });

        new Vue({
            el:'#app',
            data:{
                items:[
                    {text:'item1'},
                    {text:'item2'},
                    {text:'item3'}
                ]
            }
        })
****** 这编辑器真是太垃圾了  ******

深剖析作用域插槽

父组件

<div class="parent">
  <child msg="msg">
    <template scope="aaa">
      <span>{{ aaa.text }}</span>
      <span>{{ aaa.text2 }}</span>
    </template>
  </child>
</div>

子组件

<div class="child">
  <slot text="hi" text2="hello"></slot>
</div>

  • 这里的scope属性的值是一个变量名aaa,这个aaa指向一个对象{ text='hi',text2='hello'},这个对象正是子组件传递过来的<slot>标签属性的集合。因此我们可以通过<slot>标签属性绑定数据,父组件模板通过scope属性指定一个变量来接收。
  • 那为什么在注册组件时还要加上props选项?上面例子父组件给组件传递了msg这个数据<child msg='msg'>,此时子组件必须在props选项中声明msg变量才能接收。


猜你喜欢

转载自blog.csdn.net/like_jack/article/details/80660110