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

Vue源碼學(xué)習(xí)defineProperty響應(yīng)式數(shù)據(jù)原理實(shí)現(xiàn)

 更新時(shí)間:2022年09月06日 09:25:50   作者:i東東  
這篇文章主要為大家介紹了Vue源碼學(xué)習(xí)defineProperty響應(yīng)式數(shù)據(jù)原理實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

準(zhǔn)備工作

接上文數(shù)據(jù)初始化完成之后,就可以對(duì)數(shù)據(jù)進(jìn)行劫持。Vue2中對(duì)數(shù)據(jù)進(jìn)行劫持采用了一個(gè)Api叫Object.defineProperty()

在這里需要提供一個(gè)方法去觀測(cè)data變化,這個(gè)方法是一個(gè)核心模塊(響應(yīng)式模塊),我們單獨(dú)建一個(gè)文件夾來存放在/src/observe/index.js

// src/state.js
import { observe } from "./observe/index"
export function initState(vm){
    // 對(duì)數(shù)據(jù)需要進(jìn)行劫持
    const opts = vm.$options //獲取所有選項(xiàng)
    if (opts.data){
        initData(vm)
    }
}
function initData(vm){
    // 對(duì)數(shù)據(jù)進(jìn)行代理
    let data = vm.$options.data
    // data可以是函數(shù)或者對(duì)象,根實(shí)例可以是對(duì)象,組件data必須是函數(shù)
    data = typeof data === 'function' ? data.call(vm) : data
    // 對(duì)數(shù)據(jù)進(jìn)行劫持 Vue2采用的一個(gè)api object.defineproperty
    observe(data)
}
// src/observe/index.js
export  function observe(data){
  debugger
  console.log(data);
}

執(zhí)行/dist/index.html,當(dāng)控制臺(tái)出可以輸出{name: 'i東東', age: 18}說明前面的代碼沒有問題,接下來就可以開始下面的操作了。

第一步 對(duì)對(duì)象進(jìn)行劫持

當(dāng)拿到了data,就可以對(duì)data數(shù)據(jù)進(jìn)行劫持,如果說他不是對(duì)象就不用劫持,所以還需要進(jìn)行一個(gè)判斷。

// src/observe/index.js
export  function observe(data){   // 對(duì)這個(gè)對(duì)象進(jìn)行劫持
  if(typeof data !=='object'|| data == null){
    return // 只對(duì)對(duì)象進(jìn)行劫持
  }
}

那么緊接著如何劫持這個(gè)對(duì)象呢?

如果一個(gè)對(duì)象被劫持過了,那么就不需要再次被劫持了(要判斷一個(gè)對(duì)象是否被劫持過,可以增添一個(gè)實(shí)例,來判斷是否被劫持過),所以在內(nèi)部創(chuàng)造了一個(gè)類去觀測(cè)數(shù)據(jù),如果數(shù)據(jù)被觀測(cè)過那他的實(shí)例就是這個(gè)類。

// src/observe/index.js
class Observer{
  constructor(data){ //所有數(shù)據(jù)
    this.walk(data) // 因?yàn)閐ata是一個(gè)對(duì)象,所以就需要對(duì)data進(jìn)行比遍歷
  }
  walk(data){ // 循環(huán)對(duì)象 對(duì)屬性依次劫持
     Object.keys(data).forEach(key=>defineReactive(data,key,data[key])) //重新定義屬性
  }
}
export function defineReactive(target,key,value){ // 閉包  屬性劫持
Object.defineProperty(target,key,{
  get(){ //取值的時(shí)候會(huì)執(zhí)行g(shù)et
    return value
  },
  set(newValue){ // 修改的時(shí)候執(zhí)行set
    if(newValue === value) return
    value = newValue
  }
})
}
export  function observe(data){   // 對(duì)這個(gè)對(duì)象進(jìn)行劫持
  if(typeof data !=='object'|| data == null){
    return // 只對(duì)對(duì)象進(jìn)行劫持
  }
  return new Observer(data); // 對(duì)這個(gè)數(shù)據(jù)進(jìn)行觀測(cè)
}

因?yàn)橐獙?duì)每個(gè)屬性進(jìn)行劫持,但是Objece.defineProperty()只能劫持已經(jīng)存在的屬性,后增加的或者刪除的是不知道的,(Vue2里面會(huì)為此單獨(dú)寫一些api 比如:setset setdelete),所以需要對(duì)data進(jìn)行遍歷 this.walk()對(duì)屬性依次劫持,重新定義屬性(性能會(huì)差,Vue3中proxy就會(huì)好很多),就可以調(diào)用defineReactive,因?yàn)檫@個(gè)方法可以單獨(dú)去使用,所以直接導(dǎo)出。

