不调用 Vue v-model 和代理第一集



目前我正在做一个 Vue 项目,我想有一个模型类,将所有初始数据存储在两个属性中:originalattributes。但是,我在通过v-model将属性绑定到输入时遇到困难。

假设我有以下类:

class Model
{
constructor () {
return new Proxy(this, {
get: (target, property, receiver) => {
console.log('get');
return target[property];
},
set: (target, property, value, receiver) => {
console.log('set');
target[property] = value + 123;
return true;
}
});
}
}

此类将在获取属性时记录get,在设置属性时记录set。此外,在设置时,它将在值的末尾添加123。将执行以下操作:

let model = new Model();
model.name = 'test'; // Logs: 'set'
console.log(model.name); // Logs: 'get' and 'test123'

这按预期工作。

当我通过v-model将这些属性绑定到输入时,问题就开始了。将发生以下情况:

在以下位置执行操作:

<input v-model="model.name" />
...
data () {
return {
model: new Model
};
}

在第一次更改时,属性name将添加到model对象。根本没有日志。值末尾没有添加123。模型值已更改为{ model: 't' }

第二次更改它将记录set并添加123。模型值已更改为{ model: 'te123' }

在第二次更改期间记录set调用的参数:Model {__ob__: Observer}, "name", "te", Proxy {__ob__: Observer}

有人以前遇到过这个问题或知道这里发生了什么?

回答@sphinx后

谢谢你的回答!它有效!

为了使事情变得更加复杂,我想将某个fillable数组中的属性设置为名为attributes的属性。但是,相同的行为会返回。

class Model
{
constructor () {
this.attributes = {};
this.fillable = ['name'];
return new Proxy(this, {
get: (target, property, receiver) => {
console.log('get', property);
if (target.fillable.indexOf(property) > -1) { // Check if in fillable
if (!(property in  target.attributes)) {
Vue.set(target.attributes, property, null);
}
return target.attributes[property];
}
return target[property];
},
set: (target, property, value, receiver) => {
console.log('set', property, value);
if (target.fillable.indexOf(property) > -1) {
Vue.set(target.attributes, property, value + 123);
} else {
target[property] = value
}
return true;
}
});
}
}
Vue.config.productionTip = false
new Vue({
el: '#app',
data() {
return {
test: new Model
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<span>{{test.name}}</span>
<input v-model="test.name" type="text">
</div>

在第一次更改期间,name属性直接在model对象上设置。但不调用set方法。

在第二次更改期间,name属性将更改,并调用set方法。

关于为什么会发生这种情况的任何建议?

在你的考试中,getter 将创建一个属性,但它不是反应性(查看 Vue 指南:深度反应性(。

所以 Vue 无法跟踪这些变化

正如上述指南介绍的那样,该解决方案很简单,使用Vue.setvm.$set来确保您的对象具有反应性。

像下面的演示:

class Model
{
constructor () {
return new Proxy(this, {
get: (target, property, receiver) => {
console.log('get', property);
if(!(property in target)) Vue.set(target, property, null)
return target[property]
},
set: (target, property, value, receiver) => {
console.log('set', property, value);
Vue.set(target, property, value + 123)
return true;
}
});
}
}
Vue.config.productionTip = false
new Vue({
el: '#app',
data() {
return {
test: new Model
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<span>{{test.name}}</span>
<input v-model="test.name" type="text">
</div>

最新更新