成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

vue - 響應(yīng)式原理梳理(二)

mochixuan / 3136人閱讀

摘要:原型方法通過原型方法方法來掛載實(shí)例。當(dāng)響應(yīng)式屬性發(fā)生變化時(shí),會(huì)通知依賴列表中的對(duì)象進(jìn)行更新。此時(shí),對(duì)象執(zhí)行方法,重新渲染節(jié)點(diǎn)。在執(zhí)行過程中,如果需要讀取響應(yīng)式屬性,則會(huì)觸發(fā)響應(yīng)式屬性的??偨Y(jié)響應(yīng)式屬性的原理

vue實(shí)例 初始化 完成以后,接下來就要進(jìn)行 掛載

vue實(shí)例掛載,即為將vue實(shí)例對(duì)應(yīng)的 template模板,渲染成 Dom節(jié)點(diǎn)。

原型方法 - $mount

? 通過原型方法 $mount方法 來掛載vue實(shí)例。

? 掛載vue實(shí)例時(shí),經(jīng)歷一下幾個(gè)重要步驟:

生成render函數(shù);

生成vue實(shí)例的監(jiān)聽器watcher;

執(zhí)行render函數(shù),將vue實(shí)例的template模板轉(zhuǎn)化為VNode節(jié)點(diǎn)樹;

執(zhí)行update函數(shù),將VNode節(jié)點(diǎn)樹轉(zhuǎn)化為dom節(jié)點(diǎn)樹;

    // 掛載Vue實(shí)例
    Vue$3.prototype.$mount = function(el, hydrating) {
        // el為dom元素對(duì)應(yīng)的選擇器表達(dá)式,根據(jù)選擇器表達(dá)式,獲取dom元素
        el = el && query(el);

        ...
        
        // this->Vue實(shí)例,或者是組件實(shí)例對(duì)象
        var options = this.$options;
        
        // 解析模板,將模板轉(zhuǎn)換為render渲染函數(shù)
        if(!options.render) {
            // 一般是組件實(shí)例的構(gòu)造函數(shù)的options中會(huì)直接有template這個(gè)屬性
            var template = options.template;
            if(template) {
                if(typeof template === "string") {
                    if(template.charAt(0) === "#") {
                        template = idToTemplate(template);
                        /* istanbul ignore if */
                        if("development" !== "production" && !template) {
                            warn(
                                ("Template element not found or is empty: " + (options.template)),
                                this
                            );
                        }
                    }
                } else if(template.nodeType) {
                    template = template.innerHTML;
                } else {
                    {
                        warn("invalid template option:" + template, this);
                    }
                    return this
                }
            } else if(el) {
                // 獲取dom節(jié)點(diǎn)的outerHTML
                template = getOuterHTML(el);
            }
            // template,模板字符串
            if(template) {
                /* istanbul ignore if */
                if("development" !== "production" && config.performance && mark) {
                    mark("compile");
                }
                
                // 將html模板字符串編譯為渲染函數(shù)
                var ref = compileToFunctions(template, {
                    // 換行符
                    shouldDecodeNewlines : shouldDecodeNewlines,
                    // 分割符
                    delimiters : options.delimiters,
                    // 注釋
                    comments : options.comments
                }, this);
                // 獲取渲染函數(shù)
                var render = ref.render;
                // 獲取靜態(tài)渲染函數(shù)
                var staticRenderFns = ref.staticRenderFns;
                // 將渲染函數(shù)添加到Vue實(shí)例對(duì)象的配置項(xiàng)options中
                options.render = render;
                // 將靜態(tài)渲染函數(shù)添加到Vue實(shí)例對(duì)象的配置項(xiàng)options中
                options.staticRenderFns = staticRenderFns;

                /* istanbul ignore if */
                if("development" !== "production" && config.performance && mark) {
                    mark("compile end");
                    measure(((this._name) + " compile"), "compile", "compile end");
                }
            }
        }
        return mountComponent.call(this, el, hydrating)
    };
    
    
    // 掛載vue實(shí)例
    function mountComponent(vm, el, hydrating) {
        vm.$el = el;
        
        ...
        
        updateComponent = function() {
            vm._update(vm._render(), hydrating);
        };

        // 給Vue實(shí)例或者是組件實(shí)例創(chuàng)建一個(gè)監(jiān)聽器, 監(jiān)聽updateComponent方法
        vm._watcher = new Watcher(vm, updateComponent, noop);
        
        ...
        
        return vm;
    }

? watcher 對(duì)象在構(gòu)建過程中,會(huì)作為觀察者模式中的 Observer,會(huì)被添加到 響應(yīng)式屬性的dep對(duì)象的依賴列表 中。

