Vue.slot原理及slot是如何实现的
本篇内容介绍了“Vue.slot原理及slot是如何实现的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
成都创新互联长期为近千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为河津企业提供专业的做网站、成都做网站,河津网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制开发。
一、回顾 slot
用法
1. 默认插槽
默认插槽
页面展示效果如图:
2. 具名插槽
接着上述的案例,添加具名插槽
header
,代码如下:header 具名插槽
默认插槽
如上代码块可以发现:
子组件中的
slot标签
带上了一个名为name
的属性,值为header
父组件中的
template标签
带上了v-slot
的属性,值为header
页面展示效果如图:
3. 作用域插槽(slot-scope)
再接着上述案例,添加作用域插槽
footer
,代码如下header 具名插槽
默认插槽
footer 具名 + 作用域插槽
{{ slotProps.footerInfo.text }}
如上代码块可以发现:
子组件中的
slot标签
除了有name=footer
的属性,还有一个:footerInfo="footerInfo"
的属性(作用就是传递子组件数据)父组件中的
template标签
不仅有v-slot:footer
,并且还有一个赋值操作="slotProps"
,在模版的双括号语法中,直接通过slotProps
访问到 子组件的footerInfo
页面展示效果如图:
好了,简单回顾完用法后,笔者在这里先提三个问题:
普通插槽、 作用域插槽 的 vNode 是在哪个环节生成的,render 父组件时还是子组件时?
作用域插槽 为什么能在父组件访问到子组件的数据?
普通插槽 跟 作用域插槽 在实现上有区别吗?
我们带着疑问接着往下看!
二、不同
slot
的编译区别我们根据上述最终的案例代码,执行一下打包命令,看看 Vue 在编译模板的时候,是怎么处理我们的
slot
的!事不宜迟,赶紧build
一哈~(偷偷告诉大?,Vue
处理 作用域插槽跟 普通插槽的差异就是从编译开始的,也就是 render函数 会有所不同)这里笔者顺便使用
v2.5
的具名插槽写法给大?参照一下(对具名插槽header做改写,使用slot="header"
的写法),大家可以看下v2.6
、v2.5
具名插槽的 写法、实现 上的区别~反正也不难,也就顺便带出来看看了上图左边是
v2.6
、右边是v2.5
的,这里,我们集中关注:
scopedSlots
属性。使用作用域插槽的footer
的 render函数 是放在scopedSlots
里的,并且 函数中 还有接收一个参数
my-slot
的children
。可以发现,默认插槽的render函数
一直都是作为当前组件的childre节点
,放在 当前 组件render函数 的第三个参数中关注
header
两种具名插槽写法的区别。
v2.6中,我们使用了具名插槽,但是又未使用 作用域插槽的 header 也被放在了
scopedSlots
,但是函数的参数为空,这点跟作用域插槽有区别。v2.5中, 具名插槽header 仅仅作为
my-slot组件
的children节点,并且其render函数的第二个参数中有一个slot
的属性。其实根据上述编译后的结果,我们不妨这样猜测:
默认插槽直接在父组件的
render
阶段生成vNode
。
子组件
render
时,可能通过某种手段取得已经生成好的插槽vNode
用作自己的slot
节点。因为观察上述默认插槽的render函数:
e("h2", [t._v("默认插槽")])
,直接就是my-slot
组件的childre节点(位于my-slot
组件的第三个参数)。作用域插槽是在子组件
render
阶段生成vNode
。
因为我们观察作用域插槽
footer
的编译后结果,其不作为my-slot
组件的 children,而是被放在了my-slot
组件的 第二个参数data
中的一个scopedSlots属性
里。并且,作用域插槽的 render 函数 外层的 funciton 接收了一个参数。如果在执行子组件 render 的时候调用,那完全可以拿到子组件的数据。
这里放出具体的 作用域插槽打包后代码,大家一看就很清晰了:
{ scopedSlots: t._u([ { key: "footer", // 函数接收了一个参数n fn: function (n) { return [ // h2 标签的 render 函数 e("h2", [t._v("footer 具名 + 作用域插槽")]), // p 标签的 render 函数,这里可以看到编译后是:n.footerInfo.text e("p", [t._v(t._s(n.footerInfo.text))]) ] } } ]) }三、
slot
实现原理1. 断点调试
为了方便大家看调试结果,当前项目的组件结构主要是这样,有三大层:
Vue
->->
这里笔者在运行时代码
initRender()
、renderSlot()
中,打上 debugger,直接带大火看看执行流程。这里简单介绍下两个方法:
initRender:获取
vm.$slot
。组件初始化时执行(比如执行到my-slot组件
时,可从vm.$slot 获取父组件中的slot vNode
,也就是我们的 默认插槽)renderSlot:把组件的
slot
替换成真正的插槽vNode
接下来直接看实验截图:
1、先是进入
initRender()
(这里跳过初始化大Vue
、App
的过程)。直接到初始化my-slot组件
过程。【 简单解释:由于App组件
执行render
得到 App组件vNode,在patch
过程中 遇到vue-component-my-slot
的 vNode ,又执行my-slot组件
的 初始化流程。】
我们不难发现,图中此时正值
my-slot组件
的init
阶段。
再往下执行,我们可以得到 App组件中的
的vNode,赋值给
默认插槽
vm.$slot
(这里我们记住,默认插槽的 vNode 已经得到)2、再是进入
renderSlot()
。接着上面继续单步执行,会走到renderSlot
中。这时候,已经进入到my-slot组件
的render
阶段了。回顾第一步中,此时我们手握 默认插槽的vNode,并存在vm.$slot.default
中header插槽
按顺序走,先是 render 排第一的 header 的 vNode。如图所示,会走到断点处,我们接着单步
直接进入执行我们 header插槽 的render函数执行处。根据调试步骤,我们可以肯定,放置在
scopedSlots属性
中的 render函数,是在子组件 render 的时候执行
得到 header插槽 的 vNode
默认插槽
继续单步走,这次轮到 默认插槽 了!如图所示,这里的
key
正是'default'
。可以发现,这里并没有像上面 header插槽 一样,去执行 render,而是直接将我们之前得到的 插槽vNode返回了。
得到 default插槽 的 vNode
作用域插槽
前面都跟 header插槽 一致,都是会在 my-slot 组件中 执行插槽的 render。我们直接单步到 render 处看看有什么区别。这里可以得出,function处传入的参数正是我们子组件
my-slot
的data
数据,这就是为什么我们在App组件
能通过作用域插槽
访问到子组件数据的原因了
最后也是返回 footer插槽 的vNode。好了,验证过程结束~
2. 总结插槽实现原理
其实上面的流程只是论证过程,大家不可以不必深陷其中。笔者在这里直接根据实践过程,给大伙总结出结论!也就是要回到我们一开始的三个问题!
1、普通插槽、 作用域插槽 的 vNode 是在哪个环节生成的,render 父组件时还是子组件时?
默认插槽,不管
v2.5
、v2.6
的写法,都是在 父组件中生成vNode
。vNode
存在vm.$slot
中。待子组件render
到插槽时,会直接拿到 父组件的vNode
具名插槽两个版本情况不一。根据编译结果可知:
v2.5
的写法,跟默认插槽是一样的,在父组件生成vNode,子组件直接拿来用
v2.6
中,直接时在 子组件 中才去执行插槽render
,生成插槽vNode
。作用域插槽。不管版本,都是在子组件中进行render的。
大家不妨这么理解,模版编译后,只要是被放在 scopeSlots属性中的插槽,都会在子组件执行 render 的时候才会去生成vNode。
2、作用域插槽 为什么能在父组件访问到子组件的数据?
作用域插槽只有子组件render的时候,才会执行render生成vNode。并且,作用域插槽的 render 函数能接参数,从而获得子组件的数据。就是这样形成了作用域插槽!所以我们能在父组件中,访问到子组件的data数据。
3、普通插槽 跟 作用域插槽 在实现上有区别吗?
有区别。
普通插槽。如果是
v2.5
,具名插槽 和 默认插槽 都只在 父组件 render 的时候生成 vNode,子组件要 渲染slot 的时候,直接在父组件实例的 $slot 中获取已经是vNode的数据。普通插槽。如果是
v2.6
,具名插槽 虽然是在子组件中执行的 render,但是其不接收参数。作用域插槽。不管
v2.5
还是v2.6
,都只在 子组件执行 render,并且能接收参数。“Vue.slot原理及slot是如何实现的”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!
名称栏目:Vue.slot原理及slot是如何实现的
标题网址:http://myzitong.com/article/jcsocs.html