vue 插槽
网上有很多帖子再说插槽的问题= =,emmm我这里只是实践之后的记录。用于自己复习用的,当然包括最近一段时间的开发任务
插槽的作用
让用户可以拓展组件,去更好地复用组件和对其做定制化处理
默认插槽
// 父组件
<template>
<slot-default>这是传入的</slot-default>
</template>
<script>
import slotDefault from "./slot";
export default {
components:{
slotName,
}
}
</script>
// 子组件
<template>
<button class="slotDefault">
<slot>这是父组件没有传值时候渲染的值</slot>
</button>
</template>
// 渲染出
<button class="slotDefault">这是传入的</button>
从上可以看出我们的slot-default标签内的值被传入到slot中。
具名插槽
子组件的slot带有name属性,没有name的slot被赋予默认的default值,在vue2.6之后更改以往的slot=slot_name的写法改为v-slot:slot_name
//父组件
<template>
<slot-name>
<template v-slot:header>{{slotName.header}}</template>
<template v-slot:footer>{{slotName.footer}}</template>
</slot-name>
</template>
<script>
import slotName from "./slotName";
export default {
components:{
slotName,
},
data(){
return {
slotName:{
header:'这是header !',
footer:'这是footer !'
},
}
}
}
</script>
//子组件
<template>
<div class="slotName">
<header>
<slot name="header"></slot>
</header>
<main>
<slot>这是躯干</slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
//渲染出的结果
<div class="slotName">
<header>这是header !</header>
<main>这是躯干</main>
<footer>这是footer !</footer>
</div>
这个例子中我们可以看到,父组件向子组件传递值得一种方式,slotName被传入到子组件中显示
作用域插槽
那我们可以通过父组件传递值给子组建,那么插槽也能吧子组建的值传递给父组件。在vue2.6以上采用v-slot=data的形式废弃了slotScope=data的形式。
//父组件
<template>
<myslot v-slot:name='slotScope'>{{ user.firstName }}</myslot>
</template>
<script>
import myslot from './myslot';
export default {
components: {
myslot
}
}
</script>
//子组建
<template>
<div>
<span>
<slot name="name" :user='user'>{{user.lastNameName}}</slot>
</span>
</div>
</template>
<script>
export default {
data () {
return {
user:{
firstName:'gerace',
lastName:'haLi'
}
}
}
}
</script>
//渲染后
<div>
<span>gerace</span>
</div>
以上就是插槽的所有内容
工作中遇到的问题是写了一个类似于gitee企业版的search组件,一开始写的并不优雅,后来想用插槽改装成一个通用组件后来由于数据更新失败就采用了另外一种方式,当时以为是插槽并不能修改子组建的值,但是今天进行尝试之后发现是可以的,附上demo
- 父组件
<template>
<div>
<slot-scope>
<template v-slot:default="{ choice }">
<ul>
<template v-for="(value,key) in slider">
<li :class="value.choice ? 'choice':''" :key="value.id" @click.stop="getOneLi(choice,value,key)">{{value.title}}</li>
</template>
</ul>
</template>
</slot-scope>
</div>
</template>
<script>
import slotScope from "./slotScope";
let data = [
{
"id": 1,
"path": "product/huawei",
"title": "华为"
},
{
"id": 2,
"path": "product/oppo",
"title": "OPPO"
},
{
"id": 3,
"path": "product/vivo",
"title": "VIVO"
}
]
export default {
components:{
slotScope,
},
data(){
return {
slider:[]
}
},
mounted(){
//模拟axios网络请求
setTimeout(() => {
for(let item of data){
item.choice = false
}
this.slider = data
}, 1000);
},
methods:{
getOneLi(choice,value,key){
value.choice = !value.choice
if(choice[key])
this.$delete(choice,key)
else{
this.$set(choice,key,{...value})
}
}
}
}
</script>
<style scoped>
.choice{
background: coral;
}
</style>
- 子组建
<template>
<div class="slotScope">
<div>
<template v-for="key in Object.keys(choice)">
<span :key="key">{{choice[key].title}}</span>
</template>
</div>
<slot :choice="choice"></slot>
</div>
</template>
<script>
export default {
data(){
return {
choice:{}
}
}
}
//生成的choice的数据结构
{
0: {
choice: true
id: 1
path: "product/huawei"
title: "华为"
}
}
</script>
这样父组件改变了choice的值并且更改视图变化
另外关于Object插入key改变不了vue视图可以这样做
- 使用this.$set(Object,key,value)
- 创建新的对象
- { …oldValue , key:newValue }
- Object.assgin({},oldValue,newValue)