双方向データ バインディングの実装方法 (インタビューの質問)
双方向バインディングを実装するには、次の 2 つの方法があります。
- Object.definedProperty( ) [オブジェクト監視のために vue2 で使用される Object.definedProperty( )]
- Proxy(プロキシオブジェクト)【vue3以降はProxyで実現】
上記の 2 つの方法で実現するには、簡単に言えば、データのハイジャックです. オブジェクトのプロパティにアクセスまたは変更する場合、これらの 2 つの方法でインターセプトされ、さらに操作すると結果が返されます。
1. Object.defineProperty() を使用して、双方向のデータ バインディングを実現します。
- Data -> view Object.defineProperty は object プロパティの値変更を乗っ取り、set メソッドでビューに影響を与える
- 表示 -> データ監視入力/変更イベント、変数に値を代入
<body>
<div class="box">
<h4>当控制台中的值发生改变,input框中的内容随之发生改变</h4>
数据影响视图:
<input type="text" id="inp">
</div>
<div class="box">
<h4>当input框中内容发生改变,控制台中的值发生改变</h4>
视图影响数据:
<input type="text" id="inp2">
</div>
<script>
// data对象
let data = {
msg: '初始值'
}
//definedProperty()方法 vue2
// txt 实例
let txt = {
};
let txt1 = {
};
// 1. 变量 =》 视图 使用Object.definedProperty定义对象中新属性或修改原有的属性(也就是检测对象属性值的变化)
// ----Object.definedProperty语法
// -------defineProperty(属性所在对象,属性名,描述符对象(value))
// (1):给txt添加同名的属性(影子)
Object.defineProperty(txt, 'msg', {
set(val) {
//给txt的msg属性赋值,就会触发set方法(val就是给txt.msg赋予的值)
data['msg'] = val;
// (2): set中影响对应视图
document.getElementById('inp').value = val;
},
get() {
//获取txt的msg的值
return data['msg']
}
})
// // 2. 视图 =》 变量 (依赖于oninput/onchange事件)
inp2.oninput = function() {
txt1.msg = this.value
}
</script>
</body>
双方向データバインディング (definedProperty)
2. Proxy (プロキシ) を使用して、データの双方向バインディングを実現します。
- オブジェクトのプロキシ オブジェクトを作成し、プロキシ オブジェクトのメソッドを変更します。
<body>
<div class="box">
<h4>当控制台中的值发生改变,input框中的内容随之发生改变</h4>
数据影响视图:
<input type="text" id="inp">
</div>
<div class="box">
<h4>当input框中内容发生改变,控制台中的值发生改变</h4>
视图影响数据:
<input type="text" id="inp2">
</div>
<script>
// data对象
let data = {
msg: '初始值'
}
// Proxy(代理对象) vue3
let txt = new Proxy(data, {
set: function(target, prop, val) {
data['msg'] = val;
document.getElementById('inp').value = val;
return Reflect.set(target, prop, val);
},
get: function(target, prop) {
return Reflect.get(target, prop);
}
})
let txt1 = new Proxy(data, {
set: function(target, prop, val) {
data['msg'] = val;
return Reflect.set(target, prop, val)
},
get: function(target, prop) {
return Reflect.get(target, prop)
}
})
inp2.oninput = function() {
txt1.msg = this.value;
}
</script>
</body>
双方向のデータ バインディング (プロキシ)
3. Object.definedProperty( ) と Proxy (プロキシ) の違い
(1) Proxy は Object.defineProperty よりもはるかに便利です。
(2) Proxy はオブジェクト全体をプロキシし、Object.defineProperty はオブジェクトのプロパティのみをプロキシします。
(3) vue では、Proxy は呼び出し時に再帰的であり、Object.defineProperty は最初はすべて再帰的であり、Proxy のパフォーマンスは Object.defineProperty よりも優れています。
(4) オブジェクトに新しいプロパティが定義されると、Proxy はそれを監視できますが、Object.defineProperty は監視できません。
(5) 配列が追加、削除、または変更されると、Proxy はそれを監視できますが、Object.defineProperty は監視できません。
(6) Proxy は IE と互換性がなく、Object.defineProperty は IE8 以下と互換性がありません。
4. まとめ:
(1) ビューの変更を変数に同期する方法は?
- ビューは oninput/onchange イベントをバインドし、値を取得して変数に割り当てます
(2) オブジェクト内の属性の値の変化を検出する方法は?
- Object.defineProperty データの乗っ取り、set と get の書き換え
(3) いつ設定され、いつトリガーされますか?
- プロパティに値を割り当てるとセットがトリガーされ、値を取得すると取得がトリガーされます