Home > Article > Web Front-end > Let’s talk about the principle of Vue.slot and let’s explore how slot is implemented!
This article will share with you Vue dry information and talk about the principles of Vue.slot that you may not know. I hope it will be helpful to everyone!
I believe that whether it is daily business development or encapsulation of basic components,
slot slot
often appears in our field of vision, because It provides a lot of convenience for our programming implementation. Maybe everyone is familiar with the usage ofslot
, whether it is named slot, or scope slot various usages, etc... Do you know how the bottom layer ofslot
andslot-scope
is implemented?
Easy to understand, You can take away 's Vue.slot
in 10 minutes Source code implementation analysis! ! ! Follow the author to explore how the slot slot
in Vue (v2.6.14)
is implemented! ! This article will mainly explain it in two parts:
Normal slots (named slots, default slots)
Scope slot
This article does not have obscure source code analysis, it is explained directly in vernacular, so no matter how familiar you are with the Vue source code, you can understand it. Through on-site debugging, you can see clearly how the slot
of Vue
is implemented. let's go go go! (Learning video sharing: vue video tutorial)
slot
Usage Let me first review the general usage of the slot. The usage of slot
here uses the new standard of 2.6.0 (this article will also explain how to write v2.5
and v2.6
What is the difference in source code implementation!).
If you want to learn more about usage, you can go to the official website to read Vue’s slot documentation in detail
https://cn.vuejs.org/v2/guide/components-slots.html
<!-- 子组件 --> <template> <div class="wrapper"> <!-- 默认插槽 --> <div class="main"> <slot></slot> </div> </template> <!-- 父组件 --> <my-slot> <template> <h1>默认插槽</h1> </template> </my-slot>
The page display effect is as shown in the figure:
Follow the above case, add a named slot header
, the code is as follows:
<!-- 子组件 --> <template> <div class="wrapper"> <!-- header 具名插槽 --> <header class="header"> <slot name="header"></slot> </header> <!-- 默认插槽 --> <div class="main"> <slot></slot> </div> </template> <!-- 父组件 --> <my-slot> <template v-slot:header> <h1>header 具名插槽</h1> </template> <template> <h1>默认插槽</h1> </template> </my-slot>
The above code block can be found:
in the subcomponent The slot tag
carries an attribute named name
, and the value is header
in the parent component The template tag
has the attribute v-slot
, and the value is header
The page display effect is as follows:
Following the above case, add the scope slot footer
, The code is as follows
<!-- 子组件 --> <template> <div class="wrapper"> <!-- header 具名插槽 --> <header class="header"> <slot name="header"></slot> </header> <!-- 默认插槽 --> <div class="main"> <slot></slot> </div> <!-- footer 具名 + 作用域插槽 --> <footer class="footer"> <slot name="footer" :footerInfo="footerInfo"></slot> </footer> </div> </template> <script> export default { name: "mySlot", data () { return { footerInfo: { text: '这是 子组件 footer插槽 的作用域数据' } } } } </script> <!-- 父组件 --> <my-slot> <template v-slot:header> <h1>header 具名插槽</h1> </template> <template> <h1>默认插槽</h1> </template> <template v-slot:footer="slotProps"> <h1>footer 具名 + 作用域插槽</h1> <p>{{ slotProps.footerInfo.text }}</p> </template> </my-slot>
The above code block can be found:
The slot tag
in the subcomponent except for name=footer
Attribute, there is also a :footerInfo="footerInfo"
attribute (its function is to pass the child component data)
template tag in the parent component
Not only has v-slot:footer
, but also has an assignment operation ="slotProps"
. In the double bracket syntax of the template, directly pass slotProps
After accessing the footerInfo
# page of the sub-component, the page display effect is as shown in the figure:
Okay, a brief review After finishing the usage, the author will ask three questions here:
Let’s read on with questions!
slot
Based on the final case code above, we execute the packaging command to see how Vue handles it when compiling the template. Our slot
's! Without further ado, hurry up and build
~ (Secretly tell everyone, Vue
handles scope slots and normal slots The difference starts from compilation, that is, the render function will be different)
Here I will use the named slot writing method of v2.5
to give you a reference (for named slots To rewrite the header, use slot="header"
), you can take a look at the writing and implementation of v2.6
, v2.5
The difference~ It’s not difficult anyway, so I took it out to have a look
上图左边是 v2.6
、右边是 v2.5
的,这里,我们集中关注:
scopedSlots
属性。使用作用域插槽的 footer
的 render函数 是放在 scopedSlots
里的,并且 函数中 还有接收一个参数
my-slot
的 children
。可以发现,默认插槽的 render函数
一直都是作为当前组件的childre节点
,放在 当前 组件render函数 的第三个参数中
关注 header
两种具名插槽写法的区别。
scopedSlots
,但是函数的参数为空,这点跟作用域插槽有区别。my-slot组件
的children节点,并且其render函数的第二个参数中有一个 slot
的属性。其实根据上述编译后的结果,我们不妨这样猜测:
默认插槽直接在父组件的 render
阶段生成 vNode
。
render
时,可能通过某种手段取得已经生成好的 插槽vNode
用作自己的 slot
节点。e("h1", [t._v("默认插槽")])
,直接就是 my-slot
组件的childre节点(位于 my-slot
组件的第三个参数)。作用域插槽是在子组件 render
阶段生成 vNode
。
footer
的编译后结果,其不作为 my-slot
组件的 children,而是被放在了 my-slot
组件的 第二个参数 data
中的一个 scopedSlots属性
里。这里放出具体的 作用域插槽 打包后代码,大家一看就很清晰了:
{ scopedSlots: t._u([ { key: "footer", // 函数接收了一个参数n fn: function (n) { return [ // h1 标签的 render 函数 e("h1", [t._v("footer 具名 + 作用域插槽")]), // p 标签的 render 函数,这里可以看到编译后是:n.footerInfo.text e("p", [t._v(t._s(n.footerInfo.text))]) ] } } ]) }
slot
实现原理为了方便大家看调试结果,当前项目的组件结构主要是这样,有三大层:
Vue
-><app></app>
-><my-slot></my-slot>
这里笔者在运行时代码 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组件
的 初始化流程。不是很熟悉组件化流程的朋友可以去看看笔者的Vue响应式原理~】
my-slot组件
的 init
阶段。<h1>默认插槽</h1>
的vNode,赋值给 vm.$slot
(这里我们记住,默认插槽的 vNode 已经得到)2. Then enter renderSlot()
. Then continue the single-step execution above and you will reach renderSlot
. At this time, we have entered the render
stage of my-slot component
. Looking back at the first step, at this time we have the vNode of the default slot, and there is the
vm.$slot.default
scopedSlots attribute
is executed when the subcomponent renders
##Default slot
here is exactly
'default'. It can be found that
does not execute render like the header slot above, but directly returns the slot vNode we got before.
Scope slot
data of our sub-component
my-slot, which is why we use
App component The reason why sub-component data can be accessed through
scope slot
Default slot, regardless of how v2.5 and
v2.6 are written, are in the parent component
vNode is generated in .
vNode exists in
vm.$slot. When the child component
render reaches the slot,
will directly get the vNode
of the parent component. Named SlotThe situation is different between the two versions. According to the compilation results, it can be seen that:
v2.5 is written in the same way as the default slot. vNode is generated in the parent component and used directly by the child component
v2.6,
slot render is executed directly in the sub-component to generate
slot vNode.
Scope slot. Regardless of the version, is rendered in the subcomponent .
scopeSlots attribute, it will not be used until the subcomponent executes render. Generate vNode.
Normal Slot. If it is v2.5, both the named slot and the default slot will only generate vNode when the parent component renders. When the child component wants to render the slot, it will be directly obtained from the $slot of the parent component instance. vNode data.
Normal Slot. If it is v2.6
, although the named slot executes render in the child component, it does not receive parameters .
Scope slot. Regardless of v2.5
or v2.6
, render will only be executed in the subcomponent and can receive parameters .
Okay, let’s give a concise summary at the end. The scope slot must be delayed and receive parameters! Ordinary slots may be executed delayed or directly, but do not receive parameters!
Written at the end, many times we copy bricks and follow the documentation to implement the functions, which is really labor-saving and worry-free~ But if you do it too much, you will find that the current things lack challenges and are boring. . At this time, there will be an impulse to delve into its implementation principle and see how slot
is implemented. Especially scope slots. When using it, you will take it for granted that the upper-level component should obtain the data of the sub-component through the scope slot. However, after digging into the source code and understanding how others do it, you will suddenly feel enlightened~
(Learning video sharing: web front-end development, Basic programming video)
The above is the detailed content of Let’s talk about the principle of Vue.slot and let’s explore how slot is implemented!. For more information, please follow other related articles on the PHP Chinese website!