大きなフロントエンド研究ノート-Vue.js3.0レスポンシブシステムの原則

Vue.js3.0レスポンシブシステムの原則

記事コンテンツの出力ソース:大規模なフロントエンドの高額トレーニングキャンプ

1.はじめに

1.Vue.jsレスポンシブレビュー

  • プロキシオブジェクトはプロパティモニタリングを実装します
  • マルチレベルの属性のネスト、属性にアクセスするプロセスで次のレベルの属性を処理する
  • 動的に追加された属性はデフォルトで監視されます
  • デフォルトの監視属性の削除操作
  • デフォルトの監視アレイのインデックスと長さのプロパティ
  • 個別のモジュールとして使用できます

2.コア機能

  • eactive / ref / toRefs / computed
  • 効果
  • 追跡
  • 引き金

2、プロキシオブジェクトのレビュー

1. strictモードでは、Proxy関数はブール値を返す必要があります。そうでない場合、TypeErrorが報告されます。

Uncaught TypeError: 'set' on proxy:trap return falsish for property'foo '

'use strict'
// 问题1: set和deleteProperty中需要返回布尔类型的值
// 严格模式下,如果返回false的话,会出现TypeError的异常
const target = {
    
    
  foo: 'xxx',
  bar: 'yyy'
}
// Reflect.getPrototypeOf()
// Object.getPrototypeOf()
const proxy = new Proxy(target, {
    
    
  get (target, key, receiver) {
    
    
    // return target[key]
    return Reflect.get(target, key, receiver)
  },
  set (target, key, value, receiver) {
    
    
    // target[key] = value
    return Reflect.set(target, key, value, receiver) // 这里得写return
  },
  deleteProperty(target, key) {
    
    
    // delete target[key]
    return Reflect.deleteProperty(target, key) // 这里得写return
  }
})

proxy.foo = 'zzz'

2.プロキシとリフレクトでレシーバーを使用する

プロキシのレシーバー:プロキシまたは
Reactのプロキシレシーバーを継承するオブジェクト:ターゲットオブジェクトにゲッターがある場合、ゲッターのこれはレシーバーを指します

const obj = {
    
    
  get foo () {
    
    
    console.log(this)
    return this.bar
  }
}

const proxy = new Proxy(obj, {
    
    
  get(target, key, receiver) {
    
    
    if (key === 'bar') {
    
    
      return 'value - bar'
    }
    return Reflect.get(target, key, receiver) // 执行this.bar的时候,this指向代理对象,也就是获取target.bar
  }
})
console.log(proxy.foo) // value - bar

return Reflect.get(target, key, receiver)記述されている場合return Reflect.get(target, key)、レスポンシブ属性fooのthisは元のオブジェクトobjを指し、this.barは未定義であり、レシーバーが渡された後、レスポンシブ属性のthisは新しいレスポンシブオブジェクトプロキシthis.barを指します。戻りvalue - barます。

三、反応性

  • パラメータを受け入れ、このパラメータがオブジェクトであるかどうかを判断します
  • インターセプターオブジェクトハンドラーを作成し、get / set / deletePropertyを設定します
  • Proxyオブジェクトを返します

自分でリアクティブを実現

function isObject(value) {
    
    
  return value !== null && typeof value === 'object'
}

function convert(target) {
    
    
  return isObject(target) ? reactive(target) : target
}

const hasOwnProperty = Object.prototype.hasOwnProperty

function hasOwn(target, key) {
    
    
  return hasOwnProperty.call(target, key)
}

export function reactive(target) {
    
    
  if (!isObject(target)) return target

  const handler = {
    
    
    get (target, key, receiver) {
    
    
      // 收集依赖
      // track(target, key) // 稍后解注释
      console.log('get', key)
      const ret = Reflect.get(target, key, receiver)
      return convert(ret)
    },
    set (target, key, value, receiver) {
    
    
      const oldValue = Reflect.get(target, key, receiver)
      let ret = true
      if (oldValue !== value) {
    
    
        ret = Reflect.set(target, key, value, receiver)
        // 触发更新
        // trigger(target, key) // 稍后解注释
				console.log('set', key, value)
      }
      return ret
    },
    deleteProperty (target, key) {
    
    
      const hasKey = hasOwn(target, key)
      const ret = Reflect.deleteProperty(target, key)
      if (hasKey && ret) {
    
    
        // 触发更新
        // trigger(target, key) // 稍后解注释
				console.log('detele', key)
      }
      return ret
    }
  }

  return new Proxy(target, handler)
}

使用する:

<body>
  <script type="module">
    import {
     
      reactive } from './reactivity/index.js'
    const obj = reactive({
     
     
      name: 'zs',
      age: 18
    })
    obj.name = 'lisi'
    delete obj.age
    console.log(obj)
  </script>
</body>

出力は次のとおりです。

セット名
lisiindex.js:39 detele age
index.html:17プロキシ{名前:“ lisi”}

