搞懂Vue的作用域插槽—从分析到案例演示

这是我参与新手入门的第3篇文章

前言:

作用域插槽,简而言之,就是带数据的插槽,要求在slot上面绑定数据,供将来使用组件时使用。

为什么使用作用域插槽?

插槽让我们可以自定制内容,但当我们想给插槽注册事件时,发现行不通,因为具名插槽和匿名插槽都是不携带任何数据的,所以根本获取不到数据项的id。

案例分析:

比如这个小demo需求:点击删除按钮,删除对应项:

微信截图_20210711123246.png

结构分析:

插槽里放的是删除按钮,三句歌词是子组件从父组件中接收的,然后遍历数据生成页面。

<script>
  Vue.component('my-music',{
    template:`
    <div>
      <h2>歌词收录</h2>
      <ul>
        <li v-for='item in music'>  //遍历接收到的内容进行渲染视图
           <slot></slot>            //匿名插槽,用来存放删除按钮
        </li>
      </ul>
    </div>
    `,
    props:['music']   //用来接收父组件的值
  })
const vm = new Vue({
   el: '#app',
   data: {
     msg: 'hello vue',
     list:[
       {id:1,classical:'红雨瓢泼泛起了回忆怎么潜'},
       {id:2,classical:'执子手吹散苍茫茫烟波'},
       {id:3,classical:'就回来吧 回来吧 有人在等你呢'},
     ]
   }
}
复制代码

要想通过删除按钮来删除对应项,那肯定要拿到对应项的id,一般我们会这样想,item.id不就拿到id了吗,这么easy,比如下段代码:

  <div id="app">
     <my-music :music='list'>
          <button @click=del(item.id)>删除</button>
      </my-music>
  </div>
复制代码

但是,你肯定是忽略了 模块的范围原则:

模块属于谁,那么用的就是谁的data和method,这是在div中,是父组件范围,而item本来就是从父组件接收来的数据,在子组件中我们就用它来渲染了页面,插槽又没有携带任何数据。所以,如果这么简单,也就没了这篇文章存在的意义啦

那么,就迎来了文章的主题–作用域插槽。

开头我们有讲,作用域插槽就是需要在slot上面绑定数据,供将来使用组件时使用 ,意思就是要我们在子组件里的slot就预先把数据存起来。

步骤如下:

1.给插槽以添加属性的方式,传值

添加的所有属性,都会被收集到一个对象中,为第二步做铺垫。

  Vue.component('my-music',{
    template:`
    <div>
      <h2>歌词收录</h2>
      <ul>
        <li v-for='item in music'>
           {{item.classical}}
           <slot :zzz='item'></slot>
        </li>
      </ul>
    </div>
    `
复制代码

2.在使用组件时,我们需要将插槽放在template标签里

将第一步添加到插槽里的所有内容都赋值给一个变量,那么这个template里就形成了作用域插槽,这个时候插槽里使用的数据就不在是父组件里的了,而是自己的作用域里的。

   <div id="app">
     <my-music :music='list'>
<!--匿名插槽写在template里,默认内容要加 v-slot:default  -->
        <template v-slot:default='obj'>   
          <button @click=del(obj.zzz.id)>删除</button>
        </template>
      </my-music>
  </div>
复制代码

3.给组件注册删除事件,通过过滤器的方式模拟删除数据

   methods:{
     del(id){
     console.log(id);
      this.list=this.list.filter(item => item.id !== id)
     }
   }
复制代码

看效果–删除成功啦:

微信截图_20210711123822.png

最后,完整代码献上:(ps:记得引入vue.js哈)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      #app{
        width: 600px;
        margin: 100px ;
        background-color: #8bacc3;
        padding: 10px;
        box-shadow: 10px 10px 5px #888888;;
      }
      ul{
        list-style: none;
      }
      ul li{
        margin: 20px;
      }
      button{
        float: right;
      }
    </style>
</head>
<body>
   <div id="app">
     <my-music :music='list'>
        <template v-slot:default='obj'>
          <button @click=del(obj.zzz.id)>删除</button>
        </template>
      </my-music>
  </div>
  <script src="https://juejin.cn/post/vue.js"></script>
  <script>
  Vue.component('my-music',{
    template:`
    <div>
      <h2>歌词收录</h2>
      <ul>
        <li v-for='item in music'>
           {{item.classical}}
           <slot :zzz='item'></slot>
        </li>
      </ul>
    </div>
    `,
    props:['music']
  })
const vm = new Vue({
   el: '#app',
   data: {
     msg: 'hello vue',
     list:[
       {id:1,classical:'红雨瓢泼泛起了回忆怎么潜'},
       {id:2,classical:'执子手吹散苍茫茫烟波'},
       {id:3,classical:'就回来吧 回来吧 有人在等你呢'},
     ]
   },
   methods:{
     del(id){
     console.log(id);
      this.list=this.list.filter(item => item.id !== id)
     }
   }
})
</script>
</body>
</html>
复制代码

如果你觉得还不错的话,留个赞再走呗,

如果有哪里不恰当的,欢迎指正。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享