这是我参与新手入门的第3篇文章
前言:
作用域插槽,简而言之,就是带数据的插槽,要求在slot上面绑定数据,供将来使用组件时使用。
为什么使用作用域插槽?
插槽让我们可以自定制内容,但当我们想给插槽注册事件时,发现行不通,因为具名插槽和匿名插槽都是不携带任何数据的,所以根本获取不到数据项的id。
案例分析:
比如这个小demo需求:点击删除按钮,删除对应项:
结构分析:
插槽里放的是删除按钮,三句歌词是子组件从父组件中接收的,然后遍历数据生成页面。
<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)
}
}
复制代码
看效果–删除成功啦:
最后,完整代码献上:(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