成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

mochixuan / 3092人閱讀

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

vue實例 初始化 完成以后,接下來就要進行 掛載。

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

原型方法 - $mount

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

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

生成render函數(shù);

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

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

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

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

        ...
        
        // this->Vue實例,或者是組件實例對象
        var options = this.$options;
        
        // 解析模板,將模板轉(zhuǎn)換為render渲染函數(shù)
        if(!options.render) {
            // 一般是組件實例的構(gòu)造函數(shù)的options中會直接有template這個屬性
            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é)點的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實例對象的配置項options中
                options.render = render;
                // 將靜態(tài)渲染函數(shù)添加到Vue實例對象的配置項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實例
    function mountComponent(vm, el, hydrating) {
        vm.$el = el;
        
        ...
        
        updateComponent = function() {
            vm._update(vm._render(), hydrating);
        };

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

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

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

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

watcher

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

 // vm => 當前監(jiān)聽者對應(yīng)的vue實例
 // expOfFn => 需要監(jiān)聽的表達式
 // cb => 監(jiān)聽回調(diào)方法
 // options => 選項,比如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對象實例
        this.deps = [];
        this.newDeps = [];
        // 存儲監(jiān)聽器已經(jīng)訂閱的Dep對象實例的id,防止重復(fù)訂閱。
        // 每一個Dep對象實例都有一個ID
        this.depIds = new _Set();
        this.newDepIds = new _Set();
        
        // 監(jiān)聽器監(jiān)聽的表達式
        this.expression = expOrFn.toString();
        // 初始化getter,getter用于收集依賴關(guān)系
        if(typeof expOrFn === "function") {
            // expOfFn 為 函數(shù)
            // 對應(yīng):給vue實例建立watcher
            this.getter = expOrFn;
        } else {
            // epOfFn 為 字符串
            // 對應(yīng):在vue實例中建立監(jiān)聽
            // 比如 vm.$watch("message", function() {...})
            this.getter = parsePath(expOrFn);
        }

        this.value = this.lazy
            ? undefined
            : this.get();
    };
    
    // 執(zhí)行watcher的getter方法,用于收集響應(yīng)式屬性dep對象 和 watcher的依賴關(guān)系
    // 在vue實例掛載過程中, getter = updateComponent
    Watcher.prototype.get = function get() {
        // 將Dep.target設(shè)置為當前Watcher對象實例
        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實例時,watcher對象會在構(gòu)建過程中會執(zhí)行 updateComponent 方法。

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

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

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

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

render

? render 方法是 vue實例 在掛載時由 template 編譯成的一個 渲染函數(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é)點對應(yīng)的VNode // _c, 生成"div"元素節(jié)點對應(yīng)的Vnode

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

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

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

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

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

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

總結(jié)

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

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/101402.html

相關(guān)文章

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

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

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

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

    AbnerMing 評論0 收藏0
  • JS核心知識點梳理——原型、繼承(下)

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

    joyqi 評論0 收藏0
  • JavaScript - 收藏集 - 掘金

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

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

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

    laznrbfe 評論0 收藏0

發(fā)表評論

0條評論

mochixuan

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<