【问题标题】:How do I update props on a manually mounted vue component?如何更新手动安装的 vue 组件上的道具?
【发布时间】:2019-05-16 03:16:54
【问题描述】:

问题: 有没有办法更新像这样创建的手动安装的 vue 组件/实例的道具?我传入一个名为 item 的对象作为组件的 data 属性。

let ComponentClass = Vue.extend(MyComponent);

let instance = new ComponentClass({
    propsData: { data: item }
});

// mount it
instance.$mount();

为什么

我有一个非 vue 3rd 方库,可以在时间轴上呈现内容 (vis.js)。因为我的应用程序的其余部分是用 vue 编写的,所以我试图将 vue 组件用于时间轴本身的内容。

我已经设法通过在 vis.js 的模板函数中手动创建和挂载组件来在时间轴上呈现组件。

template: function(item, element, data) {

    // create a class from the component that was passed in with the item
    let ComponentClass = Vue.extend(item.component);

    // create a new vue instance from that component and pass the item in as a prop
    let instance = new ComponentClass({
        propsData: { data: item },
        parent: vm
    });

    // mount it
    instance.$mount();

    return instance.$el;
}

item.component 是一个接受数据属性的 vue 组件。

我可以通过这种方式创建和挂载 vue 组件,但是当 item 更改时,我需要更新组件上的 data 属性。

【问题讨论】:

  • 我怀疑您需要为父级编写一个render 函数,以显示您的动态新组件。这就是你正确连接道具的方式。 propsData 是不可更改的,用于测试创建。
  • @RoyJ 所以没有办法将动态道具添加到手动安装的实例?甚至使用不同于propsData 的东西?我没有在渲染函数中安装这个组件的选项,因为它被传递到第 3 方库(不是 vue)。
  • 如果item 是一个成员值发生变化的对象,你可以设置data 函数返回item 并可能得到你想要的。
  • @RoyJ 你能举个例子吗?

标签: vue.js vis.js


【解决方案1】:

在 Vue 2.2+ 中,您可以使用 $props。 事实上,我的用例和你的完全一样,有一个 Vue 项目、vis-timeline 和带有手动安装组件的项目。

在我的例子中,为 $props.data 分配一些东西会触发观察者和整个反应机器。

编辑:而且,正如我之前应该注意到的,这不是你应该做的。控制台中有一个错误日志,告诉 prop 不应该像这样直接突变。所以,我会尝试寻找其他解决方案。

【讨论】:

    【解决方案2】:

    以下是我能够以编程方式传递和更新道具的方法:

    const ComponentClass = Vue.extend({
      template: '<div>Hi {{data}}</div>',
      props: {
        data: String
      }
    });
    
    const propsObj = {
      data: 'something'
    }
    
    const instance = new ComponentClass()
    
    const props = Vue.observable({
          ...instance._props,
          ...propsObj
    })
    
    instance._props = props
    
    // mount it
    instance.$mount();
    document.getElementById('target').appendChild(instance.$el);
    
    setTimeout(() => {
      props.data = 'another thing';  // or instance.data = ...
    }, 1500);
    <script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
    <div id="target">
    </div>

    【讨论】:

    • 感谢您的回答。似乎合乎逻辑,但我认为如果我再次尝试这个,我不会使用道具,而是使用实例数据或 vuex 存储。
    【解决方案3】:

    如果你在 Vue 之外定义了一个对象,然后在 Vue 实例的 data 中使用它,它将变为反应式。在下面的示例中,我以这种方式使用dataObj。虽然我遵循使用data 函数的约定,但它返回一个预定义的对象(如果我使用data: dataObj,它的工作方式完全相同)。

    挂载实例后,我更新dataObj.data,您可以看到组件更新以反映新值。

    const ComponentClass = Vue.extend({
      template: '<div>Hi {{data}}</div>'
    });
    
    const dataObj = {
      data: 'something'
    }
    
    let instance = new ComponentClass({
      data() {
        return dataObj;
      }
    });
    
    // mount it
    instance.$mount();
    document.getElementById('target').appendChild(instance.$el);
    
    setTimeout(() => {
      dataObj.data = 'another thing';
    }, 1500);
    <script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
    <div id="target">
    </div>

    【讨论】:

    • 这可能是我正在寻找的。所以基本上答案是使用数据而不是道具?所以你直接修改组件数据好吗?
    • 基本上就是这样。对于这种情况,确实没有规则或惯例。 Vue 不管理组件,所以你必须这样做。
    • 但是如果我想根据非反应性属性重新计算一个值(比如取决于ref)怎么办?
    • @YakovL 你必须创造一些对变化做出反应的东西。
    • @RoyJ 不确定你的意思是什么......好吧,我最终将计算属性更改为数据并在装载时重新计算 (stackoverflow.com/q/59392865/3995261)
    猜你喜欢
    • 2021-06-11
    • 1970-01-01
    • 2017-11-11
    • 2021-08-09
    • 2020-09-30
    • 2020-01-20
    • 2020-05-04
    • 2020-06-15
    • 2017-10-24
    相关资源
    最近更新 更多