javascript - Vue v-model and proxy first set is not called
问题描述
Currently I am working on a Vue project where I want to have a model class that stores all its initial data in two properties: original
and attributes
. However I am having difficulties with binding properties to an input via v-model
.
Lets say I have the following class:
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;
}
});
}
}
This class will log get
when getting a property and set
when setting a property. Also while setting it will add 123
at the end of the value. The following will be executed:
let model = new Model();
model.name = 'test'; // Logs: 'set'
console.log(model.name); // Logs: 'get' and 'test123'
This works as expected.
The problems start when I bind these properties to an input via v-model
. The following happens:
Actions are executed on:
<input v-model="model.name" />
...
data () {
return {
model: new Model
};
}
On the first change the property name
will be added to the model
object. No log at all. No added 123
at the end of the value. The model value has changed to { model: 't' }
.
Second change it will log set
and it will add 123
. The model value has changed to { model: 'te123' }
.
Logging the arguments of of the set
call during the second change:
Model {__ob__: Observer}, "name", "te", Proxy {__ob__: Observer}
Anyone had this problem before or knows what is going on here?
After answer of @sphinx
Thank you for your answer! It works!
To make things more complicated I want to have the properties that are in a certain fillable
array to be set in a property called attributes
. However the same behaviour returns.
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>
During the first change the name
property is set directly on the model
object. But the set
method is not called.
During the second change the name
property is changing and the set
method is called.
Any suggestions on why this happens?
解决方案
在您的示例中,getter 将创建一个属性,但它不是反应性的(查看Vue 指南:深度反应性)。
因此 Vue 无法跟踪更改。
该解决方案很简单,如上述指南介绍、使用Vue.set
或vm.$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>
推荐阅读
- elasticsearch - ElasticSearch 过滤多个必填字段
- spring-batch - 使用 @StepScope 时 Spring Batch 重启功能不起作用
- terminal - Windows 10 更新后,Visual Studio Code 终端以浅蓝色突出显示
- java - 如何修复 64 位/32 位系统的 java.lang.UnsatisfiedLinkError-Problem?
- node.js - MongoNetworkError:无法连接到服务器
- codeigniter - 我已将我的文件从现有服务器迁移到新服务器?但测试,会话正在工作
- html-table - DOMPDF 0.8.3 如何拆分长垂直表
- javascript - JS 文件无法在 CPanel 中加载
- recaptcha - 谷歌 reCAPTCHA 响应
- jar - 从命令行运行时,weld-se 无法在类路径的不同 jar 中找到 bean