国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

用vue框架的基本原理,簡(jiǎn)單實(shí)現(xiàn)一個(gè)todo-list

Karrdy / 3231人閱讀

摘要:前言最近在學(xué)習(xí)框架的基本原理,看了一些技術(shù)博客以及一些對(duì)源碼的簡(jiǎn)單實(shí)現(xiàn),對(duì)數(shù)據(jù)代理數(shù)據(jù)劫持模板解析變異數(shù)組方法雙向綁定有了更深的理解。

前言

最近在學(xué)習(xí)vue框架的基本原理,看了一些技術(shù)博客以及一些對(duì)vue源碼的簡(jiǎn)單實(shí)現(xiàn),對(duì)數(shù)據(jù)代理、數(shù)據(jù)劫持、模板解析、變異數(shù)組方法、雙向綁定有了更深的理解。于是乎,嘗試著去實(shí)踐自己學(xué)到的知識(shí),用vue的一些基本原理實(shí)現(xiàn)一個(gè)簡(jiǎn)單的todo-list,完成對(duì)深度復(fù)雜對(duì)象的雙向綁定以及對(duì)數(shù)組的監(jiān)聽(tīng),加深了對(duì)vue基本原理的印象。

github地址:todo-list

在線預(yù)覽: https://fatdong1.github.io/to...

學(xué)習(xí)鏈接

前排感謝以下文章,對(duì)我理解vue的基本原理有很大的幫助!

剖析vue實(shí)現(xiàn)原理,自己動(dòng)手實(shí)現(xiàn)mvvm by DMQ

對(duì)vue早期源碼的理解 by 梁少峰

實(shí)現(xiàn)效果

數(shù)據(jù)代理 1.簡(jiǎn)單介紹數(shù)據(jù)代理

正常情況下,我們都會(huì)把數(shù)據(jù)寫在data里面,如下面所示

var vm = new Vue({
    el: "#app",
    data: {
        title: "hello world"
    }
    methods: {
        changeTitle: function () {
            this.title = "hello vue"
        }
    }
})
console.log(vm.title) // "hello world" or "hello vue"

如果沒(méi)有數(shù)據(jù)代理,而我們又要修改data里面的title的話,methods里面的changeTitle只能這樣修改成this.data.title = "hello vue", 下面的console也只能改成console.log(vm.data.title),數(shù)據(jù)代理就是這樣的功能。

2. 實(shí)現(xiàn)原理

通過(guò)遍歷data里面的屬性,將每個(gè)屬性通過(guò)object.defineProperty()設(shè)置getter和setter,將data里面的每個(gè)屬性都復(fù)制到與data同級(jí)的對(duì)象里。

(對(duì)應(yīng)上面的示例代碼)

觸發(fā)這里的getter將會(huì)觸發(fā)data里面對(duì)應(yīng)屬性的getter,觸發(fā)這里的setter將會(huì)觸發(fā)data里面對(duì)應(yīng)屬性的setter,從而實(shí)現(xiàn)代理。實(shí)現(xiàn)代碼如下:

var self = this;   // this為vue實(shí)例, 即vm
Object.keys(this.data).forEach(function(key) {
    Object.defineProperty(this, key, {    // this.title, 即vm.title
        enumerable: false,
        configurable: true,
        get: function getter () {
            return self.data[key];   //觸發(fā)對(duì)應(yīng)data[key]的getter
        },
        set: function setter (newVal) {
            self.data[key] = newVal;  //觸發(fā)對(duì)應(yīng)data[key]的setter
        }
    });
}

對(duì)object.defineProperty不熟悉的小伙伴可以在MDN的文檔(鏈接)學(xué)習(xí)一下

雙向綁定

數(shù)據(jù)變動(dòng) ---> 視圖更新

視圖更新(input、textarea) --> 數(shù)據(jù)變動(dòng)

視圖更新 --> 數(shù)據(jù)變動(dòng)這個(gè)方向的綁定比較簡(jiǎn)單,主要通過(guò)事件監(jiān)聽(tīng)來(lái)改變數(shù)據(jù),比如input可以監(jiān)聽(tīng)input事件,一旦觸發(fā)input事件就改變data。下面主要來(lái)理解一下數(shù)據(jù)變動(dòng)--->視圖更新這個(gè)方向的綁定。

1. 數(shù)據(jù)劫持

不妨讓我們自己思考一下,如何實(shí)現(xiàn)數(shù)據(jù)變動(dòng),對(duì)應(yīng)綁定數(shù)據(jù)的視圖就更新呢?

答案還是object.defineProperty,通過(guò)object.defineProperty遍歷設(shè)置this.data里面所有屬性,在每個(gè)屬性的setter里面去通知對(duì)應(yīng)的回調(diào)函數(shù),這里的回調(diào)函數(shù)包括dom視圖重新渲染的函數(shù)、使用$watch添加的回調(diào)函數(shù)等,這樣我們就通過(guò)object.defineProperty劫持了數(shù)據(jù),當(dāng)我們對(duì)數(shù)據(jù)重新賦值時(shí),如this.title = "hello vue",就會(huì)觸發(fā)setter函數(shù),從而觸發(fā)dom視圖重新渲染的函數(shù),實(shí)現(xiàn)數(shù)據(jù)變動(dòng),對(duì)應(yīng)視圖更新。

2. 發(fā)布-訂閱模式

那么問(wèn)題來(lái)了,我們?nèi)绾卧趕etter里面觸發(fā)所有綁定該數(shù)據(jù)的回調(diào)函數(shù)呢?

既然綁定該數(shù)據(jù)的回調(diào)函數(shù)不止一個(gè),我們就把所有的回調(diào)函數(shù)放在一個(gè)數(shù)組里面,一旦觸發(fā)該數(shù)據(jù)的setter,就遍歷數(shù)組觸發(fā)里面所有的回調(diào)函數(shù),我們把這些回調(diào)函數(shù)稱為訂閱者。數(shù)組最好就定義在setter函數(shù)的最近的上級(jí)作用域中,如下面實(shí)例代碼所示。

Object.keys(this.data).forEach(function(key) {
    var subs = [];  // 在這里放置添加所有訂閱者的數(shù)組
    Object.defineProperty(this.data, key, {    // this.data.title
        enumerable: false,
        configurable: true,
        get: function getter () {
            console.log("訪問(wèn)數(shù)據(jù)啦啦啦")
            return this.data[key];   //返回對(duì)應(yīng)數(shù)據(jù)的值
        },
        set: function setter (newVal) {
            if (newVal === this.data[key]) {   
                return;    // 如果數(shù)據(jù)沒(méi)有變動(dòng),函數(shù)結(jié)束,不執(zhí)行下面的代碼
            }
            this.data[key] = newVal;  //數(shù)據(jù)重新賦值
            
            subs.forEach(function () {
                // 通知subs里面的所有的訂閱者
            })
        }
    });
}

那么問(wèn)題又來(lái)了,怎么把綁定數(shù)據(jù)的所有回調(diào)函數(shù)放到一個(gè)數(shù)組里面呢?

我們可以在getter里面做做手腳,我們知道只要訪問(wèn)數(shù)據(jù)就會(huì)觸發(fā)對(duì)應(yīng)數(shù)據(jù)的getter,那我們可以先設(shè)置一個(gè)全局變量target,如果我們要在data里面title屬性添加一個(gè)訂閱者(changeTitle函數(shù)),我們可以先設(shè)置target = changeTitle,把changeTitle函數(shù)緩存在target中,然后訪問(wèn)this.title去觸發(fā)title的getter,在getter里面把target這個(gè)全局變量的值添加到subs數(shù)組里面,添加完成后再把全局變量target設(shè)置為null,以便添加其他訂閱者。實(shí)例代碼如下:

Object.keys(this.data).forEach(function(key) {
    var subs = [];  // 在這里放置添加所有訂閱者的數(shù)組
    Object.defineProperty(this.data, key, {    // this.data.title
        enumerable: false,
        configurable: true,
        get: function getter () {
            console.log("訪問(wèn)數(shù)據(jù)啦啦啦")
            if (target) {
                subs.push(target);                
            }
            return this.data[key];   //返回對(duì)應(yīng)數(shù)據(jù)的值
        },
        set: function setter (newVal) {
            if (newVal === this.data[key]) {   
                return;    // 如果數(shù)據(jù)沒(méi)有變動(dòng),函數(shù)結(jié)束,不執(zhí)行下面的代碼
            }
            this.data[key] = newVal;  //數(shù)據(jù)重新賦值
            
            subs.forEach(function () {
                // 通知subs里面的所有的訂閱者
            })
        }
    });
}

上面的代碼為了方便理解都是通過(guò)簡(jiǎn)化的,實(shí)際上我們把訂閱者寫成一個(gè)構(gòu)造函數(shù)watcher,在實(shí)例化訂閱者的時(shí)候去訪問(wèn)對(duì)應(yīng)的數(shù)據(jù),觸發(fā)相應(yīng)的getter,詳細(xì)的代碼可以閱讀DMQ的自己動(dòng)手實(shí)現(xiàn)MVVM

3. 模板解析

通過(guò)上面的兩個(gè)步驟我們已經(jīng)實(shí)現(xiàn)一旦數(shù)據(jù)變動(dòng),就會(huì)通知對(duì)應(yīng)綁定數(shù)據(jù)的訂閱者,接下來(lái)我們來(lái)簡(jiǎn)單介紹一個(gè)特殊的訂閱者,也就是視圖更新函數(shù),幾乎每個(gè)數(shù)據(jù)都會(huì)添加對(duì)應(yīng)的視圖更新函數(shù),所以我們就來(lái)簡(jiǎn)單了解一下視圖更新函數(shù)。

假如說(shuō)有下面這一段代碼,我們?cè)趺窗阉馕龀蓪?duì)應(yīng)的html呢?


