最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文完全掌握Vue中的$set方法

 更新時(shí)間:2023年11月01日 10:49:53   作者:upward_tomato  
這篇文章主要給大家介紹了關(guān)于如何完全掌握Vue中$set方法的相關(guān)資料,vue中$set方法對(duì)數(shù)組和對(duì)象的處理本質(zhì)上的一樣的,對(duì)新增的值添加響應(yīng)然后手動(dòng)觸發(fā)派發(fā)更新,需要的朋友可以參考下

start

今天在使用 $set 的時(shí)候,發(fā)現(xiàn)如果 被賦值的數(shù)據(jù) 層級(jí)較深會(huì)出現(xiàn)報(bào)錯(cuò)的情況。

一知半解,是我最討厭的狀態(tài),今天就帶著問(wèn)題,再閱讀一下對(duì)應(yīng)的源碼,了解問(wèn)題的本質(zhì)。

問(wèn)題說(shuō)明

簡(jiǎn)單說(shuō)明一下我遇到的問(wèn)題,明確探究問(wèn)題的目標(biāo)。

需求

我有一個(gè)空對(duì)象,我希望可以給它的屬性的屬性的屬性賦值。

錯(cuò)誤代碼:

<template>
  <div>
    lazy_tomato

    <h2>{{ obj }}</h2>

    <button @click="handleChange">點(diǎn)擊我給obj賦值</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj: {},
    }
  },
  methods: {
    handleChange() {
      this.obj.a = {
        b: {
          c: '愛(ài)吃番茄',
        },
      }

      console.log(JSON.stringify(this.obj))
      // 直接新增屬性,不會(huì)觸發(fā) vue2本質(zhì)的Object.defineProperty。所以數(shù)據(jù)更新了視圖不更新
    },
  },
}
</script>

正確代碼

<template>
  <div>
    lazy_tomato
    <h2>{{ obj }}</h2>
    <button @click="handleChange">點(diǎn)擊我給obj賦值</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      obj: {},
    }
  },
  methods: {
    handleChange() {
      // 錯(cuò)誤代碼二  typeError: Cannot read properties of undefined (reading '__ob__')
      // this.$set(this.obj.a, 'b.c', '愛(ài)吃番茄')
      // 正確代碼
      this.$set(this.obj, 'a', { b: { c: '愛(ài)吃番茄' } })
      console.log(JSON.stringify(this.obj))
    },
  },
}
</script>

所以 $set 對(duì)這三個(gè)參數(shù)分別是如何處理的?如何避免我們錯(cuò)誤使用?

官方文檔

區(qū)分 Vue.set 和 vm.$set

Vue 構(gòu)造函數(shù)自身上的 setvm 實(shí)例上的 $set 是相同的函數(shù)。

解決了以下問(wèn)題:

1.新增對(duì)象的屬性

2.刪除對(duì)象的屬性

3.通過(guò)數(shù)組索引修改數(shù)據(jù)

對(duì)應(yīng)源碼

完整源碼

export function set (target: Array<any> | Object, key: any, val: any): any {
  if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
  }
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  if (target._isVue || (ob && ob.vmCount)) {
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  if (!ob) {
    target[key] = val
    return val
  }
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

分析源碼

// 1. 接受參數(shù)類型分別為  數(shù)組/對(duì)象; 任意 ; 任意
export function set(target: Array<any> | Object, key: any, val: any): any {
  // 2. 判斷第一個(gè)參數(shù) 不為 undefined null string number symbol boolean
  if (
    process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(
      `Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`
    )
  }

  // 3. 如果是數(shù)組,而且第二個(gè)參數(shù)是有效索引
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 更新數(shù)組長(zhǎng)度 有可能傳入的索引大于現(xiàn)有索引
    target.length = Math.max(target.length, key)

    // 調(diào)用 splice
    target.splice(key, 1, val)

    // // 返回值是設(shè)置的值
    return val
  }

  // 4. 是該對(duì)象的屬性 (且不是原型鏈上的屬性)
  if (key in target && !(key in Object.prototype)) {
    // 直接賦值 (這里賦值可以觸發(fā) Object.defineProperty)
    target[key] = val

    // 返回值是設(shè)置的值
    return val
  }

  // 5. 獲取 observe實(shí)例
  const ob = (target: any).__ob__
  if (target._isVue || (ob && ob.vmCount)) {
    process.env.NODE_ENV !== 'production' &&
      warn(
        'Avoid adding reactive properties to a Vue instance or its root $data ' +
          'at runtime - declare it upfront in the data option.'
      )
    return val
  }

  // 6. 無(wú)observe實(shí)例,直接賦值,// 返回值是設(shè)置的值
  if (!ob) {
    target[key] = val
    return val
  }

  // 7. 收集依賴
  defineReactive(ob.value, key, val)

  // 8. 手動(dòng)通知,觸發(fā)視圖更新
  ob.dep.notify()
  // // 返回值是設(shè)置的值
  return val
}

