slot插槽

作者: 姜治宇 | 来源:发表于2020-04-13 15:53 被阅读0次

    在vue中有个slot插槽的东西,很多同学不知道这玩意到底是干啥的。
    插槽么,突出的是一个字,哦。。。可别想歪了,咱思想都纯洁一点哈~~
    那具体怎么插呢?就是从父亲插到孩子。
    比如父亲定义一个header和footer的样式,希望给孩子拿过去使用,这样孩子就不用再定义一遍了。

    <Child>
        <header>这是父亲给孩子留下的东西-header</header>
        <footer>这是父亲给孩子留下的东西-footer</footer>
    </Child>
    

    插槽分了三种类型,分别是匿名插槽、具名插槽和作用域插槽,下面一一介绍之。

    匿名插槽

    匿名插槽,就是父亲定义了一些html标签,孩子拿过去直接用就行。
    粗暴的理解就是:父亲所有的东西都给孩子。
    父组件:

    <template>
      <div class="hello">
        <!--匿名插槽-->
        <Child1>
          <h1>这是父亲留下的东西</h1>
        </Child1>
    
      </div>
    </template>
    
    <script>
    import Child1 from './child1'
    
    export default {
      name: 'HelloWorld',
      components:{Child1},
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      }
    }
    </script>
    

    子组件child1.vue:

    <template>
      <div>
        <slot></slot>
        {{text}}
    
    
      </div>
    </template>
    <script>
      export default {
        name: 'Child',
    
        data () {
          return {
            text: '我是孩子-1'
          }
        }
      }
    </script>
    
    执行结果: 1.jpg

    具名插槽

    具名插槽就是父亲定义了一些html标签,会指定具体怎么使用。
    粗暴的理解就是:父亲只给孩子一部分东西。
    父组件:

    <template>
      <div class="hello">
        <!--具名插槽-->
        <Child>
          <h2 slot="header">这是父亲留下的header信息</h2>
          <div>这是父亲保留的内容</div>
          <h2 slot="footer">这是父亲留下的footer信息</h2>
    
        </Child>
    
      </div>
    </template>
    
    <script>
    import Child from './child'
    
    export default {
      name: 'HelloWorld',
      components:{Child},
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      }
    }
    </script>
    

    子组件child.vue:

    <template>
      <div>
        <slot name="header"></slot>
        {{text}}
        <slot name="footer"></slot>
      </div>
    </template>
    <script>
      export default {
        name: 'Child',
    
        data () {
          return {
            text: '我是孩子'
          }
        }
      }
    </script>
    
    执行结果: 2.jpg

    作用域插槽

    顾名思义,就是父亲定义了一个作用域,并且定义了这个作用域的逻辑,然后孩子拿过去具体实现它。
    父组件:

    <template>
      <div class="hello">
        <!--作用域插槽-->
        <Child2>
         
          <!--myscope是一个作用域标识-->
          <template slot-scope="myscope">
            <!--子组件要实现的是作用域下的item这个字段-->
            <span>{{myscope.item}}</span>
          </template>
    
        </Child2>
    
      </div>
    </template>
    
    <script>
    import Child2 from './child2'
    
    export default {
      name: 'HelloWorld',
      components:{Child2},
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      }
    }
    </script>
    
    

    子组件child2.vue:

    <template>
      <div>
        <ul>
          <li v-for="(v,k) in items" :key="k">
            <!--item字段要赋值实现-->
            <slot :item="k"></slot>:
            {{v}}
    
          </li>
        </ul>
      </div>
    </template>
    <script>
      export default {
        name: 'Child2',
    
        data () {
          return {
            items:['Webkit','Gecko','Trident','Blink']
          }
        }
      }
    </script>
    
    
    执行结果: 3.jpg

    插槽应用场景

    这里重点说一下作用域插槽。看个场景,比如有如下这一个列表页:

    tb.jpg
    列表项有图片、标题和描述,其中标红的描述部分出现了不一致。
    这个功能我们可以划分为父组件、列表项组件(list.vue)和描述组件(comment.vue)三部分。
    我们在父组件for循环列表项组件,点击描述信息会跳到商品详情。
    传统的做法是从父组件传递数据和跳转事件给list.vue,然后list.vue再将描述的文字信息和跳转事件继续传递到comment.vue,最后由comment.vue执行跳转。
    这样设计不太直观,而且有一定的耦合。因为跳转事件是发生在comment.vue的,凭什么让list.vue参与进来呢?
    好的设计是划分好组件各自的职责,组件只做自己应该干的事情。
    我们可以用slot优雅的解决这个问题。
    父组件:
    <template>
      <div class="hello">
    
        <ul>
          <li  v-for="(v,k) in dataList" :key="k">
            <List :item="v">
    
              <template slot-scope="myscope">
    
                <!--定义myscope.row字段,放在List去实现-->
                <Comment :comm="myscope.row.comment" @myclick="toDetail(myscope.row.id)"></Comment>
    
              </template>
    
            </List>
    
          </li>
        </ul>
    
      </div>
    </template>
    
    <script>
    import List from './list'
    import Comment from './comment'
    
    export default {
      name: 'HelloWorld',
      components:{List:List,Comment:Comment},
      data () {
        return {
          dataList:[
            {id:1,title:'商品1',comment:'这是商品1的描述'},
            {id:2,title:'商品2',comment:'这是商品2的描述'},
            {id:3,title:'商品3',comment:'这是商品3的描述'},
            {id:4,title:'商品4',comment:'这是商品4的描述'}
          ]
        }
      },
      methods:{
        toDetail(id){
          console.log('商品详情',id)
        }
      }
    }
    </script>
    

    list.vue:

    <template>
      <div>
        <div>
            商品名称:{{item.title}}
            <slot :row="item"></slot><!--实现row字段-->
        </div>
      </div>
    </template>
    <script>
    
      export default {
        name: 'List',
        props:{
          item:{
            required:true,
          }//继承父类的属性
        },
        data () {
          return {
    
          }
        }
      }
    </script>
    

    comment.vue

    <template>
      <div>
        <h3 @click="clickComment">{{comm}}</h3>
      </div>
    </template>
    <script>
      export default{
        name:'Comment',
        props:{
          comm:{
            required:true,
          }
        },
        methods:{
          clickComment(){
            this.$emit('myclick')
          }
        }
    
      }
    </script>
    
    运行结果: res.jpg

    相关文章

      网友评论

        本文标题:slot插槽

        本文链接:https://www.haomeiwen.com/subject/ofkimhtx.html