{{title}}

先簡(jiǎn)單介紹視圖更新函數(shù)的用途,
比如解析指令v-model="title",v-on:click="changeTitle",還有把{{title}}替換為對(duì)應(yīng)的數(shù)據(jù)等。

回到上面那個(gè)問(wèn)題,如何解析模板?我們只要去遍歷所有dom節(jié)點(diǎn)包括其子節(jié)點(diǎn),

如果節(jié)點(diǎn)屬性含有v-model,視圖更新函數(shù)就為把input的value設(shè)置為title的值

如果節(jié)點(diǎn)為文本節(jié)點(diǎn),視圖更新函數(shù)就為先用正則表達(dá)式取出大括號(hào)里面的值"title",再設(shè)置文本節(jié)點(diǎn)的值為data["title"]

如果節(jié)點(diǎn)屬性含有v-on:xxxx,視圖更新函數(shù)就為先用正則獲取事件類型為click,然后獲取該屬性的值為changeTitle,則事件的回調(diào)函數(shù)為this.methods["changeTitle"],接著用addEventListener監(jiān)聽(tīng)節(jié)點(diǎn)click事件。

我們要知道視圖更新函數(shù)也是data對(duì)應(yīng)屬性的訂閱者,如果不知道如何觸發(fā)視圖更新函數(shù),可以把上面的發(fā)布-訂閱模式再看一遍。

可能有的小伙伴可能還有個(gè)疑問(wèn),如何實(shí)現(xiàn)input節(jié)點(diǎn)的值變化后,下面的h1節(jié)點(diǎn)的title值也發(fā)生變化?在遍歷所有節(jié)點(diǎn)后,如果節(jié)點(diǎn)含有屬性v-model,就用addEventListener監(jiān)聽(tīng)input事件,一旦觸發(fā)input事件,改變data["title"]的值,就會(huì)觸發(fā)title的setter,從而通知所有的訂閱者。

監(jiān)聽(tīng)數(shù)組變化 無(wú)法監(jiān)控每個(gè)數(shù)組元素

如果讓我們自己實(shí)現(xiàn)監(jiān)聽(tīng)數(shù)組的變化,我們可能會(huì)想到用object.defineProperty去遍歷數(shù)組每個(gè)元素并設(shè)置setter,但是vue源碼里面卻不是這樣寫的,因?yàn)閷?duì)每一個(gè)數(shù)組元素defineProperty帶來(lái)代碼本身的復(fù)雜度增加和代碼執(zhí)行效率的降低。

