blog

Vue3レスポンシブ原則

Vue3について\nとはいえ、Vue3はrc4バージョンに持ち越され、4月にフロントエンドサークルのベータリリースが赤熱したときに、みんなが勉強し始めたわけではありません!\nvue2レスポンシブ原則...

Oct 20, 2020 · 8 min. read
シェア

Vue3について とはいえ、Vue3はrc4版まで実施されており、4月にフロントエンドのベータ版リリースが赤っ恥をかいたのをきっかけに、みんな勉強し始めたのでしょうがありません!

vue2 レスポンシブ原則のレビュー

//  
function observe(){
    if(typeof obj !='object' || obj == null){
        return
    }
    if(Array.isArray(obj)){
        Object.setPrototypeOf(obj,arrayProto)
    }else{
    const keys = Object.keys()
    for(let i=0;i<keys.length;i++){
      const key = keys[i]
      defineReactive(obj,key,obj[key])
    }``
    }
}
function defineReactive(target, key, val){
  observe(val)
  Object.defineProperty(obj, key, {
    get(){
      // 依存関係コレクション
      dep.depend()
      return val
    },
    set(newVal){
      if(newVal !== val){
        observe(newVal)
        val = newVal
        // お知らせの更新
        dep.notify()
      }
    }
  })
}

Array responsive: 配列のプロトタイプメソッドをオーバーライドし、変更を通知するロジックを追加します。

//  
const originalProto = Array.prototype
const arrayProto = Object.create(originalProto)
['push','pop','shift','unshift','splice','reverse','sort'].forEach(key=>{
    arrayProto[key] = function(){
        originalProto[key].apply(this.arguments)
        notifyUpdate()
    }
})

vue2レスポンシブの問題点

再帰的、消費量が多い 属性の追加/削除、別のAPIの追加実装が必要 配列、マップ・セット・クラスや他のデータ型の追加実装が必要、レスポンシブには対応できない 修正構文には制限があります。

vue3レスポンシブソリューション

ES6のProxyを使用してデータ応答性を高め、上記のVue2の問題点をすべて解決します。

プロキシは、ターゲット・オブジェクトにインターセプション/プロキシのレイヤーを追加することができ、ターゲット・オブジェクトに対する外部からの操作は、このインターセプションのレイヤーを通過します。

// reactive  
function reactice(obj){
  return new Proxy(obj,{
    get(target, key, receiver){
      const ret = Reflect.get(target, key, receiver)
      return isObject(ret) ? reactice(ret) : ret
    },
    set(target, key, val, receiver){
      const ret = Reflect.set(target, key, val, receiver)
      return ret
    },
    deleteProperty(target, key){
      const ret = Reflect.deleteProperty(target, key)
      return ret
    },
  })
}

レスポンシブ原則

レスポンシブデータに依存する関数cbをeffectで宣言し、cb関数を実行し、実行中にレスポンシブデータゲッターをトリガーして、レスポンシブデータゲッターに追跡します 依存性の収集:targetMapに格納されたデータとcbのマッピング関係を確立します レスポンシブデータが変更されると、トリガーがトリガーされ、targetMapに従って、関連する実行するcbを見つけます。レスポンシブデータが変更されると、トリガがトリガされ、targetMapに従って、関連するcbの実行マッピング関係targetMap構造が見つかります:

targetMap: WeakMap{ 
    target:Map{ 
        key: Set[cb1,cb2...] 
    }
}

手書き vue3 レスポンシブ

構造

// mini-vue3.js
/* レスポンシブデータの作成 */
function reactice(obj){}
/* 応答関数cbを宣言する */
function effect(cb){}
/* 依赖收集:建立 数据&cb 人間関係をマッピングする */
function track(target,key){}
/* トリガー更新:マッピング関係に従って、cbを実行する。 */
function trigger(target,key){}

reactive