完成之后執(zhí)行index.html中console.log(vm),會(huì)發(fā)現(xiàn)vm上只有用戶的選項(xiàng),并沒有剛才劫持過的屬性,是因?yàn)樵趕tate.js中我們只是data傳入了observe函數(shù),所以就考慮,在vm上增加一個(gè)屬性,叫_data,這樣就相當(dāng)于把_data對(duì)象放在了實(shí)例vm上,并且又把這個(gè)對(duì)象進(jìn)行了觀測(cè),觀測(cè)的時(shí)候依舊回去循環(huán)這個(gè)對(duì)象。

// src/state.js
function initData(vm){
    let data = vm.$options.data
    data = typeof data === 'function' ? data.call(vm) : data
    vm._data = data // 新增這一句
    observe(data)
}

這樣再次輸出,會(huì)發(fā)現(xiàn)控制臺(tái)輸出了_data,并且給age,name都增加上來get和set方法,現(xiàn)在說明這個(gè)事情就成了。

這個(gè)時(shí)候就可以通過vm._data.name進(jìn)行取值

// dist/index.html
const vm = new Vue({
  data(){
    return {
      name:'i東東',
      age:18
    }
  }
})
vm._data.name = 'i東東修改'
console.log(vm._data.name); 
// 用戶設(shè)置值了
// index.js:15 用戶取值了
// index.html:29 i東東修改

第二步 修改取值方法

緊接著就會(huì)發(fā)現(xiàn)正常我們?nèi)≈刀际莢m.name,但是上面的訪問還是vm._data.name,所以下面需要將取值的方法進(jìn)行一下優(yōu)化。需要在state.js中將vm._data用vm代理。

// state.js
function proxy(vm,target,key){
    Object.defineProperty(vm,key,{
        get(){
            return vm[target][key]  // vm._data.name
        },
        set(newValue){
            vm[target][key] = newValue
        }
    })
}
function initData(vm){
    // 對(duì)數(shù)據(jù)進(jìn)行代理
    let data = vm.$options.data
    data = typeof data === 'function' ? data.call(vm) : data
    vm._data = data
    observe(data)
    // 新增 將vm._data用vm代理
    for(let key in data){
        proxy(vm,'_data',key)
    }
}

這樣在index.html中我們就可以用過vm.name重鋼訪問到數(shù)據(jù),也可以通過vm.name = 'i東東修改'去設(shè)置值,雖然這樣性能是不太好的,但是他用起來會(huì)很方便的。所以在這里面相當(dāng)于代理了兩次第一次把用戶的數(shù)據(jù)進(jìn)行了屬性劫持,第二次就是proxy當(dāng)取值和設(shè)置值的時(shí)候代理到某個(gè)人身上。

第三步 深度屬性劫持

// index.html
const vm = new Vue({
  data(){
    return {
      name:'i東東',
      age:18,
      say:{
        hobby:'學(xué)習(xí)'
      }
    }
  }
})
console.log(vm);

假如說我再增加一個(gè)對(duì)象say,輸出vm會(huì)發(fā)現(xiàn)hobby并沒有被劫持,原因是因?yàn)槲覀冎唤俪至薾ame、age、say三個(gè)屬性,如果屬性是個(gè)對(duì)象的話,我們就需要再次劫持。這樣我們只需要在defineReactive()里面再次調(diào)用observe再次建立劫持,形成遞歸這樣就可以完成對(duì)對(duì)象的深度屬性劫持。

// src/observe/index.js
export function defineReactive(target,key,value){ // 閉包  屬性劫持
  observe(value) // 新增 對(duì)所有的對(duì)象都進(jìn)行屬性接觸
  Object.defineProperty(target,key,{
  get(){ //取值的時(shí)候會(huì)執(zhí)行g(shù)et
    console.log('用戶取值了');
    return value
  },
  set(newValue){ // 修改的時(shí)候執(zhí)行set
    console.log('用戶設(shè)置值了');
    if(newValue === value) return
    value = newValue
  }
})
}

