Vue Slot 层级、作用域详解

    xiaoxiao2022-07-07  146

    vue slot插槽的作用域在官方教程中有一条说明: “父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。” 父级模版可以通过prop把参数传递给子级模版,但是反过来是不推荐的。 插槽v-slot就是用来反向传参的。

    首先来看一下层级关系,一下是html页面中的dom元素实例

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Language" content="zh-cn"> <title>Template</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="components-demo" level="0"> <im-level-11 title="how are you." level="1"> {{ posts[2].title }} <im-level-12 :name="posts[1].title" level="1"> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} {{ posts[0].title }} </template> </im-level-12> </im-level-11> </div> <script src="template.js"></script> </body> </html>

    同步对照js代码如下

    Vue.component('im-level-11',{ props:['title'], data(){ return {count: 5,level:2} }, template:` <div> <label> {{ title }} </label> <button @click='count++'> You clicked me {{ count }} times. </button> <slot></slot> </div> ` }); Vue.component('im-level-12',{ props:['name'], data(){ return { user:{ lastName:"AJS", firstName:"Silvan" }, level:2 }; }, template:` <div> <label> {{ name }} </label> <slot v-bind:user="user"> {{ user.lastName }} </slot> </div> ` }) var vm = new Vue({ el: "#components-demo", data: { posts: [ { id: 1, title: 'My journey with Vue' }, { id: 2, title: 'Blogging with Vue' }, { id: 3, title: 'Why Vue is so fun' } ], level:1 } });

    其中components-demo是根节点,在js中vue实例被绑定到了该节点上。 那么components-demo 作为level0 js代码中的vm Vue实例是level1 两个组件im-level-11 im-level-12 实际上是和vm实例同一级的。 在html中可以看到,im-level-11 和 im-level-12 可以直接调用vm实例中的posts数组对象, 虽然im-level-11 和 im-level-12 在html中是嵌套实现的,但是在js中是同级申明的。

    在 im-level-11 和 im-level-12 组件内部,作为level2,他们各自的template模版只能直接调用组件内部的数据。

    这个时候,子级给父级反向传参可以看im-level-12 的实现 im-level-12 内部有一个user对象,可以直接使用user.lastName值, 而父级level1要直接用同样的user对象则会报错。

    在level2的插槽上即 im-level-12的 绑定user,把自己的user对象传去去。 在level1调用组件时直接使用 来接收传出的对象,该对象作为slotProps的属性存在,可以直接用过slotProps.user来访问。

    "slotProps"只是一个自定义名称,可以随便改。

    这里要吐槽官网的描述,也可能是我理解能力太差,之前一直搞混了。官网有这么一段说明:

    <span> <slot>{{ user.lastName }}</slot> </span>

    我们想让它的后备内容显示用户的名,以取代正常情况下用户的姓,如下:

    <current-user> {{ user.firstName }} </current-user>

    我一直没搞明白后备内容不是user.lastName 显示了用户的姓么,怎么又变成名了。还纠结了半天,官网指的lastName难道按照中国人的习惯是名字?

    后来终于理解了,现在后备内容区域显示的是姓,要把他用组件改为名字显示。 这一下也终于搞明白,这个user是从子级组件里通过插槽slot传出来给父级组件渲染时调用的。

    终于弄明白这个插槽的逻辑了,加油!

    最新回复(0)