javascript - 如何在 'value' 输入之前修改 VueJS 中的 `$emit(' prop')`完成更新

标签 javascript vue.js vuejs2 v-model

我有一个关于创建可与 v-model 一起使用的 VueJS 组件的问题,它利用底层 value prop 和 $emit('input', newVal)

props: {
  value: Array
},
methods: {
  moveIdToIndex (id, newIndex) {
    const newArrayHead = this.value
      .slice(0, newIndex)
      .filter(_id => _id !== id)
    const newArrayTail = this.value
      .slice(newIndex)
      .filter(_id => _id !== id)
    const newArray = [...newArrayHead, id, ...newArrayTail]
    return this.updateArray(newArray)
  },
  updateArray (newArray) {
    this.$emit('input', newArray)
  }
}

在上面的代码示例中,如果我快速连续地进行两次修改,它们都会在“旧数组”(未修改的 value 属性)上执行。

moveIdToIndex('a', 4)
moveIdToIndex('b', 2)

换句话说,我需要等待 value 通过 $emit('input') 更新,以便第二次调用 moveIdToIndex 以使用已修改的数组。

错误的解决方案 1

一种解决方法是将 updateArray 更改为:

  updateArray (newArray) {
    return new Promise((resolve, reject) => {
      this.$emit('input', newArray)
      this.$nextTick(resolve)
    })
  }

然后像这样执行:

await moveIdToIndex('a', 4)
moveIdToIndex('b', 2)

但我不想这样做,因为我需要对一个 ID 数组执行此操作并将它们同时移动到不同的位置。而 awaiting 会大大降低性能。

错误的解决方案 2

我发现一个更好的解决方案是这样做:

  updateArray (newArray) {
    this.value = newArray
    this.$emit('input', newArray)
  }

然后我根本不需要等待 $emit 完成。

但是,在这种情况下,VueJS 会给出一个控制台错误:

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"

有没有人有更好的解决方案?

最佳答案

好的。据我了解您的用例和应用程序,这些是您的选择。

首先,不要改变 props 直接在内部保存 props 然后修改那个值。

props: {
  value: Array
},
data() {
  return {
    val: this.value
  }
}

如果对数组的下一次修改依赖于对数组的先前修改,则您不能同时执行它们。但是你需要它发生得相当快(我假设你希望用户觉得它发生得很快)。您可以做的是对组件内的 val 进行修改,而不是使其依赖于 prop。 val 变量仅在安装组件时初始化。通过这种方式,您可以在 UI 中即时修改数据,并让数据库在后台更新。

换句话说,您的完整解决方案如下所示:

props: {
  value: Array
},
data () {
  return {val: this.value}
},
methods: {
  moveIdToIndex (id, newIndex) {
    const newArrayHead = this.val
      .slice(0, newIndex)
      .filter(_id => _id !== id)
    const newArrayTail = this.val
      .slice(newIndex)
      .filter(_id => _id !== id)
    const newArray = [...newArrayHead, id, ...newArrayTail]
    return this.updateArray(newArray)
  },
  updateArray (newArray) {
    this.val = newArray
    this.$emit('input', newArray)
  }
}

此解决方案解决了您的问题,并允许您快速连续执行 moveIdToIndex,而无需等待任何事情。

现在,如果数组在应用程序中的许多地方使用,下一个最好的办法是将它移动到商店并将其用作单一事实点并更新它并使用它来更新您的组件。您的状态将不会同时快速更新,然后将更新延迟到数据库适当的时间。

关于javascript - 如何在 'value' 输入之前修改 VueJS 中的 `$emit(' prop')`完成更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55914130/

相关文章:

typescript - vue-router 3.5.1 : <router-link>'s tag prop is deprecated and has been removed in Vue Router 4 中的警告

javascript - Vue native 总是执行 App.js 而不是 .vue

vue.js - 将数据传递给指令?

javascript - Python 中的 Json 带有 var 给出错误

javascript - 方括号和圆括号中三元条件包裹的区别

javascript - 在 Angular App 中通过 RouterLink 绑定(bind) URL 参数

javascript - Vue 3 在设置中使用函数

javascript - AngularJS:指令与 Controller - 什么逻辑放在哪里?

javascript - Vuejs 将数组子级合并为数组

javascript - v-数据表 : bind a custom property to "items" slot