Vue2 の双方向バインディングの原則

1. vue2では、Object.defineProperty()によるデータハイジャック(イベント監視データ変更)により双方向のデータバインディングを実現

Object.defineProperty() :

意味:

Object.defineProperty() メソッドは、オブジェクトに新しいプロパティを直接定義するか、オブジェクトの既存のプロパティを変更して、オブジェクトを返します。(私自身の理解: このメソッドを使用すると、オブジェクトにプロパティを追加したり、既存のプロパティを変更したり、プロパティの変更を監視したりできます)

Vue2 では、このメソッドを使用してデータ オブジェクト (data) を使用できます。Object.defineProperty()进行监听data里面属性的变化进行双向数据绑定

2. Object.defineProperty() の使用方法については、ここでは説明しませんので、mdn の公式ドキュメントを参照してください。

Object.defineProperty() - JavaScript | MDN

3.Object.defineProperty() 関数を使用してオブジェクトの新しいプロパティをカプセル化し、このプロパティの変更を監視できます

 function objAddProperty(obj, key,value){
  // 返回处理完毕的对象
    return Object.defineProperty(obj,key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('obj.a被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('obj.a被访问...')
    return value 
  }
})
}
//声明一个对象
let obj={}
// 为对象新增属性并进行监听该属性的变化
obj= objAddProperty(obj, 'a',1)
console.log(obj);
obj.a=666

3.Object.defineProperty() 関数を使用してオブジェクトの既存のプロパティを変更し、プロパティの変更を監視することができ、プロパティを変更せずにプロパティのハイジャックを実現することもできます (Vue2 でのデータハイジャック、オブジェクトのプロパティの変更のハイジャック)

 1. オブジェクト内の属性をハイジャックする

    function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('属性被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('属性被访问...')
    return value 
  }
  });
}
let obj = { a: 1 };
observeKey(obj, "a");
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;

2. オブジェクト内のすべてのプロパティをハイジャックする

実際には、監視するオブジェクトのプロパティをトラバースすることです。

   function observeObj(obj){
    //循环对象的属性进行监听
   for(let key in obj){
  observeKey(obj,key)
}
   }
    function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('属性被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('属性被访问...')
    return value 
  }
  });
}
let obj = { a: 1,b:2 };
observeObj(obj)
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;
// 读取b,触发get函数
console.log(obj.b);
// 设置a,触发set函数
obj.b = 3;

注: 上記には欠陥があります。つまり、属性値もオブジェクトである場合、{a:1,c:{b:1}} のように属性値をハイジャックすることはできません。

解決策: オブジェクトの属性値のデータ型を確認し、再帰が必要かどうかを判断します。

   function observeObj(obj){
    //循环对象的属性进行监听
   for(let key in obj){
  if(obj[key] instanceof Object){
    observeObj(obj[key])
  }
  else{
    observeKey(obj,key)
  }
}
   }
    function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('属性被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('属性被访问...')
    return value 
  }
  });
}
let obj = { a: 1,c:{b:2} };
observeObj(obj)
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;
// 读取b,触发get函数
console.log(obj.c.b);
// 设置a,触发set函数
obj.c.b = 3;

 observeObj 関数はオブジェクトの新しいプロパティをハイジャックできませんが、オブジェクトの既存のプロパティのみをハイジャックできることに注意してください。

四、Object.defineProperty()的缺陷

1. 詳細な監視には 1 回の再帰が必要です (パフォーマンスの消費が大きい)

2. オブジェクトの追加および削除されたプロパティを監視できない

5、双方向データバインディングの簡単なシミュレーション

注: this._name が理解できない場合は、Object.definePropety を使用してエラー「最大呼び出しスタック サイズを超えました」を報告することになります。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
    <div class="app">
      <input type="text">
      <p><span></span></p>
      <p><button>点击修改data数据模型的name值为马云</button></p>
    </div>
    <script>
      const button=document.querySelector("button")
      const span=document.querySelector("span")
      const input =document.querySelector('input')
      const data={
       name:'hsq'
      }
      input.value=data.name
      span.innerText=`data数据模型的值为${data.name}`
      Object.defineProperty(data,'name',{
        get(){
          return this._name
        },
        set(newValue){
          input.value=newValue
          this._name=newValue
          span.innerText=`data数据模型的值为${newValue}`
          console.log('data数据模型name属性值',newValue);
        }
      })
      input.addEventListener("input",function(e){
        console.log('输入框的值',e.target.value);
        data.name=e.target.value
      })
      button.addEventListener("click",function(){
        data.name='马云'
      })
    </script>
</body>
</html>

おすすめ

転載: blog.csdn.net/h18377528386/article/details/127515469