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

資訊專(zhuān)欄INFORMATION COLUMN

vue 源碼學(xué)習(xí)(二) 實(shí)例初始化和掛載過(guò)程

時(shí)飛 / 2696人閱讀

摘要:最后判斷有無(wú)根節(jié)點(diǎn),無(wú)則表示首次掛載,添加鉤子函數(shù),返回總結(jié)實(shí)例初始化掛載方法屬性初始化掛載過(guò)程在版本,生成函數(shù)對(duì)作處理,執(zhí)行中定義了通過(guò)實(shí)例化的回調(diào)執(zhí)行執(zhí)行,即調(diào)用了真實(shí)渲染成對(duì)象。

vue 入口

從vue的構(gòu)建過(guò)程可以知道,web環(huán)境下,入口文件在 src/platforms/web/entry-runtime-with-compiler.js(以Runtime + Compiler模式構(gòu)建,vue直接運(yùn)行在瀏覽器進(jìn)行編譯工作)

import Vue from "./runtime/index"

下一步,找到./runtime/index,發(fā)現(xiàn):

import Vue from "core/index"

下一步,找到core/index,發(fā)現(xiàn):

import Vue from "./instance/index"

按照這個(gè)思路找,最后發(fā)現(xiàn):Vue是在"core/index"下定義的

import { initMixin } from "./init"
import { stateMixin } from "./state"
import { renderMixin } from "./render"
import { eventsMixin } from "./events"
import { lifecycleMixin } from "./lifecycle"
import { warn } from "../util/index"

function Vue (options) {
  if (process.env.NODE_ENV !== "production" &&
    !(this instanceof Vue)
  ) {
    warn("Vue is a constructor and should be called with the `new` keyword")
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

引入方法,用function定義了Vue類(lèi),再以Vue為參數(shù),調(diào)用了5個(gè)方法,最后導(dǎo)出了vue

可以進(jìn)入這5個(gè)文件查看相關(guān)方法,主要就是在Vue原型上掛載方法,可以看到,Vue 是把這5個(gè)方法按功能放入不同的模塊中,這很利于代碼的維護(hù)和管理

initGlobalAPI

回到core/index.js, 看到除了引入已經(jīng)在原型上掛載方法后的 Vue 外,還導(dǎo)入initGlobalAPI 、 isServerRendering、FunctionalRenderContext,執(zhí)行initGlobalAPI(Vue),在vue.prototype上掛載$isServer、$ssrContext、FunctionalRenderContext,在vue 上掛載 version 屬性,

看到initGlobalAPI的定義,主要是往vue.config、vue.util等上掛載全局靜態(tài)屬性和靜態(tài)方法(可直接通過(guò)Vue調(diào)用,而不是實(shí)例調(diào)用),再把builtInComponents 內(nèi)置組件擴(kuò)展到Vue.options.components下。此處大致了解下它是做什么的即可,后面用到再做具體分析。

new Vue()

一般我們用vue都采用模板語(yǔ)法來(lái)聲明:

{{ message }}
var app = new Vue({
  el: "#app",
  data: {
    message: "Hello Vue!"
  }
})

當(dāng)new Vue()時(shí),vue做了哪些處理?

function Vue (options) {
  if (process.env.NODE_ENV !== "production" &&
    !(this instanceof Vue)
  ) {
    warn("Vue is a constructor and should be called with the `new` keyword")
  }
  this._init(options)
}

看到vue只能通過(guò)new實(shí)例化,否則報(bào)錯(cuò)。實(shí)例化vue后,執(zhí)行了this._init(),該方法在通過(guò)initMixin(Vue)掛載在Vue原型上的,找到定義文件core/instance/init.js 查看該方法。

_init()

一開(kāi)始在this對(duì)象上定義_uid、_isVue,判斷options._isComponent,此次先不考慮options._isComponenttrue的情況,走else,合并options,接著安裝proxy, 初始化生命周期,初始化事件、初始化渲染、初始化data、鉤子函數(shù)等,最后判斷有vm.$options.el則執(zhí)行vm.$mount(),即是把el渲染成最終的DOM。

初始化data 數(shù)據(jù)綁定

_init()中通過(guò)initState()來(lái)綁定數(shù)據(jù)到vm上,看下initState的定義:

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

獲取options,初始化propsmethods、data、計(jì)算屬性、watch綁定到vm上,先來(lái)看下initData()是如何把綁定data的:

先判斷data是不是function類(lèi)型,是則調(diào)用getData,返回data的自調(diào)用,不是則直接返回data,并將data賦值到vm._data

對(duì)data、props、methods,作個(gè)校驗(yàn),防止出現(xiàn)重復(fù)的key,因?yàn)樗鼈冏罱K都會(huì)掛載到vm上,都是通過(guò)vm.key來(lái)調(diào)用

通過(guò)proxy(vm, `_data`, key)把每個(gè)key都掛載在vm

export function proxy (target: Object, sourceKey: string, key: string) {
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key]
  }
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val
  }
  Object.defineProperty(target, key, sharedPropertyDefinition)
}
const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: noop,
  set: noop
}