以上就是Vue源碼學(xué)習(xí)defineProperty響應(yīng)式數(shù)據(jù)原理實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Vue defineProperty響應(yīng)式數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue3自定義打印實(shí)現(xiàn)原理詳解

    Vue3自定義打印實(shí)現(xiàn)原理詳解

    近接觸到了一個(gè) Vue3 的打印需求,我發(fā)現(xiàn)自己雖然從事前端開發(fā)已有多年,但對(duì)如何實(shí)現(xiàn)自定義打印還沒有深入研究,一般都是找現(xiàn)成的庫來解決問題,借這次的機(jī)會(huì)研究了一下如何實(shí)現(xiàn)自定義打印,需要的朋友可以參考下
    2024-07-07
  • vue3如何實(shí)現(xiàn)PDF文件在線預(yù)覽功能

    vue3如何實(shí)現(xiàn)PDF文件在線預(yù)覽功能

    PDF文件在線預(yù)覽的功能相信大家都是有遇到過的,下面這篇文章主要給大家介紹了關(guān)于vue3如何實(shí)現(xiàn)PDF文件在線預(yù)覽功能的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • vue點(diǎn)擊當(dāng)前路由高亮小案例

    vue點(diǎn)擊當(dāng)前路由高亮小案例

    這篇文章主要為大家詳細(xì)介紹了vue點(diǎn)擊當(dāng)前路由高亮小案例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • vue監(jiān)聽瀏覽器網(wǎng)頁關(guān)閉和網(wǎng)頁刷新事件代碼示例

    vue監(jiān)聽瀏覽器網(wǎng)頁關(guān)閉和網(wǎng)頁刷新事件代碼示例

    在前端開發(fā)中我們通常會(huì)遇到這樣的需求,用戶離開、刷新頁面前,修改數(shù)據(jù)未進(jìn)行保存操作,需要提示框提醒用戶,這篇文章主要給大家介紹了關(guān)于vue監(jiān)聽瀏覽器網(wǎng)頁關(guān)閉和網(wǎng)頁刷新事件的相關(guān)資料,需要的朋友可以參考下
    2023-08-08
  • vue.js 實(shí)現(xiàn)a標(biāo)簽href里添加參數(shù)

    vue.js 實(shí)現(xiàn)a標(biāo)簽href里添加參數(shù)

    今天小編就為大家分享一篇vue.js 實(shí)現(xiàn)a標(biāo)簽href里添加參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • Vuepress 搭建帶評(píng)論功能的靜態(tài)博客的實(shí)現(xiàn)

    Vuepress 搭建帶評(píng)論功能的靜態(tài)博客的實(shí)現(xiàn)

    這篇文章主要介紹了Vuepress 搭建帶評(píng)論功能的靜態(tài)博客的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • 在vue+element-plus中無法同時(shí)使用v-for和v-if的問題及解決方法

    在vue+element-plus中無法同時(shí)使用v-for和v-if的問題及解決方法

    由于路由中存在不需要遍歷的數(shù)據(jù)所以像用v-if來過濾,但是報(bào)錯(cuò),百度說vue不能同時(shí)使用v-if和v-for,今天小編給大家分享解決方式,感興趣的朋友跟隨小編一起看看吧
    2023-07-07
  • Vue對(duì)Element中的el-tag添加@click事件無效的解決

    Vue對(duì)Element中的el-tag添加@click事件無效的解決

    本文主要介紹了Vue對(duì)Element中的el-tag添加@click事件無效的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • vue3中關(guān)于路由hash與History的設(shè)置

    vue3中關(guān)于路由hash與History的設(shè)置

    這篇文章主要介紹了vue3中關(guān)于路由hash與History的設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 使用vue與jquery實(shí)時(shí)監(jiān)聽用戶輸入狀態(tài)的操作代碼

    使用vue與jquery實(shí)時(shí)監(jiān)聽用戶輸入狀態(tài)的操作代碼

    本文是腳本之家小編給大家?guī)淼氖褂胿ue與jquery實(shí)時(shí)監(jiān)聽用戶輸入狀態(tài),實(shí)現(xiàn)效果是input未輸入值時(shí),按鈕禁用狀態(tài),具體操作代碼大家參考下本文吧
    2017-09-09

最新評(píng)論

淳化县| 乐陵市| 喀什市| 喀喇沁旗| 仁怀市| 华坪县| 商洛市| 桓台县| 钟山县| 日喀则市| 长治县| 丽江市| 保康县| 即墨市| 葵青区| 甘孜| 临漳县| 嘉禾县| 松溪县| 贵定县| 景东| 左权县| 焦作市| 辽宁省| 昭觉县| 新乡县| 苏尼特右旗| 永仁县| 五常市| 英山县| 棋牌| 井陉县| 左权县| 安平县| 收藏| 成安县| 澳门| 永平县| 廉江市| 奉化市| 凤城市|