【问题标题】:Vue reactivity, prevent re-rendering component on prop update with input v-modelVue 反应性,防止在使用输入 v-model 更新道具时重新渲染组件
【发布时间】:2020-12-22 04:04:33
【问题描述】:

我正在尝试如何在不导致组件重新渲染的情况下改变文本输入中的道具。

这是我的代码

//App.vue

<template>
    <div class="row">
        <category-component v-for="category in categories" :key="category.title" :category="category" />
    </div>
</template>


export default {
  name: "App",
  data() {
    return {
      categories: [
        {
          title: "Cat 1",
          description: "description"
        },
        {
          title: "Cat 2",
          description: "description"
        },
        {
          title: "Cat 3",
          description: "description"
        }
      ]
    };
  },
  components: {
    CategoryComponent
  }
}
// CategoryComponent.vue

<template>
    <div>
        <input type="text" v-model="category.title">
        <br>
        <textarea v-model="category.description"></textarea>
    </div>
</template>

当我更新文本输入时,组件重新渲染并且我失去焦点。但是,当我更新 textarea 时,它不会重新渲染。

任何人都可以对此有所了解吗?我显然错过了一些简单的 vue 反应性。

这是我的问题的基本codesandbox

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    您遇到的问题是由:key="category.title" 引起的。检查Vue Guide: key

    key 特殊属性主要用作 Vue 的提示 虚拟 DOM 算法在区分新列表时识别 VNode 对旧列表的节点。没有键,Vue 使用一种算法 最小化元素移动并尝试修补/重用 尽可能在原地使用相同的类型。使用键,它将重新排序 基于键的顺序变化的元素,以及带有键的元素 不再存在的将始终被删除/销毁。

    改变标题时,改变key,然后VNode会被销毁然后创建,这就是它失去焦点的原因,改变摘要时也不会失去焦点。

    所以解决方法是使用 v-for 的第二个参数=index 作为键。

    并且不要直接改变 props,所以在下面的 sn-p 中,我使用了一个计算的 setter 来发出一个输入事件来通知父组件更新绑定值(v-model)。

    您也可以查看this question: updating-a-prop-inside-a-child-component-so-it-updates-on-the-parent 了解有关更新组件内的道具的更多详细信息。

    Vue.component('category-component', {
        template:`
          <div class="hello">
            <input type="text" v-model="innerTitle">
            <br>
            <textarea v-model="innerSummary"></textarea>
          </div>
        `,
        props: {
          value: {
            default: () => {return {}},
            type: Object
          }
        },
        computed: {
          innerTitle: {
            get: function () {
              return this.value.title
            },
            set: function (val) {
              this.$emit('input', {summary: this.value.summary, title: val})
            }
          },
          innerSummary: {
            get: function () {
              return this.value.summary
            },
            set: function (val) {
              this.$emit('input', {title: this.value.title, summary: val})
            }
          }
        }
    })
    
    new Vue ({
      el:'#app',
      data () {
        return {
          categories: [
            {
              title: "Cat 1",
              summary: "description"
            },
            {
              title: "Cat 2",
              summary: "description"
            },
            {
              title: "Cat 3",
              summary: "description"
            }
          ]
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
      <div id="app">
        {{ categories }}
        <category-component v-for="(category, index) in categories" :key="index" v-model="categories[index]" />
      </div>

    【讨论】:

    • NP。在某些场景下,我们可能会使用特殊的 attr=key 来实现一些特殊的效果或特性。例如:手动更改key触发enter/leave动画,或者强制重新创建一个组件(VNode)。
    猜你喜欢
    • 2019-10-09
    • 1970-01-01
    • 2021-01-19
    • 2019-09-15
    • 2018-01-30
    • 2020-05-01
    • 2021-01-22
    • 2018-12-30
    相关资源
    最近更新 更多