首页  >  问答  >  正文

VueJS无法更新组件

我有这个 Vue 1 组件,它获取一个对象作为必须由用户填充的道具。

该对象具有以下结构:

{
    property1: ...,
    property2: ...,
    inputs: {
        2130: { value: ..., comment: ... },
        2131: { ... },
        ...,
    }

}

该组件是一个简单的模式,带有一个包含所有必要输入的表格。我想检查一些内容,进行计算并根据用户输入更改单元格样式。

当模态加载时,我构建页面,使用它们的 id 设置这些输入的模型:

v-model="object.inputs[subgroup[1].dx.mob.id].comment"

(注意:subgroup[1]是包含表结构“定义”的另一个对象的一部分,通过执行 inputs[subgroup[1].dx.mob.id] 我期望链接表字段到对象对应的输入)

问题是,无论我尝试什么,页面都不会重新呈现。 <input> 字段甚至不保存该值,一旦我单击它就会消失。

更奇怪的是,这些值实际上已设置,但使该组件重新渲染并执行我需要他做的所有良好检查和样式的唯一方法是通过关闭并重新打开模式或通过在表的父表上设置 v-if

这些显然都是不可行的选择

这是我尝试过的事情:

...forEach((input, index)=>{
    vm.$watch(`object.inputs[${index}].comment`, function(){
            this.$forceUpdate();
        })
}

正如预期的那样,我能做到这一点的唯一方法是销毁并重新创建组件。

谁有解决办法吗?

丑陋的解决方案:经过几次失败的尝试后,我发现了一些可以解决问题的方法,即使是以不正确的方式。任何真实的 答案仍然非常受欢迎。

本质上,我设法强制组件重新渲染:

  • 在数据中声明一个新变量,我将其命名为 key (在我的例子中它是数字,但任何都可以)
  • 创建一个 update 函数,将 key 从 1 切换到 0,反之亦然。
  • 将该函数绑定到每个输入或选择的 @blur 事件
  • 由于我的整个模态是根据计算属性呈现的,因此我在该函数内的 key 上执行了一些读取操作(在 我的情况是我将其值分配给一个新变量,然后记录它(不是 确定两者中的哪一个触发渲染,但我猜第一个是 够了))
... 
data: function() {
      return {
        ... ,
        key: 0
      };   
},

...

methods: {
    ... ,
    update: function(){
        this.key = this.key == 0 ? 1 : 0
    }
},
computed: {
    ... ,
    testData: function () { //this functions builds an object that is used to render the page  
        var data = []
        var __self = this
        var blu = this.key // This is the line where i read key
        console.log(blu)
        this.test.inputs.forEach(function(input){

            var slug = input.slug.replaceAll('#', '').split('-')
        
            __self.setItem(data, slug, input)

        })
     
        console.log('data', data)
        return data // this value gets then passed to Object.entries() to get an iterable object I build the page with
    } 
}

P粉517475670P粉517475670206 天前353

全部回复(1)我来回复

  • P粉198749929

    P粉1987499292024-03-27 12:53:49

    更好的答案

    经过委婉的调试,我成功解决了这个问题。

    本质上,我在问题中描述的组件用于两个不同的页面:“创建”页面和“编辑”页面。当我看到编辑页面中一切都按预期运行时,我的心灵动起来。

    发生了什么:

    组件在两个页面中的使用方式之间的唯一区别是传递给它的数据。在“编辑”页面中,每个对象都已填充,因为数据已经存在,而在“创建”页面中,每个对象显然都是空白的。

    由于我需要一个可用的对象,因此我必须用空输入填充它,以便稍后可以访问它们。

    我愚蠢地尝试像这样手动设置属性:

    objects[index].inputs = {}

    期望将属性分配给响应式对象会自动使该属性也成为响应式。天哪,我错了。

    Vue 响应式 getter 和 setter:

    为了使事情反应灵敏,vue 覆盖了默认的 Object 类 getter 和 setter。但这仅在特定条件下发生:

    • 该属性必须通过 Vue.set()this.$set() 添加
    • 所有父属性也必须是响应式的

    例如,经过几次尝试,在设置 objects[index].inputs = {} 后,我尝试使用 this.$set() 来填充我的输入。

    这不起作用,因为我也没有使 .inputs 具有反应性。

    所以我不得不

    this.$set('objects[${index}].inputs', {})

    之前

    this.$set(`objects[${index}].inputs[${input.id}].value`, null)
    this.$set(`objects[${index}].inputs[${input.id}].comment`, null)

    结论:

    如果您有反应性问题,我的建议是记录所述对象并检查它及其父对象是否具有正确的 getter 和 setter。

    请记住,如果您想向响应式对象添加新属性,则必须 $set() 它。

    反应对象:
    非反应性对象:

    回复
    0
  • 取消回复