2

我有一个关于创建可使用的 VueJS 组件的问题,这些组件v-model利用底层的valueprop 和$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 给出了一个控制台错误:

避免直接改变 prop,因为只要父组件重新渲染,该值就会被覆盖。相反,使用基于道具值的数据或计算属性。道具被变异:“价值”

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

4

3 回答 3

1

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

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

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

如果对数组的下一次修改依赖于对数组的先前修改,则您不能同时执行它们。但是你需要它发生得相当快(我假设你希望用户觉得它发生得很快)。您可以做的是val对组件内部进行修改,而不是使其依赖于道具。该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快速连续执行,而无需等待任何事情。

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

于 2019-04-30T05:29:44.857 回答
0
  1. Emit向父母发送消息以更改道具。
  2. 把 awatcher放在道具上(在孩子身上),然后把你的代码放在那里使用新值。

这可以防止孩子改变它不拥有的数据,并允许它避免使用nextTick. 现在您的代码是异步且反应式的,无需依赖非确定性延迟。

于 2019-04-30T05:35:53.590 回答
0

制作副本怎么样value

moveIdToIndex (id, newIndex) {
    const valueCopy = [...this.value]
    const newArrayHead = this.valueCopy
      .slice(0, newIndex)
      .filter(_id => _id !== id)
    const newArrayTail = this.valueCopy
      .slice(newIndex)
      .filter(_id => _id !== id)
    const newArray = [...newArrayHead, id, ...newArrayTail]
    return this.updateArray(newArray)
于 2019-04-30T05:48:42.597 回答