/* 工具函數(shù) */
function isPrimitive(value) {
  return (
    typeof value === 'string' ||
    typeof value === 'number' ||
    // $flow-disable-line
    typeof value === 'symbol' ||
    typeof value === 'boolean'
  )
}

// explicitness and function inlining.
function isUndef(v) {
  return v === undefined || v === null
}

// 是否是有效的數(shù)組索引
function isValidArrayIndex(val) {
  const n = parseFloat(String(val))
  return n >= 0 && Math.floor(n) === n && isFinite(val)
}

小結(jié):

主要的處理順序:

  • 處理數(shù)組(使用 劫持過(guò)的數(shù)組 splice 方法);
  • 處理對(duì)象上自帶的屬性;
  • 收集依賴,手動(dòng)觸發(fā)。
// this.$set(this.obj.a, 'b.c', '愛(ài)吃番茄')
錯(cuò)誤的原因,this.obj.a 本身是 undefined 所以直接被第一步就攔截了。

// this.obj.a={}
// this.$set(this.obj.a, 'b.c', '愛(ài)吃番茄')
也達(dá)不到效果,它會(huì)直接吧 b.c當(dāng)做屬性名初始化

思考:

雖然官方文檔設(shè)定,第二個(gè)參數(shù)是數(shù)字和字符串,理論上可以傳入其他類型的。第二個(gè)參數(shù)最好是單層級(jí)的屬性值

擴(kuò)展 :del 方法

/**
 * Delete a property and trigger change if necessary.
 * 如果需要,刪除屬性并觸發(fā)更改。
 */
export function del(target: Array<any> | Object, key: any) {
  if (
    process.env.NODE_ENV !== "production" &&
    // 如果是 undefined 或 null; 或者是原始值 ---同Vue.$set
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(
      `Cannot delete reactive property on undefined, null, or primitive value: ${target}`
    );
  }

  // 數(shù)組,利用splice,直接改
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.splice(key, 1);
    return;
  }

  // ---同Vue.$set 排除Vue實(shí)例 和 根對(duì)象
  const ob = (target: any).__ob__;
  if (target._isVue || (ob && ob.vmCount)) {
    process.env.NODE_ENV !== "production" &&
      warn(
        "Avoid deleting properties on a Vue instance or its root $data " +
          "- just set it to null."
      );
    return;
  }

  // 如果 屬性不是自身的屬性,直接 return
  if (!hasOwn(target, key)) {
    return;
  }

  // 刪除對(duì)應(yīng)的key
  delete target[key];

  // 不是響應(yīng)式的不做處理(這個(gè)地方可以理解為,淺層監(jiān)聽(tīng)的 watch,有些深層的屬性不需要watch,就會(huì)走這個(gè)情況)
  if (!ob) {
    return;
  }

  // 手動(dòng)觸發(fā) ?。?有作者在想,直接在代碼中 `.__ob__`  手動(dòng)通知不就ok了? 雖然可以但是不建議這樣做、
  ob.dep.notify();
}

end

上述的演示,源碼查看的是 vue@2.6。 vue3中由于響應(yīng)式實(shí)現(xiàn)原理發(fā)生了變化,所以不需要 $set 了,所以不做探究。

