Vue.js之slot深度复制详解
发布时间 - 2026-01-11 00:06:43 点击率:次前言

在Vue中,slot是一个很有用的特性,可以用来向组件内部插入一些内容。slot就是“插槽”的意思,用大白话说就是:定义组件的时候留几个口子,由用户来决定插入的内容。
例如我们定义一个组件MyComponent,其包含一个slot:
Vue.component('MyComponent', {
template: `
<div>
<slot></slot>
</div>
`
})
当调用<MyComponent>123</MyComponent>时,会渲染为如下DOM结构:
<div> 123 </div>
现在又有新需求了,我们希望调用<MyComponent>123</MyComponent>时,渲染出这样的DOM结构:
<div> 123 123 </div>
看起来很容易实现,即再为MyComponent添加一个slot:
Vue.component('MyComponent', {
template: `
<div>
<slot></slot>
<slot></slot>
</div>
`
})
渲染出的结构也确实如你所愿,唯一美中不足的是控制台有一个小小的Warning:
Duplicate presence of slot "default" found in the same render tree
如果你不是强迫症患者,这时候你可以收工安心回家睡觉了。直到有一天你的同事向你抱怨,为什么向MyComponent插入一个自定义组件会渲染不出来?
例如有一自定义组件MyComponent2:
Vue.component('MyComponent2', {
template: `
<div>456</div>
`
})
当调用<MyComponent><MyComponent2></MyComponent2></MyComponent>时,预期渲染为如下DOM结构:
<div> <div>456</div> <div>456</div> </div>
为什么不能正常工作呢?估计是前面的那个Warning搞得鬼,通过查询发现在Vue 2.0中不允许有重名的slot:
重名的 Slots 移除
同一模板中的重名 已经弃用。当一个 slot 已经被渲染过了,那么就不能在同一模板其它地方被再次渲染了。如果要在不同位置渲染同一内容,可一用 prop 来传递。
文档中提示可以用props来实现,然而在我的用例中显然是不合适的。经过搜索后,最靠谱的方法是手写render函数,将slot中的内容复制到其他的位置。
将之前的MyComponent改为render函数的方式定义:
Vue.component('MyComponent', {
render (createElement) {
return createElement('div', [
...this.$slots.default,
...this.$slots.default
])
}
})
在上面的定义中我们插入了两个this.$slots.default,测试下能不能正常工作。然而并没有什么卵用,Vue文档在render函数这一章有以下说明:
VNodes 必须唯一
所有组件树中的 VNodes 必须唯一
这意味着我们不能简单地在不同位置引用this.$slots.default,必须对slot进行深度复制。深度复制的函数如下:
function deepClone(vnodes, createElement) {
function cloneVNode (vnode) {
const clonedChildren = vnode.children && vnode.children.map(vnode => cloneVNode(vnode));
const cloned = createElement(vnode.tag, vnode.data, clonedChildren);
cloned.text = vnode.text;
cloned.isComment = vnode.isComment;
cloned.componentOptions = vnode.componentOptions;
cloned.elm = vnode.elm;
cloned.context = vnode.context;
cloned.ns = vnode.ns;
cloned.isStatic = vnode.isStatic;
cloned.key = vnode.key;
return cloned;
}
const clonedVNodes = vnodes.map(vnode => cloneVNode(vnode))
return clonedVNodes;
}
上面的核心函数就是cloneVNode() ,它递归地创建VNode,实现深度复制。VNode的属性很多,我并不了解哪些是关键属性,只是参照着Vue的源码一并地复制过来。
基于以上函数,我们更改MyComponent的定义:
Vue.component('MyComponent', {
render (createElement) {
return createElement('div', [
...this.$slots.default,
...deepClone(this.$slots.default, createElement)
])
}
})
经测试,一切正常。
总结
在Vue 1.0中重名的slots并不会出现什么问题,不知道为什么在2.0中取消了这个功能。我听说React提供了复制Element的标准函数,希望Vue也能提供这个函数,免得大家踩坑。以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
# vue.js
# slot
# vuejs
# 怎么使用
# 深入理解vue中slot与slot-scope的具体使用
# Vuejs第十一篇组件之slot内容分发实例详解
# vue 组件中slot插口的具体用法
# 深入浅析Vue中的slots/scoped slots
# vue中slot(插槽)的介绍与使用
# 详解vue slot插槽的使用方法
# vue中父子组件注意事项
# 传值及slot应用技巧
# Vue 技巧之控制父类的 slot
# 可以用
# 自定义
# 递归
# 插槽
# 的是
# 是一个
# 有什么
# 几个
# 有一
# 文档
# 过了
# 你可以
# 也能
# 又有
# 其他的
# 要在
# 很容易
# 你不是
# 大白
# 美中不足
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
装修招标网站设计制作流程,装修招标流程?
音响网站制作视频教程,隆霸音响官方网站?
Laravel如何实现API版本控制_Laravel版本化API设计方案
青岛网站建设如何选择本地服务器?
宙斯浏览器怎么屏蔽图片浏览 节省手机流量使用设置方法
Laravel如何生成API文档?(Swagger/OpenAPI教程)
Laravel如何实现模型的全局作用域?(Global Scope示例)
大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?
Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比
Android中AutoCompleteTextView自动提示
如何用y主机助手快速搭建网站?
Laravel如何实现一对一模型关联?(Eloquent示例)
如何解决hover在ie6中的兼容性问题
Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程
如何在云指建站中生成FTP站点?
Swift中循环语句中的转移语句 break 和 continue
西安专业网站制作公司有哪些,陕西省建行官方网站?
在Oracle关闭情况下如何修改spfile的参数
网站制作报价单模板图片,小松挖机官方网站报价?
Laravel如何集成Inertia.js与Vue/React?(安装配置)
Laravel怎么实现支付功能_Laravel集成支付宝微信支付
济南网站建设制作公司,室内设计网站一般都有哪些功能?
如何选择PHP开源工具快速搭建网站?
如何用虚拟主机快速搭建网站?详细步骤解析
网站制作大概多少钱一个,做一个平台网站大概多少钱?
javascript如何操作浏览器历史记录_怎样实现无刷新导航
香港服务器如何优化才能显著提升网站加载速度?
Laravel如何创建自定义中间件?(Middleware代码示例)
javascript基本数据类型及类型检测常用方法小结
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
浅述节点的创建及常见功能的实现
三星、SK海力士获美批准:可向中国出口芯片制造设备
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
北京网页设计制作网站有哪些,继续教育自动播放怎么设置?
如何在云虚拟主机上快速搭建个人网站?
活动邀请函制作网站有哪些,活动邀请函文案?
高性能网站服务器部署指南:稳定运行与安全配置优化方案
打造顶配客厅影院,这份100寸电视推荐名单请查收
如何用PHP快速搭建CMS系统?
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
高防服务器租用指南:配置选择与快速部署攻略
javascript中对象的定义、使用以及对象和原型链操作小结
昵图网官网入口 昵图网素材平台官方入口
Python并发异常传播_错误处理解析【教程】
如何用好域名打造高点击率的自主建站?
Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】
免费网站制作appp,免费制作app哪个平台好?
Laravel如何使用Blade模板引擎?(完整语法和示例)
如何用花生壳三步快速搭建专属网站?
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)