proxy() 定義了一個(gè)get/set函數(shù),再通過(guò)Object.defineProperty定義修改屬性(不了解Object.defineProperty()的同學(xué)可以先看下文檔,通過(guò)Object.defineProperty()定義的屬性,通過(guò)描述符的設(shè)置可以進(jìn)行更精準(zhǔn)的控制對(duì)象屬性),將對(duì)target的key訪(fǎng)問(wèn)加了一層get/set,即當(dāng)訪(fǎng)問(wèn)vm.key時(shí),實(shí)際上是調(diào)用了sharedPropertyDefinition.get,返回this._data.key,這樣就實(shí)現(xiàn)了通過(guò)vm.key來(lái)調(diào)用vm._data上的屬性

最后,observe(data, true /* asRootData */) 觀(guān)察者,對(duì)數(shù)據(jù)作響應(yīng)式處理,這也是vue的核心之一,此處先不分析

$mount() 實(shí)例掛載

Vue的核心思想之一是數(shù)據(jù)驅(qū)動(dòng),在vue下,我們不會(huì)直接操作DOM,而是通過(guò)js修改數(shù)據(jù),所有邏輯只需要考慮對(duì)數(shù)據(jù)的修改,最后再把數(shù)據(jù)渲染成DOM。其中,$mount()就是負(fù)責(zé)把數(shù)據(jù)掛載到vm,再渲染成最終DOM。

接下來(lái)將會(huì)分析下 vue 是如何把javaScript對(duì)象渲染成dom元素的,和之前一樣,主要分析主線(xiàn)代碼

預(yù)處理

還是從src/platform/web/entry-runtime-with-compiler.js 文件入手,

const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && query(el)
  ···
}

首先將原先原型上的$mount方法緩存起來(lái),再重新定義$mount

先判斷 el ,el 不能是 body, html ,因?yàn)殇秩境鰜?lái)的 DOM 最后是會(huì)替換掉el

判斷render方法, 有的話(huà)直接調(diào)用mount.call(this, el, hydrating)

沒(méi)有render方法時(shí):

判斷有沒(méi)有template ,有則用compileToFunctions將其編譯成render方法

沒(méi)有template時(shí),則查看有沒(méi)有el,有轉(zhuǎn)換成template,再用compileToFunctions將其編譯成render方法

render掛載到options下

最后調(diào)用 mount.call(this, el, hydrating),即是調(diào)用原先原型上的mount方法

我們發(fā)現(xiàn)這一系列調(diào)用都是為了生成render函數(shù),說(shuō)明在vue中,所有的組件渲染最終都需要render方法(不管是單文件.vue還是el/template),vue 文檔里也提到:

Vue 選項(xiàng)中的 render 函數(shù)若存在,則 Vue 構(gòu)造函數(shù)不會(huì)從 template 選項(xiàng)或通過(guò) el 選項(xiàng)指定的掛載元素中提取出的 HTML 模板編譯渲染函數(shù)。
原先原型上的mount方法

找到原先原型上的mount方法,在src/platform/web/runtime/index.js中:

// public mount method
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && inBrowser ? query(el) : undefined
  return mountComponent(this, el, hydrating)
}

這個(gè)是公用的$mount方法,這么設(shè)計(jì)使得這個(gè)方法可以被 runtime onlyruntime+compiler 版本共同使用

$mount 第一個(gè)參數(shù)el, 表示掛載的元素,在瀏覽器環(huán)境會(huì)通過(guò)query(el)獲取到dom對(duì)象,第二個(gè)參數(shù)和服務(wù)端渲染相關(guān),不進(jìn)行深入分析,此處不傳。接著調(diào)用mountComponent()

看下query(),比較簡(jiǎn)單,當(dāng)el string時(shí),找到該選擇器返回dom對(duì)象,否則新創(chuàng)建個(gè)div dom對(duì)象,eldom對(duì)象直接返回el.

mountComponent

mountComponent定義在src/core/instance/lifecycle.js中,傳入vm,el,

el緩存在vm.$el

判斷有沒(méi)有render方法,沒(méi)有則直接把createEmptyVNode作為render函數(shù)

開(kāi)發(fā)環(huán)境警告(沒(méi)有Render但有el/template不能使用runtime-only版本、rendertemplate必須要有一個(gè))

掛載beforeMount鉤子

定義 updateComponent , 渲染相關(guān)

updateComponent = () => {
  vm._update(vm._render(), hydrating)
}

new Watcher() 實(shí)例化一個(gè)渲染watcher,簡(jiǎn)單看下定義,
this.getter = expOrFn
updateComponent掛載到this.getter
this.value = this.lazy ? undefined : this.get()

get () {
  pushTarget(this)
  let value
  const vm = this.vm
  try {
    value = this.getter.call(vm, vm)
  } catch (e) {...}
  return value
}

執(zhí)行this.get(),則執(zhí)行了this.getter,即updateComponent,所以new Watcher()時(shí)會(huì)執(zhí)行updateComponent,也就會(huì)執(zhí)行到vm._update、vm._render方法。