? 當(dāng)響應(yīng)式屬性發(fā)生變化時(shí),會(huì)通知依賴列表中的watcher對(duì)象進(jìn)行更新。

? 此時(shí),watcher 對(duì)象執(zhí)行 updateComponent 方法,重新渲染 dom節(jié)點(diǎn)。

watcher

? 在 掛載vue實(shí)例 時(shí), 會(huì)為 vue實(shí)例 構(gòu)建一個(gè) 監(jiān)聽者watcher。

 // vm => 當(dāng)前監(jiān)聽者對(duì)應(yīng)的vue實(shí)例
 // expOfFn => 需要監(jiān)聽的表達(dá)式
 // cb => 監(jiān)聽回調(diào)方法
 // options => 選項(xiàng),比如deep、immediate
 // vm.$watch("message", function(newValue) {...})
 
 var Watcher = function Watcher(vm, expOrFn, cb,  options) {
        this.vm = vm;

        vm._watchers.push(this);
        
        ...
        
        // 監(jiān)聽器訂閱的Dep對(duì)象實(shí)例
        this.deps = [];
        this.newDeps = [];
        // 存儲(chǔ)監(jiān)聽器已經(jīng)訂閱的Dep對(duì)象實(shí)例的id,防止重復(fù)訂閱。
        // 每一個(gè)Dep對(duì)象實(shí)例都有一個(gè)ID
        this.depIds = new _Set();
        this.newDepIds = new _Set();
        
        // 監(jiān)聽器監(jiān)聽的表達(dá)式
        this.expression = expOrFn.toString();
        // 初始化getter,getter用于收集依賴關(guān)系
        if(typeof expOrFn === "function") {
            // expOfFn 為 函數(shù)
            // 對(duì)應(yīng):給vue實(shí)例建立watcher
            this.getter = expOrFn;
        } else {
            // epOfFn 為 字符串
            // 對(duì)應(yīng):在vue實(shí)例中建立監(jiān)聽
            // 比如 vm.$watch("message", function() {...})
            this.getter = parsePath(expOrFn);
        }

        this.value = this.lazy
            ? undefined
            : this.get();
    };
    
    // 執(zhí)行watcher的getter方法,用于收集響應(yīng)式屬性dep對(duì)象 和 watcher的依賴關(guān)系
    // 在vue實(shí)例掛載過程中, getter = updateComponent
    Watcher.prototype.get = function get() {
        // 將Dep.target設(shè)置為當(dāng)前Watcher對(duì)象實(shí)例
        pushTarget(this);
        var value;
        var vm = this.vm;
        
        ...
        
        value = this.getter.call(vm, vm);
        
        ...
        
        return value
    };
    
    // watcher 更新
    Watcher.prototype.update = function update() {
        ...
        
        this.get()
        
        ...
    };
    
    // 將watcher添加到dep屬性的依賴列表中
    Watcher.prototype.addDep = function addDep(dep) {
        var id = dep.id;
        if(!this.newDepIds.has(id)) {
            this.newDepIds.add(id);
            this.newDeps.push(dep);
            if(!this.depIds.has(id)) {
                dep.addSub(this);
            }
        }
    };
    

? 在掛載vue實(shí)例時(shí),watcher對(duì)象會(huì)在構(gòu)建過程中會(huì)執(zhí)行 updateComponent 方法。

? 執(zhí)行 updateComponent 方法分為兩個(gè)過程:

執(zhí)行 render 方法,返回 VNode節(jié)點(diǎn)樹;

執(zhí)行 update 方法,將 VNode節(jié)點(diǎn)樹 渲染為 dom節(jié)點(diǎn)樹。

? 執(zhí)行 render 方法時(shí),會(huì)觸發(fā)響應(yīng)式屬性的 getter 方法,將 watcher 添加到 dep對(duì)象的依賴列表中。

render

? render 方法是 vue實(shí)例 在掛載時(shí)由 template 編譯成的一個(gè) 渲染函數(shù)

tempalte:
    
{{message}}
render: // 執(zhí)行render, 需要讀取響應(yīng)式屬性message,觸發(fā)message的getter方法 (function anonymous() { with(this){return _c("div",{attrs:{"id":"app"}},[_v(_s(message))])} }) // _s, 將this.message轉(zhuǎn)化為字符串 // _v, 生成文本節(jié)點(diǎn)對(duì)應(yīng)的VNode // _c, 生成"div"元素節(jié)點(diǎn)對(duì)應(yīng)的Vnode

? render 函數(shù)返回 VNode節(jié)點(diǎn) , 用于 渲染Dom節(jié)點(diǎn)。

