Cet article partagera avec vous des informations utiles sur Vue et parlera des principes de Vue.slot que vous ne connaissez peut-être pas. J'espère qu'il sera utile à tout le monde !
Je crois que qu'il s'agisse de développement commercial quotidien ou d'encapsulation de composants de base, le
slot
apparaît souvent dans notre champ de vision, car il offre beaucoup de commodité pour la mise en œuvre de notre programmation. Peut-être que tout le monde est familier avec l'utilisation deslot
, qu'il s'agisse d'un emplacement nommé ou d'un slot de portée pour diverses utilisations, etc. savez-vous comment la couche inférieure deslot
etslot-scope
est implémentée ?插槽slot
都是经常出现在我们的视野的,因为它为我们编程实现提供了很多便捷。可能大家对于slot
的用法已经烂透于心了,不管是 具名插槽 ,还是 作用域插槽 各种用法等等...那大?们又知不知道slot
、slot-scope
底层是怎么实现的呢?
通俗易懂、10分钟就能带走的 Vue.slot
的干货源码实现分析!!!跟着笔者一起探究下 Vue(v2.6.14)
中的插槽 slot
是怎么实现的!!本文主要会分两块进行讲解:
普通插槽(具名插槽、默认插槽)
作用域插槽
这篇文章没有晦涩的源码解析,直接用大白话讲解,所以不管大家对Vue源码的熟悉程度,都是能看明白的。通过现场调试,让你看清 Vue
的 slot
是如何实现的。let's go go go!(学习视频分享:vue视频教程)
slot
用法先跟大家一起回顾下插槽的大概用法。这里的 slot
用法使用 2.6.0 的新标准(本文也会带一下 v2.5
的写法的跟 v2.6
在源码实现上有什么区别!)。
如果想详细了解用法可以去官网详细看看Vue 的 slot 文档
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>
页面展示效果如图:
接着上述的案例,添加具名插槽 header
,代码如下:
<!-- 子组件 --> <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>
如上代码块可以发现:
子组件中的 slot标签
带上了一个名为 name
的属性,值为 header
父组件中的 template标签
带上了 v-slot
的属性,值为 header
页面展示效果如图:
再接着上述案例,添加作用域插槽 footer
,代码如下
<!-- 子组件 --> <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>
如上代码块可以发现:
子组件中的 slot标签
除了有 name=footer
的属性,还有一个:footerInfo="footerInfo"
的属性(作用就是传递子组件数据)
父组件中的 template标签
不仅有 v-slot:footer
,并且还有一个赋值操作 ="slotProps"
,在模版的双括号语法中,直接通过 slotProps
访问到 子组件的 footerInfo
页面展示效果如图:
好了,简单回顾完用法后,笔者在这里先提三个问题:
我们带着疑问接着往下看!
slot
的编译区别我们根据上述最终的案例代码,执行一下打包命令,看看 Vue 在编译模板的时候,是怎么处理我们的 slot
的!事不宜迟,赶紧 build
一哈~(偷偷告诉大?,Vue
处理 作用域插槽 跟 普通插槽 的差异就是从编译开始的,也就是 render函数 会有所不同)
这里笔者顺便使用 v2.5
的具名插槽写法给大?参照一下(对具名插槽header做改写,使用 slot="header"
的写法),大家可以看下 v2.6
、v2.5
Vue.slot</code >< /strong> ! ! ! Suivez l'auteur pour découvrir comment le slot <code>slot
dans Vue (v2.6.14)
est implémenté ! ! Cet article l'expliquera principalement en deux parties : 🎜slot
de Vue
est implémenté. allons-y, allons-y ! (Partage de vidéos d'apprentissage : vue vidéo tutoriel🎜)🎜slots
slot
utilise ici le nouveau standard 2.6.0 (cet article parlera également de la méthode d'écriture de v2.5
et < code>v2.6 Quelle est la différence dans l'implémentation du code source ! 🎜🎜🎜Si vous souhaitez en savoir plus sur l'utilisation, vous pouvez vous rendre sur le site officiel pour lire en détail la documentation du slot Vue🎜🎜https://cn.vuejs.org/v2/guide/components-slots.html🎜 blockquote>{ 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))]) ] } } ]) }
header
nommé, le code est le suivant : 🎜rrreee🎜Vous pouvez trouver dans le bloc de code ci-dessus : 🎜la balise d'emplacement
dans le sous-composant a un nom L'attribut de name
a la valeur de header
🎜template La balise
dans le composant parent a l'attribut v -slot
, la valeur est header
🎜pied de page
. comme suit🎜rrreee🎜Le bloc de code ci-dessus peut être trouvé :🎜name=footer
, la balise d'emplacement
dans le Le composant a également un attribut :footerInfo="footerInfo"
(sa fonction est de transmettre les données du composant enfant)🎜balise modèle
dans le Le composant parent a non seulement v-slot:footer
, mais a également une opération d'affectation = "slotProps"
, dans la syntaxe à double crochet du modèle, accédez directement au footerInfo
🎜slotProps
L'effet d'affichage est comme indiqué dans l'image : 🎜🎜🎜🎜D'accord, après avoir brièvement examiné l'utilisation, l'auteur posera ici trois questions : 🎜slot
slot
lors de la création de modèles ! Sans plus tarder, dépêchez-vous et construisez
~ (Dites-le en secret à tout le monde ?, Vue
gère les emplacements de portée et les emplacements ordinaires La différence commence dès la compilation, c'est-à-dire que la fonction de rendu sera différente) 🎜🎜Ici, en passant, l'auteur utilise la méthode d'écriture de slot nommé de v2.5
pour votre référence (pour le nom slot Réécrivez l'en-tête du slot, en utilisant slot="header"
), vous pouvez jeter un oeil à v2.6
, v2.5
nommé slots La différence entre l'écriture et la mise en œuvre ~ Ce n'est pas difficile de toute façon, alors je l'ai juste sorti pour jeter un œil🎜上图左边是 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. Entrez ensuite renderSlot()
. Continuez ensuite l'exécution en une seule étape ci-dessus et vous atteindrez renderSlot
. À ce stade, nous sommes entrés dans l'étape render
du composant my-slot
. En repensant à la première étape, nous avons actuellement le vNode du emplacement par défaut et il existe dans vm.$slot.default
renderSlot()
。接着上面继续单步执行,会走到 renderSlot
中。这时候,已经进入到 my-slot组件
的 render
阶段了。回顾第一步中,此时我们手握 默认插槽的vNode,并存在 vm.$slot.default
中
header插槽
scopedSlots属性
中的 render函数,是在子组件 render 的时候执行
默认插槽
key
正是 'default'
。可以发现,这里并没有像上面 header插槽 一样,去执行 render,而是直接将我们之前得到的 插槽vNode返回了。
作用域插槽
my-slot
的 data
数据,这就是为什么我们在 App组件
能通过 作用域插槽
访问到子组件数据的原因了
最后也是返回 footer插槽 的vNode。好了,验证过程结束~
其实上面的流程只是论证过程,大家不可以不必深陷其中。笔者在这里直接根据实践过程,给大伙总结出结论!也就是要回到我们一开始的三个问题!
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、作用域插槽 为什么能在父组件访问到子组件的数据?
3、普通插槽 跟 作用域插槽 在实现上有区别吗?
普通插槽。如果是 v2.5
scopedSlots
est exécutée lors du rendu du sous-composant
clé
ici est exactement 'default'
. On peut constater que ici n'exécute pas le rendu comme l'emplacement d'en-tête ci-dessus, mais renvoie directement le slot vNode que nous avons obtenu auparavant.
data
de notre sous-composant my-slot
. C'est pourquoi nous utilisons le <. code>Composant d'application La raison pour laquelle les données des sous-composants sont accessibles via emplacement de portée
v2.5
ou v2.6
est écrit, il est toujours dans le composant parent Générez un vNode
. vNode
existe dans vm.$slot
. Lorsque le composant enfant render
atteint l'emplacement, il obtiendra directement le vNode
🎜v2.5
est écrit de la même manière que le slot par défaut, généré dans le composant parent vNode, les sous-composants sont utilisés directement dans 🎜v2.6
, et le slot render
est exécuté directement dans le sous-composant pour générer un Slot vNode
. 🎜v2.5
, l'emplacement nommé et l'emplacement par défaut génèrent un vNode uniquement lorsque le composant parent est rendu. Lorsque le composant enfant souhaite restituer l'emplacement, il l'obtient directement à partir du $slot de. l'instance du composant parent. Ce sont les données de vNode. 🎜Machines à sous normales. S'il s'agit de v2.6
, bien que le slot nommé exécute le rendu dans le composant enfant, il ne reçoit pas de paramètres. v2.6
,具名插槽 虽然是在子组件中执行的 render,但是其不接收参数。
作用域插槽。不管 v2.5
还是 v2.6
,都只在 子组件执行 render,并且能接收参数。
好了,最后来个精炼的总结。作用域插槽一定是延迟执行,且接收参数!普通插槽 可能延迟执行,可能直接执行,但不接收参数!
写在最后,很多时候我们搬砖,遵照文档把功能实现确实省力省心~但当你做多了,你就发现当前的东西缺乏挑战,索然无味。那这个时候,就会有一种冲动,想深入其实现原理,看看 slot
Indépendamment de v2.5
ou v2.6
, le rendu n'est exécuté que sur les sous-composants et peut recevoir des paramètres.
slot
est implémenté. Surtout les 🎜machines à sous limitées🎜. Lorsque vous l'utilisez, vous considérerez comme acquis que le composant de niveau supérieur doit obtenir les données du sous-composant via l'emplacement de portée. Cependant, après avoir fouillé dans le code source et compris comment les autres le font, vous vous sentirez soudainement éclairé. ~🎜🎜(Partage de vidéos d'apprentissage : 🎜développement web front-end🎜, 🎜vidéo sur les bases de la programmation🎜)🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!