第四に、依存関係を収集します

ここに写真の説明を挿入

ファイブ、エフェクト、トラック

let activeEffect = null
export function effect(callback) {
    
    
  activeEffect = callback
  callback() // 访问响应式对象的属性,去收集依赖
  activeEffect = null
}

let targetMap = new WeakMap()
export function track(target, key) {
    
     // 收集依赖
  if (!activeEffect)return
  let depsMap = targetMap.get(target)
  if(!depsMap) {
    
    
    targetMap.set(target, depsMap = new Map())
  }
  let dep = depsMap.get(key)
  if(!dep) {
    
    
    depsMap.set(key, dep = new Set())
  }
  dep.add(activeEffect)
}

6、トリガー

export function trigger(target, key) {
    
     // 触发依赖
  const depsMap = targetMap.get(target)
  if(!depsMap)return
  const dept = depsMap.get(key)
  if(dept) {
    
    
    dept.forEach(effect => {
    
    
      effect()
    })
  }
}

使用する:

<body>
  <script type="module">
    import {
     
      reactive, effect } from './reactivity/index.js'
    const product = reactive({
     
     
      name: 'iPhone',
      price: 5000,
      count: 3
    })
    let total = 0
    effect(() => {
     
     
      total = product.price * product.count
    })
    console.log(total) // 15000

    product.price = 4000
    console.log(total) // 12000

    product.count = 1
    console.log(total) // 4000
  </script>
</body>

セブン、ref

有効vs参照

  • refは、基本的なデータタイプをレスポンシブオブジェクトに変換できます

  • refによって返されるオブジェクトは、オブジェクトへの再割り当てにも応答します

  • リアクティブによって返されたオブジェクト、再割り当てはリアクティブを失います

  • リアクティブによって返されたオブジェクトは分解できません

  • 反応性

    const product = reactive({
          
          
      name: 'iPhone',
      price: 5000,
      count: 3
    })
    
  • ref

    const price = ref(5000)
    const count = ref(3)
    

参照を実装します。

export function ref(raw) {
    
    
  // 判断raw是否是ref创建的对象,如果是的话直接返回
  if (isObject(raw) && raw.__v_isRef)return

  let value = convert(raw)
  const r = {
    
    
    __v_isRef: true,
    get value () {
    
    
      track(r, 'value')
      return value
    },
    set value (newValue) {
    
    
      if(newValue !== value) {
    
    
        raw = newValue
        value = convert(raw)
        trigger(r, 'value')
      }
    }
  }
  return r
}

使用する:

<body>
  <script type="module">
    import {
     
      reactive, effect, ref } from './reactivity/index.js'
    const price = ref(5000)
    const count = ref(3)
    let total = 0
    effect(() => {
     
     
      total = price.value * count.value
    })
    console.log(total) // 15000

    price.value = 4000
    console.log(total) // 12000

    count.value = 1
    console.log(total) // 4000
  </script>
</body>

8、toRefs

export function toRefs(proxy) {
    
    
  const ret = proxy instanceof Array ? new Array(proxy.length) : {
    
    }
  for (const key in proxy) {
    
    
    ret[key] = toProxyRef(proxy, key)
  }
  return ret
}

function toProxyRef(proxy, key) {
    
    
  const r = {
    
    
    __v_isRef: true,
    get value () {
    
    
      return proxy[key]
    },
    set value (newValue) {
    
    
      proxy[key] = newValue
    }
  }
  return r
}

使用する

<body>
  <script type="module">
    import {
     
      reactive, effect, toRefs } from './reactivity/index.js'
    function useProduct() {
     
     
      const product = reactive({
     
     
        name: 'iPhone',
        price: 5000,
        count: 3
      })
      return toRefs(product) // 直接返回解构的product不是响应式对象,所以调用toRefs将reactive对象的每个属性都转化成ref对象
    }

    const {
     
      price, count } = useProduct()

    let total = 0
    effect(() => {
     
     
      total = price.value * count.value
    })
    console.log(total) // 15000

    price.value = 4000
    console.log(total) // 12000

    count.value = 1
    console.log(total) // 4000
  </script>
</body>

9、計算

export function computed(getter) {
    
    
  const result = ref()
  effect(() => (result.value = getter()))
  return result
}

使用する

<body>
  <script type="module">
    import {
     
      reactive, effect, computed } from './reactivity/index.js'
    const product = reactive({
     
     
      name: 'iPhone',
      price: 5000,
      count: 3
    })
    let total = computed(() => {
     
     
      return product.price * product.count
    })
    console.log(total.value) // 15000

    product.price = 4000
    console.log(total.value) // 12000

    product.count = 1
    console.log(total.value) // 4000
  </script>
</body>

注:Trigger / track / effctは基本的な機能であり、通常は使用されません。効果の代わりに計算を使用する

おすすめ

転載: blog.csdn.net/jal517486222/article/details/108689672