感謝Ma63d這篇文章下面的的評(píng)論,對(duì)此解釋得很詳細(xì),這里也就不再贅述。

變異數(shù)組方法

既然無(wú)法通過(guò)defineProperty監(jiān)控?cái)?shù)組的每個(gè)元素,我們可以重寫數(shù)組的方法(push, pop, shift, unshift, splice, sort, reverse)來(lái)改變數(shù)組。

vue文檔中是這樣寫的:

Vue 包含一組觀察數(shù)組的變異方法,所以它們也將會(huì)觸發(fā)視圖更新。這些方法如下:

push()

pop()

shift()

unshift()

splice()

sort()

reverse()

下面是 vue早期源碼學(xué)習(xí)系列之二:如何監(jiān)聽(tīng)一個(gè)數(shù)組的變化 中的實(shí)例代碼

const aryMethods = ["push", "pop", "shift", "unshift", "splice", "sort", "reverse"];
const arrayAugmentations = [];

aryMethods.forEach((method)=> {

    // 這里是原生Array的原型方法
    let original = Array.prototype[method];

   // 將push, pop等封裝好的方法定義在對(duì)象arrayAugmentations的屬性上
   // 注意:是屬性而非原型屬性
    arrayAugmentations[method] = function () {
        console.log("我被改變啦!");

        // 調(diào)用對(duì)應(yīng)的原生方法并返回結(jié)果
        return original.apply(this, arguments);
    };

});

let list = ["a", "b", "c"];
// 將我們要監(jiān)聽(tīng)的數(shù)組的原型指針指向上面定義的空數(shù)組對(duì)象
// 別忘了這個(gè)空數(shù)組的屬性上定義了我們封裝好的push等方法
list.__proto__ = arrayAugmentations;
list.push("d");  // 我被改變啦! 4

// 這里的list2沒(méi)有被重新定義原型指針,所以就正常輸出
let list2 = ["a", "b", "c"];
list2.push("d");  // 4

對(duì)__proto__不熟悉的小伙伴可以去看一下王福明的博客,寫的很好。

變異數(shù)組方法的缺陷

vue文檔中變異數(shù)組方法的缺陷

由于 JavaScript 的限制, Vue 不能檢測(cè)以下變動(dòng)的數(shù)組:

當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如: vm.items[indexOfItem] = newValue

當(dāng)你修改數(shù)組的長(zhǎng)度時(shí),例如: vm.items.length = newLength

同時(shí)文檔中也介紹了如何解決上面這兩個(gè)問(wèn)題。

最后

以上是自己對(duì)vue一些基本原理的理解,當(dāng)然還有很多不足的地方,歡迎指正。本來(lái)自己也是為了應(yīng)付面試才去學(xué)習(xí)vue框架的基本原理,但是簡(jiǎn)單學(xué)習(xí)了這些vue基本的原理后,讓我明白通過(guò)深入學(xué)習(xí)框架原理,可以有效避開(kāi)一些自己以后會(huì)遇到的坑,所以,有時(shí)間的話自己以后還是會(huì)去看看框架的基本原理。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/84621.html

