Vue.js render函数是否允许复用插槽中已有的嵌套VNode?
核心问题说明
- 你当前的代码功能完全正常,渲染出的真实DOM结构完全符合预期,devtools显示层级和DOM不一致是Vue插槽的固有机制导致的,不属于代码bug。
- 普通插槽的VNode是在调用
<row>的父组件中生成的,VNode的context、parent属性已经提前绑定了父组件和当前Row组件的实例。你把VNode传入b-col的children仅修改了DOM挂载位置,没有修改VNode本身的归属属性,而devtools是基于VNode归属属性展示组件树,因此会显示UiText是Row的直接子节点。 b-col的functional标记属于正常情况:BootstrapVue的b-col本身就是函数式组件,这类组件没有自身实例,性能更高,devtools会统一给函数式组件打上该标记。- 子组件的
$parent确实是不可变的:UiText实例创建时$parent就固定为Row组件,b-col作为函数式组件没有实例,天然无法作为父组件被挂载到$parent链上,这是Vue的固定设计。 - 你当前复用插槽VNode的做法本身是合法的,只要不同时把同一个VNode挂载到多个DOM节点上,就不会产生运行问题。
可选优化方案
如果需要devtools组件树和DOM结构完全对齐,可以将普通插槽改为作用域插槽实现:
- 调用Row组件时使用作用域插槽传递内容:
<row cols="4,8"> <template #default> <ui-text name="A" /> <ui-text name="B" /> </template> </row>
- 修改Row组件的render函数,调用作用域插槽生成新的VNode:
export default { props: ['cols'], computed: { columns() { let v = this.cols; if (!v) return []; return this.cols.split(/,/g); } }, render: function(h) { let columns = this.columns; // 调用作用域插槽生成最新的VNode let children = this.$scopedSlots.default ? this.$scopedSlots.default() : []; let kids = []; for(let i = 0, s = Math.min(columns.length, children.length); i < s; i++) { let kid = children[i]; kids.push(h('b-col', {props: {cols: columns[i]}}, [ kid ])); } return h('b-form-row', {}, kids); } }
内容的提问来源于stack exchange,提问作者Daniel Yang
相关产品推荐
相关产品推荐