到此這篇關(guān)于完全掌握Vue中$set方法的文章就介紹到這了,更多相關(guān)Vue $set方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決vue過(guò)濾器filters獲取不到this對(duì)象的問(wèn)題

    解決vue過(guò)濾器filters獲取不到this對(duì)象的問(wèn)題

    這篇文章主要介紹了解決vue過(guò)濾器filters獲取不到this對(duì)象的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • elementplus?card?懸浮菜單的實(shí)現(xiàn)

    elementplus?card?懸浮菜單的實(shí)現(xiàn)

    本文主要介紹了elementplus?card?懸浮菜單的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • vue+webpack dev本地調(diào)試全局樣式引用失效的解決方案

    vue+webpack dev本地調(diào)試全局樣式引用失效的解決方案

    今天小編就為大家分享一篇vue+webpack dev本地調(diào)試全局樣式引用失效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • vue 通過(guò)下拉框組件學(xué)習(xí)vue中的父子通訊

    vue 通過(guò)下拉框組件學(xué)習(xí)vue中的父子通訊

    這篇文章主要介紹了vue 通過(guò)下拉框組件學(xué)習(xí)vue中的父子通訊的相關(guān)知識(shí),文中涉及到了父組件,子組件的實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2017-12-12
  • 關(guān)于對(duì)keep-alive的理解,使用場(chǎng)景以及存在的問(wèn)題解讀

    關(guān)于對(duì)keep-alive的理解,使用場(chǎng)景以及存在的問(wèn)題解讀

    這篇文章主要介紹了關(guān)于對(duì)keep-alive的理解,使用場(chǎng)景以及存在的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 你不知道的SpringBoot與Vue部署解決方案

    你不知道的SpringBoot與Vue部署解決方案

    這篇文章主要介紹了你不知道的SpringBoot與Vue部署解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 如何用Vue3切換中英文顯示舉例說(shuō)明

    如何用Vue3切換中英文顯示舉例說(shuō)明

    這篇文章主要給大家介紹了關(guān)于如何用Vue3切換中英文顯示的相關(guān)資料,在Vue3中使用vue-i18n進(jìn)行國(guó)際化設(shè)置,包括安裝、配置、在組件中使用$t方法獲取翻譯字符串,以及可選的動(dòng)態(tài)加載語(yǔ)言包以提高性能,需要的朋友可以參考下
    2024-11-11
  • Vue編寫多地區(qū)選擇組件

    Vue編寫多地區(qū)選擇組件

    這篇文章主要為大家詳細(xì)介紹了Vue編寫一個(gè)挺靠譜的多地區(qū)選擇組件的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 在Vue中實(shí)現(xiàn)網(wǎng)頁(yè)截圖與截屏功能詳解

    在Vue中實(shí)現(xiàn)網(wǎng)頁(yè)截圖與截屏功能詳解

    在Web開(kāi)發(fā)中,有時(shí)候需要對(duì)網(wǎng)頁(yè)進(jìn)行截圖或截屏,Vue作為一個(gè)流行的JavaScript框架,提供了一些工具和庫(kù),可以方便地實(shí)現(xiàn)網(wǎng)頁(yè)截圖和截屏功能,本文將介紹如何在Vue中進(jìn)行網(wǎng)頁(yè)截圖和截屏,需要的朋友可以參考下
    2023-06-06
  • vue實(shí)現(xiàn)登錄頁(yè)面的驗(yàn)證碼以及驗(yàn)證過(guò)程解析(面向新手)

    vue實(shí)現(xiàn)登錄頁(yè)面的驗(yàn)證碼以及驗(yàn)證過(guò)程解析(面向新手)

    這篇文章主要介紹了vue實(shí)現(xiàn)登錄頁(yè)面的驗(yàn)證碼以及驗(yàn)證過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08

最新評(píng)論

栖霞市| 南部县| 石城县| 承德市| 当阳市| 沧州市| 磐安县| 罗田县| 庆安县| 紫云| 墨江| 九台市| 东台市| 本溪市| 泰宁县| 贡觉县| 辽中县| 湘阴县| 兰西县| 会泽县| 隆德县| 平远县| 雷山县| 温州市| 西乌珠穆沁旗| 安化县| 赫章县| 福安市| 巢湖市| 泸水县| 甘孜| 昔阳县| 朝阳区| 芦溪县| 湖北省| 琼结县| 水城县| 和林格尔县| 湟源县| 松阳县| 高淳县|