相關(guān)文章

  • todo-list 項(xiàng)目問(wèn)題總結(jié)(使 react 進(jìn)行開(kāi)發(fā))

    摘要:項(xiàng)目問(wèn)題總結(jié)這個(gè)項(xiàng)目,很簡(jiǎn)單,前端使用,后端使用進(jìn)行開(kāi)發(fā)。方便移動(dòng)端開(kāi)發(fā)。當(dāng)動(dòng)畫(huà)結(jié)束后,有一個(gè)鉤子函數(shù)可以使用其他一些功能組件,都是自己嘗試去編寫的,像日歷組件組件組件等。版本的,是沒(méi)有任何的鉤子函數(shù),我就感覺(jué)懵逼了。。。 todo-list 項(xiàng)目問(wèn)題總結(jié) 這個(gè) todo-list 項(xiàng)目,很簡(jiǎn)單,前端使用 react,后端 nodejs 使用 koa2 進(jìn)行開(kāi)發(fā)。數(shù)據(jù)庫(kù)使用 Mysql...

    shengguo 評(píng)論0 收藏0
  • Vue搭建一個(gè)應(yīng)盒子(一):todo-list

    摘要:最近在研究的相關(guān)知識(shí),最好的學(xué)習(xí)方法莫過(guò)于自己開(kāi)發(fā)一個(gè),這樣帶著問(wèn)題來(lái)學(xué)習(xí),進(jìn)步自然飛速。在首頁(yè)里,我們會(huì)用寫一個(gè)導(dǎo)航,通過(guò)的路由導(dǎo)航到不同的應(yīng)用。我們?cè)谖募A里創(chuàng)建一個(gè)新的組件。 最近在研究vue的相關(guān)知識(shí),最好的學(xué)習(xí)方法莫過(guò)于自己開(kāi)發(fā)一個(gè)SPA,這樣帶著問(wèn)題來(lái)學(xué)習(xí),進(jìn)步自然飛速。于是邊查邊寫差不多花了2周寫完了一個(gè)todo-list,功能不夠完備,但是麻雀雖小,卻也是五臟俱全,基本...

    MAX_zuo 評(píng)論0 收藏0
  • JavaScript從初級(jí)往高級(jí)走系列————MVVM-Vue

    摘要:原文博客地址如何理解如何實(shí)現(xiàn)是否解讀過(guò)的源碼與框架的區(qū)別實(shí)現(xiàn)實(shí)現(xiàn)獨(dú)立初始化實(shí)例兩者的區(qū)別數(shù)據(jù)和視圖的分離,解耦開(kāi)放封閉原則,對(duì)擴(kuò)展開(kāi)放,對(duì)修改封閉在中在代碼中操作視圖和數(shù)據(jù),混在一塊了以數(shù)據(jù)驅(qū)動(dòng)視圖,只關(guān)心數(shù)據(jù)變化, 原文博客地址:https://finget.github.io/2018/05/31/mvvm-vue/ MVVM 如何理解 MVVM 如何實(shí)現(xiàn) MVVM 是否解讀過(guò) ...

    codercao 評(píng)論0 收藏0
  • 讓React應(yīng)“動(dòng)”起來(lái)

    摘要:因?yàn)槠浣M件只是根據(jù)提供的及屬性,生成動(dòng)畫(huà)的數(shù)據(jù),業(yè)務(wù)應(yīng)用中拿到生成的數(shù)據(jù)后根據(jù)需要添加需要?jiǎng)赢?huà)的組件樣式。除了上述簡(jiǎn)單的動(dòng)畫(huà)應(yīng)用,在復(fù)雜動(dòng)畫(huà)的實(shí)現(xiàn)方面,表現(xiàn)非常優(yōu)越。 WEB應(yīng)用中動(dòng)畫(huà)很重要 不管是web應(yīng)用還是原生應(yīng)用,也不論是PC端應(yīng)用還是移動(dòng)端應(yīng)用,動(dòng)畫(huà)都扮演了一個(gè)重要的角色。 盡管動(dòng)畫(huà)并不會(huì)添加應(yīng)用的實(shí)際動(dòng)能,但一個(gè)好的動(dòng)畫(huà),一個(gè)流暢且優(yōu)雅,選擇在恰當(dāng)時(shí)機(jī)出現(xiàn)的動(dòng)畫(huà),能為應(yīng)用增...

    xiyang 評(píng)論0 收藏0
  • 2017-08-04 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選譯測(cè)試版本漫談前端體系建設(shè)輕松理解框架的基本原理,簡(jiǎn)單實(shí)現(xiàn)一個(gè)關(guān)鍵請(qǐng)求為什么是而不是的中文譯擴(kuò)展知乎專欄譯白話掘金調(diào)查報(bào)告眾成翻譯的平凡之路學(xué)習(xí)人氣眼中的效果中掘金與阻止元素被選中及清除選中的方法總結(jié)風(fēng) 2017-08-04 前端日?qǐng)?bào) 精選 【譯】React 16 測(cè)試版本漫談前端體系建設(shè)輕松理解vue框架的基本原理,簡(jiǎn)單實(shí)現(xiàn)一個(gè)todo-list關(guān)鍵請(qǐng)求為什么是displ...

    keelii 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<