web前端

slot插槽

2020-04-13  本文已影响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
上一篇下一篇

猜你喜欢

热点阅读