/* レスポンシブデータの作成 */
function reactive(obj){
  // Proxy:http://..com/#docs/proxy
  // Proxyこれは、オブジェクトの外側のレイヤーにインターセプトを追加することと同じである。
  // Proxy再帰が不活性なので、再帰ロジックを追加する必要がある
  
  // Reflect:http://..com/#docs/reflect
  // Reflect:オブジェクトのデフォルトの操作を実行するために使用され、より標準化され、より親しみやすく、操作オブジェクトのコレクションとして理解することができる。
  // ProxyとObjectのメソッドReflectはすべて
  if(!isObject(obj)) return obj
  const observed = new Proxy(obj,{
    get(target, key, receiver){
      const ret = Reflect.get(target, key, receiver)
      console.log('getter '+ret)
      // 跟踪 收集依赖
      track(target, key)
      return reactive(ret)
    },
    set(target, key, val, receiver){
      const ret = Reflect.set(target, key, val, receiver)
      console.log('setter '+key+':'+val + '=>' + ret)
      // トリガー更新
      trigger(target, key)
      return ret
    },
    deleteProperty(target, key){
      const ret = Reflect.deleteProperty(target, key)
      console.log('delete '+key+':'+ret)
      // トリガー更新
      trigger(target, key)
      return ret
    },
  })
  return observed
}

effect

/* 応答関数cbを宣言する */
const effectStack = []
function effect(cb){
  // 関数の高次カプセル化
  const rxEffect = function(){
    // 1.例外をキャッチする
    // 2.fnスタックからスタックへ
    // 3.fnを実行する
    try{
      effectStack.push(rxEffect)
      return cb()
    }finally{
      effectStack.pop()
    }
  }
  // 最初に依存関係の収集のために一度だけ実行する。
  rxEffect()
  return rxEffect
}

track

/* 依赖收集:建立 数据&cb 人間関係をマッピングする */
const targetMap = new WeakMap()
function track(target,key){
  // マッピングの関係を保存する
  const effectFn = effectStack[effectStack.length - 1]  // トップ・オブ・スタック機能を取り出す
  if(effectFn){
    let depsMap = targetMap.get(target)
    if(!depsMap){
      depsMap = new Map()
      targetMap.set(target, depsMap)
    }
    let deps = depsMap.get(key)
    if(!deps){
      deps = new Set()
      depsMap.set(key, deps)
    }
    deps.add(effectFn)
  }
}

trigger

/* トリガー更新:マッピング関係に従って、cbを実行する。 */
function trigger(target, key){
  const depsMap = targetMap.get(target)
  if(depsMap){
    const deps = depsMap.get(key)
    if(deps){
      deps.forEach(effect=>effect())
    }
  }
}

テストデモ

<!-- test.html -->
<div id="app">
 {{msg}}
</div>
<script src="./mini-vue3.js"></script>
<script>
  // レスポンシブなデータを定義する
  const state = reactive({
    msg:'message'
  })
  // 定义一个使用到响应式数据的 dom更新函数
    function updateDom(){
        document.getElementById('app').innerText = state.msg
    }
    // 効果を持つ更新関数を宣言する
  effect(updateDom)
  // レスポンシブデータの時限変更
  setInterval(()=>{
    state.msg = 'message' + Math.random()
  },1000)
</script>

効果

ありがとうございました。

1.この記事を気に入っていただけたなら、賛辞を送ってください。

2.私の友人を追加するには、コードをスキャンし、私は "フロントエンドの高度な交流グループ "にあなたをプル、我々はコミュニケーションと進歩のために一緒に働く。

Read next

SAP CRMアプリケーションで添付ファイルのアップロードをサポートするには?

この記事では、CRM7.0 EHP3で開発された新しいCRM - ソーシャルメディアを例にしています。 あなたは、CRM7.0 EHP3で開発された新しいCRM - ソーシャルメディアを使用しているはずです。

Oct 20, 2020 · 2 min read