vue3 --插槽

890 阅读3分钟

写在前面:组件有各自编译作用域---父级模板里的所有内容都是在父级作用域中编译的,子模板里的所有内容都是在子作用域中编译的

理解插槽

vue文档里说,将<slot>元素作为承载分发内容的出口,乍一看,确实不好理解。 我对slot的通俗理解: 因为组件有各自编译作用域,直接在父级模板里的子级标签中间填充内容是无效的,毕竟子级标签是我们自己创建出来的,不是HTML自带标签

//父组件
<template>
    <div>
        <Child><p>儿子,这是我要写给你的内容...</p></Child> 	//这是在父组件中定义的内容,子组件无法收到
    </div>
</template>

如果你确实想在这中间填充内容,怎么办? 那就得父子组件间建立通信。预先在相应的子组件中声明一下,给你要填充的内容留个坑位,于是就有了<slot></slot>

//子组件
<template>
    <div>
        <slot></slot>	//给父组件要填充的内容留个坑位,相当于父子组件建立了通信
    </div>
</template>
//父组件
<template>
    <div>
        <Child><p>儿子,我准备给你打生活费了</p></Child> 	//父子组件建立通信后,子组件可以接受到填充内容,并在后续渲染
    </div>
</template>

可是如果希望根据坑位坐标,快速找到位置 那就需要在子组件中通过<slot name="xxx"></slot>提前标注, 在父组件中在要显示的标签里添加slot="xxx"'属性,表示这条信息需绑定到某一个具体的坑位

//父组件
<template>
    <div>
        <Child>
            <span>5000 or </span>
            <span slot='ok'>10000</span>
        </Child> 	
    </div>
</template>
//子组件
<template>
    <div>
        <slot></slot>	//默认插槽,将匹配<span>5000 or </span>
        <slot name="ok"></slot> //具名插槽,将匹配<span slot='ok'>10000</span>
    </div>
</template>

如果子组件中的slot标签中有内容表示什么意思? 父子组件已建立好通信,可父组间鸽了子组件,没有“填充内容”,子组件则会显示默认内容

笔记部分

理解了插槽之后,就开始基于Vue3做点正式的笔记,(可以点击blog.csdn.net/marendu/art…) 在Vue3中,用template标签包裹要填充的内容,v-slot属性也需定义在template标签上,只有一种例外情况,就是默认插槽 v-slot:的语法糖是#,但后面必须有插槽名,例如v-slot:default 等价于 #default

插槽有三种

默认插槽

//父组件 (Child外层有templat>div标签,此处省略,方便观看)
<Child>
    <template v-slot:default>
        <p></p>
    </template>
</Child>

//也可以是这样,属于例外情况
//父组件
<Child v-slot:default>
	<p></p>
</Child>

具名插槽

//父组件
<Child>
    <template v-slot:xxx>	//绑定名称
        <p></p>
    </template>
    <template v-slot:[动态插槽名]>	//动态插槽名,即通过data的属性值来控制插槽名,以动态更新
        <p></p>
    </template>
</Child>

//子组件
<template>
    <div>
        <slot name=xxx></slot>
        <slot name=xxx></slot>
    </div>
</template>

作用域插槽

作用域插槽的作用即延展子模板中数据的作用域,使得在父级模板中也可使用子模板中的数据

//父组件
<Child>
    <template v-slot:num="slotProps">
        <p>{{slotProps.value}}</p>	//访问子组件中“num”插槽的value属性值
    </template>
    
    <template v-slot:default="slotProps">
        <p>{{slotProps.price}}</p>	//访问子组件中对应默认插槽的price属性值
    </template>
    
    <template v-slot:name="{uname: myname}">
        <p>{{myname}}</p>	//访问子组件中对应“name”插槽的uname属性值,采用解构赋值的方式
    </template>
</Child>

//子组件
<template>
    <div>
        <slot name="num" :value="value"></slot>
        <slot :price="price"></slot>
        <slot name="name" :uname="uname"></slot>
    </div>
</template>

插槽的实现原理(/过程):

当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.$slot中,默认插槽
为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,
遇到slot标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,
则可称该插槽为作用域插槽

参考:

Vue入门之slot属性 - 简书 (jianshu.com)

「2021」高频前端面试题汇总之Vue篇 (上) (juejin.cn)

vue2到vue3中插槽slot变化详解---从slot,slot-scope到v-slot的变化_marendu的博客-CSDN博客