【问题标题】:How can I duplicate slots within a Vuejs render function?如何在 Vuejs 渲染函数中复制插槽?
【发布时间】:2018-12-06 11:46:25
【问题描述】:

我有一个通过插槽传递内容的组件。我正在使用渲染函数来输出内容。我使用渲染功能的原因是我想多次复制内容。当我使用此代码时,一切正常:

render(createElement){
    return createElement('div', {}, this.$slots.default);
}

当我传递的数据发生变化时,输出也会发生变化。

但是,由于我想复制插槽内容,我现在正在尝试:

return createElement(
    'div', {},
        [
            createElement('div', { }, this.$slots.default),
            createElement('div', { }, this.$slots.default)
        ]
    )

现在的问题是,当 slot 内容从组件外部发生变化时,只有第二个 div 中的内容被更新,第一个 div 中的内容保持不变..

我错过了什么吗?

【问题讨论】:

  • 我认为您将不得不手动克隆默认插槽引用的那些元素。你的第二个例子是我所期望的。首先,它将$slots.default 设置为您首先创建的元素的子元素,然后立即将它们再次移动为第二个创建元素的子元素,此时它们离开第一个元素。我不知道 Vue 有一种内置的方法来以 render() 期望的格式递归克隆元素。
  • 我想如果 $slots.default 中的元素在 Vue 上下文之外,您可以考虑将原生 cloneNodedeep 设置为 true 并看看是否有效。跨度>
  • 我仍然觉得很奇怪,因为在第一次渲染期间它们都被渲染了。只有当插槽内容发生变化时才会出现问题。我试过 cloneNode 但这似乎不起作用(至少 this.$slots.default.cloneNode(true) 或 this.$slots.default[0].cloneNode(true) 给我错误说它不是一个函数)

标签: vue.js vuejs2 vue-component


【解决方案1】:

我无法解释为什么会这样。但是文档确实在渲染函数中提到了“VNodes Must Be Unique”。见https://vuejs.org/v2/guide/render-function.html#Constraints

不管怎样,这是一个 VNode 克隆功能,它有效,我从https://jingsam.github.io/2017/03/08/vnode-deep-clone.html 发现的。

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;
}

使用方法:

render(createElement) {
    return createElement('div', {}, [
        createElement('div', {}, this.$slots.default),
        createElement('div', {}, [...deepClone(this.$slots.default, createElement)])
    ])
}

演示:https://jsfiddle.net/jacobgoh101/bz3e0o5m/

【讨论】:

    【解决方案2】:

    我发现这个 SO 问题正在寻找一种方法来多次呈现插槽的内容,例如对于可以具有列表行内容模板的通用列表,该模板用于每个项目。

    从 2020 年开始(实际上更早),可以使用作用域插槽实现插槽的多次渲染。这记录在这里:

    https://vuejs.org/v2/guide/components-slots.html#Other-Examples

    文档说:

    Slot props 允许我们将 slot 变成可重复使用的模板,可以根据输入 props 呈现不同的内容

    (显然,如果我们可以使用模板根据props渲染不同的内容,我们也可以使用它来渲染相同的内容)

    此处给出的示例使用模板而不是渲染函数,但幸运的是,还记录了如何在渲染函数中使用作用域槽:

    https://vuejs.org/v2/guide/render-function.html#Slots

    【讨论】:

      猜你喜欢
      • 2020-06-28
      • 2018-01-09
      • 2021-09-12
      • 1970-01-01
      • 2020-12-26
      • 2020-11-15
      • 2017-07-01
      • 2020-06-03
      • 2018-04-05
      相关资源
      最近更新 更多