vue.js - 不要看v-model自己的更新

标签 vue.js vuejs2 vue-component

我有一个支持 v-model 的自定义组件。组件内部值的表示与原始输入完全不同,但在组件内部使用很方便。组件的职责是转换值并让用户以复杂的形式改变它。此外,组件应该响应父组件的 v-model 更改,即它应该监视 value 更改。

我的代码:

export default {
    props: ['value'],
    data() {
        return {innerValue: undefined};
    },
    mounted() {
        this.calculateInnerValue();
    },
    methods: {
        calculateInnerValue() {
            this.innerValue = /* very heavy transformation based on this.value */;
        },
        onUserChange() {
            const value = /* very heavy transformation based on this.innerValue */;
            this.$emit('input', value);
        }
    },
    watch: {
        value() {
            this.calculateInnerValue();
        }
    }
}

问题是,每当该组件触发 input 事件时, watch 就会被触发,从而导致不必要的 calculateInnerModel 调用。

是否有一种好方法可以防止这种行为,同时保持对来自其他来源的父值更改的响应?

我可以想出一个标志,例如

calculateInnerValue() {
    if (!this.itsMeChanging)
        this.innerValue = /* very heavy computation based on this.value */;
},
onChange() {
    const value = /* very heavy computation based on this.innerValue */;
    this.itsMeChanging = true;
    this.$emit('input', value);
    this.itsMeChanging = false;
}

但是,正如您所看到的,这是 nice 的 faaaar。

Github 上稍微相关的问题:https://github.com/vuejs/vue/issues/1829

最佳答案

您可以做的一件事是保留对未转换的 value 属性的引用,然后仅在 value 中的情况下调用 calculateInnerValue 方法观察者与子组件的引用不同。

下面是一个示例,其中 innerValue 现在对应于从父级传入的 value 属性的未转换值,并且转换后的值现在设置为 TransformedValue 数据属性:

export default {
    props: ['value'],
    data() {
        return {
            innerValue: this.value,
            transformedValue: undefined
        };
    },
    mounted() {
        this.calculateTransformedValue();
    },
    methods: {
        calculateTransformedValue() {
            this.transformedValue = /* very heavy transformation based on this.innerValue */;
        },
        onUserChange() {
            this.innerValue = /* very heavy transformation based on this.transformedValue */;
            this.$emit('input', this.innerValue);
        }
    },
    watch: {
        value(value) {
            if (value !== this.innerValue) {
                this.calculateTransformedValue();
                this.innerValue = value;
            }
        }
    }
}

您还可以通过使 transformedValue 成为基于 innerValue 的计算属性来进一步简化代码:

export default {
    props: ['value'],
    data() {
        return {
            innerValue: this.value
        };
    },
    computed: {
        transformedValue() {
           return /* very heavy transformation based on this.innerValue */
        }
    },
    methods: {
        onUserChange() {
            this.innerValue = /* very heavy transformation based on this.transformedValue */;
            this.$emit('input', this.innerValue);
        }
    },
    watch: {
        value(value) {
            this.innerValue = value;
        }
    }
}

关于vue.js - 不要看v-model自己的更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57463191/

相关文章:

vue.js - 如何从 vue.js 2 的父组件重置子组件中的数据?

vue.js - 在 VueJs 应用程序中实现表情符号

javascript - 从子组件中过滤数组数据表

javascript - 如何在 VueJs 中动态添加带有配置集的模板?

vue.js - "error"未在实例上定义,但在渲染期间引用

vue.js - [Vue warn] : Invalid prop: custom validator check failed for prop "value" 是什么原因

vue.js - Vue 未定义在独立的 Web 组件中

javascript - 如果用户关闭选项卡,Vuejs 则发布请求

javascript - Vue.js - 如何将数据传递给组件?

javascript - 在 laravel Blade 中使用 refs 来预先检查复选框