vue slot使用,v-slot vue
本文主要介绍了Vue中slot使用的详细讲解,有很好的参考价值,希望对大家有所帮助。如有错误或不足之处,请不吝赐教。
目录
使用slot基本用法命名slot作用域Slot实现总结在Vue中,我们使用组件来组织页面和代码,类似于积木。每个组件都是一个构建块,我们可以通过使用一些相同或不同的组件来构建所需的页面。
插槽(Slot)是组件功能的重要组成部分,插槽必须用于组件才有意义。
它为组件提供了一个外部接口,允许从组件外部交付内容,并将这部分内容放在指定的位置。
使用 slot
当一个组件可能至少被使用两次,并且两次使用的内容(这里是组件视图的组成)不同时,插槽就有存在的必要。注意:本文中的代码是基于Vue3编写的。
基础用法
Link.vue
模板
a:href= href rel= external no follow class= link
!-留出一个可以放置外部传入内容的插槽-
插槽/插槽
/a
/模板
脚本
导出默认值{
道具:{
href: {
必填:真,
类型:字符串,
},
},
};
/脚本
style lang=less 范围。链接{
显示:内嵌-块;
行高:1;
空白:nowrap
光标:指针;
背景:# fff
边框:1px solid # dcdfe6
颜色:# 606266;
-WebKit-外观:无;
文本对齐:居中;
框大小:边框-框;
大纲:无;
边距:0;
转场:0.1s
字体粗细:500;
填充:12px 20px
字体大小:14px
边框-半径:4px
}
/风格
App.vue
模板
div class=" app "
Link= 3359 Baidu . com rel= external no follow Baidu/Link
br /
link href= https://Google . com rel= external no follow style= margin-top:10px
!-此处允许任意内容,包括字符串和标签-
Spanicon/spangoogle /Link
/div
/模板
脚本
从导入链接。/link . vue ;
导出默认值{
组件:{
链接,
},
};
/脚本
视觉效果:
实现了上面两个组件Link.vue和App.vue。Link.vue是一个链接的组件,在组件内部已经定义了样式,然后外部世界使用的时候填充链接的内容。
在App.vue组件中,Link.vue组件使用了两次,传入的内容是不同的。
具名插槽
上面的Link.vue只要求填写一个内容,那么当我们需要在组件的几个位置填写不同的内容时该怎么办呢?这时候就可以使用命名槽了,也就是给组件的每个填充区域取一个名字,这样在使用的时候就可以用对应的名字来填充这个区域。
Page.vue
模板
div class=page
header class=page-header
插槽名称=header/slot
/页眉
div class=page-center
撇开不谈
插槽名称=备用/插槽
/抛开
div class=页面内容
槽名=内容/槽
/div
/div
页脚class=页脚
插槽名称=页脚/插槽
/页脚
/div
/模板
脚本
导出默认值{
setup() {
return { };
},
};
/脚本
style lang=less
正文{
边距:0;
}。页面{
边框:1px纯色# 333;
宽度:100vw
身高:100vh
显示器:flex
伸缩方向:列;
-标题{
高度:50px
边框-底部:1px solid # 333333
}
-中心{
flex:1;
显示器:flex
}
-靠边站
宽度:150px
右边框:1px solid # 333333
}
-内容{
flex:1;
}
-页脚{
border-top:1px solid # 333;
高度:30px
}
}
/风格
App.vue
模板
页面样式= width:500 px;高度:300px边距:30px 30px
模板v-slot:header这是标题/模板。
模板v槽:旁边这是侧边栏/模板。
模板v槽:内容这是内容区域/模板
模板v槽:页脚这是页脚/模板。
/页面
页面样式= width:500 px;高度:300px边距:30px 30px
模板v形槽:标题
H2路过/h2
/模板
模板v形槽:侧面
保险商实验所
东方的李杰石/李
李看海/李
/ul
/模板
模板v槽:内容这是内容区域/模板
模板v槽:页脚这是页脚/模板。
/页面
/模板
脚本
从导入页面。/page . vue ;
导出默认值{
组件:{
页面,
},
};
/脚本
效果图:
作用域插槽
为什么叫范围槽?首先要理解范围的概念。在JS中,作用域代表当前的执行上下文,变量只能在当前的作用域中使用。范围分为父范围和子范围。子作用域可以访问父作用域中的变量,作用域链是从每一层向上形成的。JS只有全局作用域和函数作用域,ES6有了新的块级作用域。关于范围,这里不再赘述。有需要的同学可以去MDN的范围看看。
Vue本质上是js,模板最终会编译成渲染函数。每个组件都有一个渲染函数。我们先来看一个例子:
Count.vue
模板
差异
p当前号码:{{ count }}/p
button @click=onAdd /button
button @click=onMinus-/button
插槽/插槽
/div
/模板
脚本
导出默认值{
data() {
返回{
计数:0,
};
},
方法:{
onAdd() {
this.count
},
onMinus() {
this . count-;
},
},
};
/脚本
App.vue
模板
差异
Count style=border: 1px纯红
p这是填充计数组件的插槽/p
pappCount:{{ appCount }}/p
pCount组件中的计数变量:{{ count }}/p
/计数
br /
button @click=onClick 应用添加/button
/div
/模板
脚本
从导入计数。/count . vue ;
导出默认值{
组件:{
数数,
},
data() {
返回{
appCount: 0,
};
},
方法:{
onClick() {
this . app count;
},
},
};
/脚本
效果图:
从上面的渲染图可以看出,在App.vue组件中使用Count.vue组件时,在Count.vue组件的槽中,可以访问appCount变量,但是不能访问Count.vue组件的Count变量。为什么?理论上,插槽的输入内容最终会被插入到Count.vue组件中,因此Count.vue组件的变量也应该是可访问的。
父模板中的所有内容都在父范围内编译;子模板中的所有内容都在子范围内编译。
以上引文摘自Vue文档,表示App.vue中的一切,包括Count.vue组件的slot内容,都是在App.vue组件下编译的,即Count.vue组件的slot模板可以访问App.vue组件的所有变量,但不能访问Count.vue组件的任何变量。如果我必须访问插槽中Count.vue的count变量怎么办?这就是scope插槽派上用场的时候了。
Scope slot允许一些变量暴露给组件中slot所在的上下文,覆盖上面的Count.vue组件,
Count.vue
模板
差异
p当前号码:{{ count }}/p
button @click=onAdd /button
button @click=onMinus-/button
!-向插槽范围公开count变量-
slot :count=count/slot
/div
/模板
脚本
导出默认值{
data() {
返回{
计数:0,
};
},
方法:{
onAdd() {
this.count
},
onMinus() {
this . count-;
},
},
};
/脚本
App.vue
模板
差异
Count style=border: 1px纯红
!- Count组件slot公开的所有变量都放在slotProps对象中-
模板v-slot=slotProps
p这是填充计数组件的插槽/p
pappCount:{{ appCount }}/p
pCount组件中的Count变量:{{ slotProps.count }}/p
/模板
/计数
br /
button @click=onClick 应用添加/button
/div
/模板
脚本
从导入计数。/count . vue ;
导出默认值{
组件:{
数数,
},
data() {
返回{
appCount: 0,
};
},
方法:{
onClick() {
this . app count;
},
},
};
/脚本
这是作用域插槽。本质上,它允许访问父组件范围中的子组件范围。它为插槽模板区域提供了一个上下文,数据来自子组件。
作用域插槽的用处还是挺广的,总的来说当你需要它时自然会用到它,如果想提前学习,可以看一下elementUI的桌子组件。
slot 实现
上面就插槽的使用说了一大堆,关于插槽的实现还是没有涉及,下文讲解在某视频剪辑软件中插槽是如何实现的?
首先,我们都知道,无论是使用小艾还是模板,最终都会编译成提出函数,并且提出函数在执行之后会输出虚拟多姆,下面先看一个组件在编译完成之后是什么样子?
比较某视频剪辑软件
模板
差异
pcount: {{count}}/p
button @click=onClick
模拟数字音乐制碟
/按钮
slot :count=count/slot
/div
/模板
脚本
从“vue”导入{定义组件,引用}
导出默认定义组件((道具)={
const count=ref(0);
const onClick=()={
计数。值
}
返回{
数数,
单击事件
}
})
/脚本
App.vue
模板
差异
免费票
模板v-slot=slotProps
p
{{magRef}}: {{slotProps.count}}
/p
/模板
/Comp
/div
/模板
脚本
从“vue”导入{定义组件,引用}
从导入排版 Comp.vue
导出默认定义组件({
组件:{Comp},
设置(道具){
const magRef=ref(当前的数字是)
返回{
马格雷夫
}
}
})
/脚本
比较某视频剪辑软件编译之后:
/*分析的绑定:{} */
导入{
定义一个组件,
裁判员
}来自“vue”
const _ _ sfc _ _=定义组件((props)={
const count=ref(0);
const onClick=()={
计数。值
}
返回{
数数,
单击事件
}
})
导入{
toDisplayString as _ toDisplayString,
createElementVNode as _ createElementVNode,
renderSlot as _renderSlot,
openBlock as _openBlock,
createElementBlock as _ createElementBlock
}来自“vue”
函数呈现(_ctx,_cache,$props,$setup,$data,$options) {
return (_openBlock(),_createElementBlock(div ,null,[
_createElementVNode(p ,null, count: _ toDisplayString(_ CTX。count),1 /* TEXT */),
_createElementVNode(button ,{
onClick: _cache[0] (_cache[0]=(.args)=(_ CTX。在线点击CTX。onclick(.args)))
}、添加),
_renderSlot(_ctx .$老虎机,默认,{
计数:_ctx.count
})
]))
}
__sfc__ .渲染=渲染
__sfc__ .__file=Comp.vue
导出默认值__sfc__
App.vue编译之后:
/*分析的绑定:{} */
导入{
定义一个组件,
裁判员
}来自“vue”
从导入排版 Comp.vue
const __sfc__=defineComponent({
组件:{
免费票
},
设置(道具){
const magRef=ref(当前的数字是)
返回{
马格雷夫
}
}
})
导入{
toDisplayString as _ toDisplayString,
createElementVNode as _ createElementVNode,
将组件解析为_ resolve组件,
withCtx as _withCtx,
createVNode as _createVNode,
openBlock as _openBlock,
createElementBlock as _ createElementBlock
}来自“vue”
函数呈现(_ctx,_cache,$props,$setup,$data,$options) {
const _ component _ Comp=_ resolve component( Comp )
return (_openBlock(),_createElementBlock(div ,null,[
_createVNode(_component_Comp,null,{
默认值:_ witchtx((老虎机道具)=[
_createElementVNode(p ,null,_ toDisplayString(_ CTX。mag ref): _ toDisplayString(slot props。计数),1 /* TEXT */)
]),
_: 1 /*稳定*/
})
]))
}
__sfc__ .渲染=渲染
__sfc__ .__file=App.vue
导出默认值__sfc__
这里给大家推荐一个尤雨溪搞的测试网站Vue SFC游乐场可以直接看到组件编译之后的射流研究…代码。
这个编译是在加载。某视频剪辑软件文件的时候就执行了,运行时阶段是不存在模板字符串了(使用UMD的时候会存在),在浏览器中执行的都是编译之后的js。下面具体分析一下以上比较某视频剪辑软件和App.vue编译之后的射流研究…代码。
首先在比较某视频剪辑软件中,slot :count=count/slot会被编译成_renderSlot(_ctx .$slots, default ,{count: _ctx.count}),下面看看_renderSlot中干了什么?
导出类型插槽=(.args: any[])=VNode[]
导出类型内部插槽={
[名称:字符串]:插槽未定义
}
导出函数renderSlot(
插槽:插槽,
名称:字符串,
道具:Data={},
//这不是面向用户的函数,因此回退总是由
//编译器,并保证是返回数组的函数
退路?()=VNodeArrayChildren,
没有抽签?布尔型
):VNode {
let slot=slots[name]
openBlock()
const validSlotContent=slot ensureValidVNode(slot(props))
const rendered=createBlock(
片段,
{ key: props.key `_${name}` },
validSlotContent (回退?回退():[]),
validSlotContent(作为原始插槽的插槽)。_===插槽标志。稳定的
?补丁标志。稳定碎片
:修补标志。保释
)
渲染返回
}
句子_渲染槽(_ ctx。$ slots, default ,{count: _ ctx.count})显然是为了execute _ ctx。$ slots . default({count: _ ctx.count}),意思是在父组件中,每个slot模板最终都会被编译成一个函数,而这个函数会被传到子组件中,slot函数会以props(这里是{ count:_ ctx . count })为参数执行,最后是_ CTX。$ slots . default({ count:_ CTX . count })将返回虚拟dom对象。
让我们再来看看App.vue组件:
免费票
模板v-slot=slotProps
p
{{magRef}}: {{slotProps.count}}
/p
/模板
/Comp
编译成:
_createVNode(_component_Comp,null,{
默认值:_ witchtx((slot props)=[
_createElementVNode(p ,null,_ toDisplayString(_ CTX . magref): _ toDisplayString(slot props . count),1 /* TEXT */)
]),
_: 1 /*稳定*/
})
请忽略_withCtx。很明显,模板会被编译成一个函数并传递给子组件,然后在子组件中构建一个完整的虚拟dom。在上面,_ctx是当前组件的上下文,slotProps是作用域slot公开的参数。
由此可以做一个总结,vue slot的实现原理:
的所有模板都将编译到函数中以创建vnode。从父组件传递到子组件的插槽(每个插槽都是一个函数,即不同名称的插槽是不同的函数)。内容模板也将被编译成函数并传递给子组件。如果在模板中使用了父组件的变量,它们将以闭包的形式在槽函数中使用。当子组件接收到父组件传递的槽内容函数时,它会以槽中暴露的变量(只有作用域槽有这些变量)作为参数执行这个函数,并返回vnode,它将是子组件vnode的一部分。
总结
本文从使用和实现两个方面来解释vue slot,有一定的深度,但是忽略了一些使用和实现的细节。请指出并理解不足之处。
以上个人经历,希望能给大家一个参考,也希望大家多多支持我们。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。