? 在執(zhí)行過程中,如果需要讀取 響應(yīng)式屬性,則會(huì)觸發(fā) 響應(yīng)式屬性getter。

? 在 getter 方法中, 將 watcher 對(duì)象添加到 響應(yīng)式屬性dep對(duì)象的依賴列表 中。

修改響應(yīng)式屬性

? 修改 響應(yīng)式屬性時(shí),會(huì)觸發(fā)響應(yīng)式屬性的 setter 方法。此時(shí),響應(yīng)式屬性的 dep對(duì)象執(zhí)行 notify 方法,遍歷自己的 依賴列表subs, 逐個(gè)通知subs中的 watcher 去更新。

? watcher 對(duì)象執(zhí)行 update 方法,重新調(diào)用 render 方法生成 Vnode節(jié)點(diǎn)樹,然后 對(duì)比新舊Vnode節(jié)點(diǎn)樹 的不同,更新dom樹。

總結(jié)

? 響應(yīng)式屬性 的原理:

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

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

相關(guān)文章

  • vue - 響應(yīng)原理梳理(一)

    摘要:?jiǎn)栴}為什么修改即可觸發(fā)更新和的關(guān)聯(lián)關(guān)系官方介紹的官網(wǎng)文檔,對(duì)響應(yīng)式屬性的原理有一個(gè)介紹。因此本文在源碼層面,對(duì)響應(yīng)式原理進(jìn)行梳理,對(duì)關(guān)鍵步驟進(jìn)行解析。 描述 ?我們通過一個(gè)簡(jiǎn)單的 Vue應(yīng)用 來演示 Vue的響應(yīng)式屬性: html: {{message}} js: let vm = new Vue({ el: #ap...

    weknow619 評(píng)論0 收藏0
  • vue總結(jié)系列--數(shù)據(jù)驅(qū)動(dòng)和響應(yīng)

    摘要:由于是需要兼容的后臺(tái)系統(tǒng),該項(xiàng)目并不能使用到等技術(shù),因此我在上的經(jīng)驗(yàn)大都是使用原生的編寫的,可以看見一個(gè)組件分為兩部分視圖部分,和數(shù)據(jù)部分。 在公司里幫項(xiàng)目組里開發(fā)后臺(tái)系統(tǒng)的前端項(xiàng)目也有一段時(shí)間了。 vue這種數(shù)據(jù)驅(qū)動(dòng),組件化的框架和react很像,從一開始的快速上手基本的開發(fā),到后來開始自定義組件,對(duì)element UI的組件二次封裝以滿足項(xiàng)目需求,期間也是踩了不少坑。由于將來很長(zhǎng)一...

    AbnerMing 評(píng)論0 收藏0
  • JS核心知識(shí)點(diǎn)梳理——原型、繼承(下)

    摘要:引言上篇文章介紹原型,這篇文章接著講繼承,嘔心瀝血之作,大哥們點(diǎn)個(gè)贊呀明確一點(diǎn)并不是真正的面向?qū)ο笳Z(yǔ)言,沒有真正的類,所以我們也沒有類繼承實(shí)現(xiàn)繼承有且僅有兩種方式,和原型鏈在介紹繼承前我們先介紹下其他概念函數(shù)的三種角色一個(gè)函數(shù),有三種角色。 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 上篇文章介紹原型,...

    joyqi 評(píng)論0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實(shí)現(xiàn)文件分片斷點(diǎn)續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。插....

    izhuhaodev 評(píng)論0 收藏0
  • 淺談Vue中計(jì)算屬性computed的實(shí)現(xiàn)原理

    摘要:雖然計(jì)算屬性在大多數(shù)情況下更合適,但有時(shí)也需要一個(gè)自定義的偵聽器。當(dāng)某個(gè)屬性發(fā)生變化,觸發(fā)攔截函數(shù),然后調(diào)用自身消息訂閱器的方法,遍歷當(dāng)前中保存著所有訂閱者的數(shù)組,并逐個(gè)調(diào)用的方法,完成響應(yīng)更新。 雖然目前的技術(shù)棧已由Vue轉(zhuǎn)到了React,但從之前使用Vue開發(fā)的多個(gè)項(xiàng)目實(shí)際經(jīng)歷來看還是非常愉悅的,Vue文檔清晰規(guī)范,api設(shè)計(jì)簡(jiǎn)潔高效,對(duì)前端開發(fā)人員友好,上手快,甚至個(gè)人認(rèn)為在很多...

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

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

0條評(píng)論

mochixuan

|高級(jí)講師

TA的文章

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