VueJS无法更新组件
P粉517475670
P粉517475670 2024-03-26 20:00:55
0
1
378

我有这个 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

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

  • 我需要页面具有响应性
  • 重新创建组件(在每次输入更改时)需要太多时间

这是我尝试过的事情:

  • 为每个输入动态构建一个观察器
    • 但是 vm.$watch 由于某种原因找不到对象。
...forEach((input, index)=>{
    vm.$watch(`object.inputs[${index}].comment`, function(){
            this.$forceUpdate();
        })
}
  • 返回计算属性中的输入并观察

    • 但页面无法检测到更改
  • 在 @change 和 @input 事件上手动启动 this.$forceUpdate()

    • 但是 $forceUpdate 不是一个函数
  • 在 data 中声明一个计数器,并在 @change 和 @input 事件上递增它。

    • 但页面仍然没有更新。
  • v-if 放在不可见的对象上

    • 但只有所述对象被重新渲染
  • 使用 data 属性更改组件的 :key 属性

    • 但什么也没发生

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

谁有解决办法吗?

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

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

  • 在数据中声明一个新变量,我将其命名为 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粉517475670
P粉517475670

全部回复(1)
P粉198749929

更好的答案

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

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

发生了什么:

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

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

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

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() 它。

反应对象:
非反应性对象:
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板