摘要:但沒辦法,還是得繼續(xù)。因為這邊返回的是一個,所以會執(zhí)行如下代碼然后回到剛才的里面,,額,好吧。。。
這段時間折騰了一個vue的日期選擇的組件,為了達(dá)成我一貫的使用舒服優(yōu)先原則,我決定使用directive來實現(xiàn),但是通過這個實現(xiàn)有一個難點就是我如何把時間選擇的組件插入到dom中,所以問題來了,我是不是又要看Vue的源碼?
vue2.0即將到來,改了一大堆,F(xiàn)ragment沒了,所以vue社區(qū)中為數(shù)不多的組件又有一批不能在2.0中使用,vue的官方插件也是毀得只剩vuex兼容,所以在我正在折騰我的組件的時候看到這個消息我是崩潰的。。。但沒辦法,還是得繼續(xù)。希望2.0出來之后官方能完善一下文檔,1.0中太多東西根本沒在文檔里提到,比如Fragment,比如Vue的util方法,這給第三方組件以及插件開發(fā)者帶來了無數(shù)的瑪法,你只能去看源碼了,費時費力,剛研究透又來個大更新,我真的想哭/(ㄒoㄒ)/~~
----------回歸正題--------
Vue Classvue的核心就是他的Vue class,component到最終其實也就是一個Vue的實例,包含了一些component獨有的屬性而已,我們來看看這個Class做了什么:
function Vue (options) { this._init(options) }
恩,他調(diào)用了_init,而在_init里面就是初始化了一大堆屬性,這些不重要,最重要的是最下面他有這么一句代碼:
if (options.el) { this.$mount(options.el) }
這個el是我們在調(diào)用new Vue({...})時傳入的,即這個vue對象的掛載點,好了,我們找到辦法去動態(tài)得把一個Vue的實例掛載到dom里面了,于是就有了如下代碼:
const vm = new Vue({ template: "我是天才", data: { hehe: "haha" } }) vm.$mount(document.body)
愉快得打開頁面,等等,為什么整個頁面上就剩下我是天才這句非常正確的話呢?哦~原來$mount默認(rèn)是替換整個整個元素的,呵呵噠
那么我們要如何把節(jié)點插入到body里面呢?這里有很多辦法,比如你直接調(diào)用$mount()不傳任何參數(shù),這個時候他不會執(zhí)行插入操作,然后你把他編譯過的節(jié)點(也就是vm.$el)拿出來手動通過dom操作來進(jìn)行插入,當(dāng)然我們肯定不能用這么low的方法O(∩_∩)O~,繼續(xù)擼源碼,很快我們找到了這么一個文件:
// instance/api/dom.js Vue.prototype.$appendTo = function(target, cb, withTransition) {...} Vue.prototype.$before = function(target, cb, withTransition) {...}
是的,Vue的實例自帶一些dom操作的幫助,那么我們隨便選一個用就是了,不細(xì)說
然而我們還是遇到了問題使用這種方式動態(tài)插入的節(jié)點會有一個問題,那就是$el并不是我們真正想要的節(jié)點,而是一個注釋節(jié)點,這是為啥?還是看源碼,我們跟著$mount進(jìn)去看看他做了什么:
Vue.prototype.$mount = function (el) { if (this._isCompiled) { process.env.NODE_ENV !== "production" && warn( "$mount() should be called only once." ) return } el = query(el) if (!el) { el = document.createElement("div") } this._compile(el) this._initDOMHooks() if (inDoc(this.$el)) { this._callHook("attached") ready.call(this) } else { this.$once("hook:attached", ready) } return this }
顯然我們的el是沒有的,那么這里的el就變成了一個div,然后進(jìn)行了_compile,再繼續(xù):
// 源碼太長不貼了 // 文件位置:instance/internal/lifecycle.js
這里面他做了一個el = transclude(el, options),以及this._initElement(el),我們重點看一下this._initElement(el):
Vue.prototype._initElement = function (el) { if (el instanceof DocumentFragment) { this._isFragment = true this.$el = this._fragmentStart = el.firstChild this._fragmentEnd = el.lastChild // set persisted text anchors to empty if (this._fragmentStart.nodeType === 3) { this._fragmentStart.data = this._fragmentEnd.data = "" } this._fragment = el } else { this.$el = el } this.$el.__vue__ = this this._callHook("beforeCompile") }
我們發(fā)現(xiàn)這里的el以及不是之前我們可親的div了,那么他是什么呢?我們倒回去看transclude:
... if (options) { if (options._asComponent && !options.template) { options.template = "" } if (options.template) { options._content = extractContent(el) el = transcludeTemplate(el, options) } } ...
我們是有template的,所以執(zhí)行了transcludeTemplate:
function transcludeTemplate (el, options) { var template = options.template var frag = parseTemplate(template, true) if (frag) { var replacer = frag.firstChild var tag = replacer.tagName && replacer.tagName.toLowerCase() if (options.replace) { /* istanbul ignore if */ if (el === document.body) { process.env.NODE_ENV !== "production" && warn( "You are mounting an instance with a template to " + ". This will replace entirely. You " + "should probably use `replace: false` here." ) } // there are many cases where the instance must // become a fragment instance: basically anything that // can create more than 1 root nodes. if ( // multi-children template frag.childNodes.length > 1 || // non-element template replacer.nodeType !== 1 || // single nested component tag === "component" || resolveAsset(options, "components", tag) || hasBindAttr(replacer, "is") || // element directive resolveAsset(options, "elementDirectives", tag) || // for block replacer.hasAttribute("v-for") || // if block replacer.hasAttribute("v-if") ) { return frag } else { options._replacerAttrs = extractAttrs(replacer) mergeAttrs(el, replacer) return replacer } } else { el.appendChild(frag) return el } } else { process.env.NODE_ENV !== "production" && warn( "Invalid template option: " + template ) } }
這邊生成了一個Fragment,好吧,我們最終還是回到了這里。。。因為這邊返回的是一個Fragment,所以會執(zhí)行如下代碼:
if (el instanceof DocumentFragment) { // anchors for fragment instance // passing in `persist: true` to avoid them being // discarded by IE during template cloning prepend(createAnchor("v-start", true), el) el.appendChild(createAnchor("v-end", true)) }
然后回到剛才的_initElement里面,this.$el = this._fragmentStart = el.firstChild,額,好吧。。。我表示無力吐槽
那么回到我們剛才的問題,想要讓$el正確,只需要在new Vue({...})的時候傳入replace: false就行了,但是外面就多包了一層div,怎么樣都不覺得完美
到這里我們基本了解了初始化一個Vue對象時的一些方法的執(zhí)行順序,以及一個組件如何從字符串模板最終到一個節(jié)點的過程,講得比較粗糙,建議有興趣的各位還是自行去看源代碼吧~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/79365.html
摘要:筆者系貢獻(xiàn)者之一官方說明簡單來說就是將文件變成,然后放入瀏覽器運行。部分首先分析部分從做右到左,也就是被先后被和處理過了。源碼解析之二源碼解析之三寫作中源碼解析之四寫作中作者博客作者微博 筆者系 vue-loader 貢獻(xiàn)者(#16)之一 官方說明 vue-loader is a loader for Webpack that can transform Vue components ...
摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實現(xiàn)文件分片斷點續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。插....
摘要:分享前啰嗦我之前介紹過如何實現(xiàn)和。我們采用用最精簡的代碼,還原響應(yīng)式架構(gòu)實現(xiàn)以前寫的那篇源碼分析之如何實現(xiàn)和可以作為本次分享的參考。到現(xiàn)在為止,我們再看那張圖是不是就清楚很多了總結(jié)我非常喜歡,以上代碼為了好展示,都采用最簡單的方式呈現(xiàn)。 分享前啰嗦 我之前介紹過vue1.0如何實現(xiàn)observer和watcher。本想繼續(xù)寫下去,可是vue2.0橫空出世..所以 直接看vue2.0吧...
摘要:執(zhí)行當(dāng)時傳入的回調(diào),并將新值與舊值一并傳入。文章鏈接源碼分析系列源碼分析系列之環(huán)境搭建源碼分析系列之入口文件分析源碼分析系列之響應(yīng)式數(shù)據(jù)一源碼分析系列之響應(yīng)式數(shù)據(jù)二源碼分析系列之響應(yīng)式數(shù)據(jù)三 前言 上一節(jié)著重講述了initComputed中的代碼,以及數(shù)據(jù)是如何從computed中到視圖層的,以及data修改后如何作用于computed。這一節(jié)主要記錄initWatcher中的內(nèi)容。 ...
閱讀 3209·2021-11-23 09:51
閱讀 3669·2021-09-22 15:35
閱讀 3646·2021-09-22 10:02
閱讀 2956·2021-08-30 09:49
閱讀 509·2021-08-05 10:01
閱讀 3376·2019-08-30 15:54
閱讀 1633·2019-08-30 15:53
閱讀 3558·2019-08-29 16:27