因?yàn)橹蟛恢钩跏蓟瘯r(shí)需要渲染頁(yè)面,數(shù)據(jù)發(fā)生變化時(shí)也是要更新到dom上的,實(shí)例watcher可以實(shí)現(xiàn)對(duì)數(shù)據(jù)進(jìn)行監(jiān)聽(tīng)以及隨后的更新dom處理,watcher會(huì)在初始化執(zhí)行回調(diào),也會(huì)在數(shù)據(jù)變化時(shí)執(zhí)行回調(diào),此處先簡(jiǎn)單介紹為什么要使用watcher,不深入分析watcher實(shí)現(xiàn)原理。

最后判斷有無(wú)根節(jié)點(diǎn),無(wú)則表示首次掛載,添加mounted鉤子函數(shù) ,返回vm

總結(jié)

實(shí)例初始化:new Vue()->掛載方法屬性->this._init->初始化data->$mount

掛載過(guò)程:(在complier版本,生成render函數(shù))對(duì)el作處理,執(zhí)行mountComponent,mountComponent中定義了updateComponent,通過(guò)實(shí)例化watcher的回調(diào)執(zhí)行updateComponent,執(zhí)行updateComponent,即調(diào)用了vm._update、vm._render真實(shí)渲染成dom對(duì)象。

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

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

相關(guān)文章

  • Vue源碼學(xué)習(xí))——從宏觀(guān)看Vue

    摘要:上一篇文章我們寫(xiě)到從入口文件一步步找到的構(gòu)造函數(shù),現(xiàn)在我們要去看看實(shí)例化經(jīng)歷的過(guò)程的構(gòu)造函數(shù)我們知道的構(gòu)造函數(shù)在中不明白的可以去看上一篇文章源碼學(xué)習(xí)筆記一。 上一篇文章我們寫(xiě)到從入口文件一步步找到Vue的構(gòu)造函數(shù),現(xiàn)在我們要去看看Vue實(shí)例化經(jīng)歷的過(guò)程 Vue的構(gòu)造函數(shù) 我們知道Vue的構(gòu)造函數(shù)在src/core/instance/index.js中,不明白的可以去看上一篇文章 Vue...

    AndroidTraveler 評(píng)論0 收藏0
  • Vue原理】Component - 源碼版 之 掛載組件DOM

    摘要:寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注源碼分享,文章分為白話(huà)版和源碼版,白話(huà)版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理源碼版之掛載組件由這篇文章從模 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話(huà)版和 源碼版,白話(huà)版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...

    lbool 評(píng)論0 收藏0
  • Vue原理】從模板到DOM的簡(jiǎn)要流程

    摘要:寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注源碼分享,文章分為白話(huà)版和源碼版,白話(huà)版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理從模板到的簡(jiǎn)要流程今天的計(jì)劃是, 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話(huà)版和 源碼版,白話(huà)版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基...

    wenzi 評(píng)論0 收藏0
  • vue源碼閱讀之?dāng)?shù)據(jù)渲染過(guò)程

    摘要:圖在中應(yīng)用三數(shù)據(jù)渲染過(guò)程數(shù)據(jù)綁定實(shí)現(xiàn)邏輯本節(jié)正式分析從到數(shù)據(jù)渲染到頁(yè)面的過(guò)程,在中定義了一個(gè)的構(gòu)造函數(shù)。一、概述 vue已是目前國(guó)內(nèi)前端web端三分天下之一,也是工作中主要技術(shù)棧之一。在日常使用中知其然也好奇著所以然,因此嘗試閱讀vue源碼并進(jìn)行總結(jié)。本文旨在梳理初始化頁(yè)面時(shí)data中的數(shù)據(jù)是如何渲染到頁(yè)面上的。本文將帶著這個(gè)疑問(wèn)一點(diǎn)點(diǎn)追究vue的思路??傮w來(lái)說(shuō)vue模版渲染大致流程如圖1所...

    AlphaGooo 評(píng)論0 收藏0
  • Vue源碼學(xué)習(xí)vue實(shí)例化到掛載到dom(上)

    摘要:作者王聰本篇目的是介紹實(shí)例化到掛載到的整體路線(xiàn),一些細(xì)節(jié)會(huì)被省略。從源碼中找到構(gòu)造函數(shù)的聲明,是一個(gè)很簡(jiǎn)潔的工廠(chǎng)模式聲明的一個(gè)構(gòu)造函數(shù)。內(nèi)部做了邏輯判斷構(gòu)造函數(shù)調(diào)用必須有關(guān)鍵字。代表的是當(dāng)前實(shí)例也就是構(gòu)造函數(shù)被調(diào)用后的指向。 作者:王聰本篇目的是介紹vue實(shí)例化到掛載到dom的整體路線(xiàn),一些細(xì)節(jié)會(huì)被省略。 從new Vue()開(kāi)始 所有的一切都是從 new Vue()開(kāi)始的,所以從這個(gè)...

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

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

0條評(píng)論

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