Vue源碼解析:Vue是如何設(shè)計(jì)的册招?

組成與設(shè)計(jì).png

項(xiàng)目文件結(jié)構(gòu)

Vue項(xiàng)目中岔激,所有核心的代碼都是在src目錄下完成,為了更好的了解Vue的底層實(shí)現(xiàn)是掰,我們首先來了解一下src目錄下代碼的組織情況虑鼎,從全局入手,在腦海里留下簡單的印象,方便后續(xù)的學(xué)習(xí)炫彩。(注意:當(dāng)前使用Vue的版本為2.6.12匾七,不同版本的內(nèi)容可能會有所差異)

.
├── compiler  // 編譯模塊:將 template 編譯成為可以生成 vnode 的 render 函數(shù)
│   ├── codeframe.js
│   ├── codegen             // 代碼生成文件:根據(jù) ast 樹可生成 vnode 的 render代碼
│   ├── create-compiler.js  // 創(chuàng)建編譯器的工廠函數(shù)
│   ├── directives          // 指令解析:v-on, v-bind, v-model
│   ├── error-detector.js   
│   ├── helpers.js          // 編譯相關(guān)方法,如屬性獲取等方法
│   ├── index.js            // 入口文件
│   ├── optimizer.js        // 編譯優(yōu)化:將 ast 樹進(jìn)行優(yōu)化
│   ├── parser                      // html 解析文件:將 template 解析成 ast 樹??
│   └── to-function.js      // 創(chuàng)建編譯器的工廠函數(shù)
├── core     // 構(gòu)造函數(shù)核心模塊:構(gòu)建Vue構(gòu)造函數(shù)江兢,添加原型方法昨忆,實(shí)現(xiàn)完成渲染流程的_init方法
│   ├── components  // 自帶的全局組件,如 keep-alive
│   ├── config.js   // 配置相關(guān)
│   ├── global-api  // 全局api杉允,如 Vue.use, extend, mixin, component等方法
│   ├── index.js    // 入口文件邑贴,在 Vue 上掛載全局方法并導(dǎo)出 Vue
│   ├── instance    // 構(gòu)造函數(shù)起始位置
│   ├── observer    // 響應(yīng)式原理
│   ├── util        // 一些工具方法,包含 mergeOptions, nextTick 等方法的實(shí)現(xiàn)
│   └── vdom        // 虛擬 dom
├── platforms // 平臺相關(guān)夺颤,包含不同平臺的不同構(gòu)建入口痢缎,這里主要研究web端
│   ├── weex
│   └── web
│       ├── compiler   // 與平臺相關(guān)的編譯
│       ├── entry-compiler.js // vue-template-compiler 包的入口文件
│       ├── entry-runtime-with-compiler.js // 構(gòu)建入口,包含編譯器
│       ├── entry-runtime.js  // 構(gòu)建入口世澜,不包含編譯器独旷,不支持 template 轉(zhuǎn)換 render
│       ├── entry-server-basic-renderer.js
│       ├── entry-server-renderer.js
│       ├── runtime   // 與平臺相關(guān)的構(gòu)建
│       ├── server
│       └── util
│
├── server    // 服務(wù)端渲染相關(guān)
├── sfc       // 包含單文件組件(.vue文件)的解析邏輯,用于vue-template-compiler包
└── shared    // 代碼庫通用代碼
    ├── constants.js
    └── util.js

以上是Vue項(xiàng)目中主要文件目錄寥裂,里面附帶一些注釋嵌洼,講解了比較主要模塊的功能及作用。剛開始學(xué)習(xí)時(shí)只做簡單了解即可封恰,后面我們會逐步詳細(xì)學(xué)習(xí)其中的一些模塊麻养,從而從原理級別理解整個(gè)Vue項(xiàng)目的設(shè)計(jì)與實(shí)現(xiàn)。

Vue的真面目

要想真正的了解Vue是怎樣的诺舔,首先我們需要找到Vue是咋哪里被定義的鳖昌。我們先找到package.json文件下的scripts配置。scripts里存放的都是運(yùn)行命令的別名形式低飒,通過命令可以輕松找到對應(yīng)命令執(zhí)行文件的路徑许昨。

"scripts": {
    "dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"
 }

這里當(dāng)運(yùn)行dev命令實(shí)際上是運(yùn)行scripts/config.js文件,讓我們找到scripts/config.js文件褥赊。

通過運(yùn)行命令參數(shù)我們可以知道process.env.TARGET的值為web-full-dev糕档,因此可以在builds里找到對應(yīng)的配置文件,如下

const builds = {
  'web-full-dev': {
      entry: resolve('web/entry-runtime-with-compiler.js'),
      dest: resolve('dist/vue.js'),
      format: 'umd',
      env: 'development',
      alias: { he: './entity-decoder' },
      banner
   }
  ...
}

module.exports = genConfig(process.env.TARGET)

通過entry拌喉,我們找到web/entry-runtime-with-compiler.js文件:

import Vue from './runtime/index'

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

export default Vue

在這里速那,我們終于找到了Vue相關(guān)的文件,這也是Vue的起始入口尿背。接著根據(jù)Vue的引入路徑端仰,找到./runtime/index文件:

import Vue from 'core/index'
...
Vue.prototype.__patch__ = inBrowser ? patch : noop
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  ...
}
export default Vue

這里還不是Vue真正的起始點(diǎn),繼續(xù)查找core/index文件:

import Vue from './instance/index'
initGlobalAPI(Vue)
...
Vue.version = '__VERSION__'
export default Vue

發(fā)現(xiàn)仍然不是Vue的起始點(diǎn)田藐,繼續(xù)查找'./instance/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'

// Vue 構(gòu)造函數(shù)
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

好了榆俺,大功告成!費(fèi)勁千辛萬苦終于找到了Vue的真正定義的位置!可以看出Vue其實(shí)就是一個(gè)構(gòu)造函數(shù)茴晋,而構(gòu)造函數(shù)內(nèi)部僅僅只是調(diào)用了_init方法陪捷,看上去非常簡單。但是Vue是如何通過這么簡單的定義實(shí)現(xiàn)那么復(fù)雜的功能呢诺擅?這里就要涉及到構(gòu)造函數(shù)市袖、原型實(shí)例的概念了烁涌,不了解這些概念的建議參考《javascript高級設(shè)計(jì)程序》中原型章節(jié)來進(jìn)行學(xué)習(xí)苍碟。下面我們通過下方三個(gè)方面來介紹Vue的實(shí)現(xiàn)。

  1. 原型方法屬性:通過 5 個(gè) init 方法撮执,向Vue的原型上添加方法微峰,
  2. 靜態(tài)方法屬性:在導(dǎo)入Vue構(gòu)造函數(shù)的過程中,向Vue構(gòu)造函數(shù)上添加靜態(tài)方法抒钱,也有向原型上添加方法
  3. 實(shí)例化:在實(shí)例化的過程中蜓肆,執(zhí)行_init方法,完成整個(gè)Vue初始化到渲染的邏輯谋币。

Vue的原型方法(通過5個(gè)init方法添加)

initMixin

initMixin方法主要實(shí)現(xiàn)了_init方法仗扬。

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    // init 實(shí)現(xiàn)內(nèi)容,由于這里僅做概覽蕾额,所以具體實(shí)現(xiàn)均已省略
    ... 
  }
}

從上面Vue構(gòu)造函數(shù)我們可以知道早芭,這個(gè)方法在實(shí)例化時(shí)有被調(diào)用,它主要的作用是實(shí)現(xiàn):選項(xiàng)的合并诅蝶,數(shù)據(jù)初始化(如響應(yīng)式處理)退个,以及觸發(fā)編譯和渲染的流程,所以十分重要调炬。這里也只是先做一個(gè)了解帜乞,后續(xù)的實(shí)例化章節(jié)將都會從這個(gè)方法開始分析。

stateMixin

stateMixin主要實(shí)現(xiàn)了data,props的代理功能筐眷,即當(dāng)我們訪問$data時(shí),實(shí)際訪問的是_data习柠。另外在非生產(chǎn)環(huán)境下匀谣,會對$data,$props進(jìn)行 set處理,每次設(shè)置新的值時(shí)都會打印提示资溃,所以實(shí)際上$data,$props都是只讀屬性武翎。

export function stateMixin (Vue: Class<Component>) {
  const dataDef = {}
  dataDef.get = function () { return this._data }
  const propsDef = {}
  propsDef.get = function () { return this._props }
  // 只讀屬性
  if (process.env.NODE_ENV !== 'production') {
    dataDef.set = function () {
      warn(
        'Avoid replacing instance root $data. ' +
        'Use nested data properties instead.',
        this
      )
    }
    propsDef.set = function () {
      warn(`$props is readonly.`, this)
    }
  }
  Object.defineProperty(Vue.prototype, '$data', dataDef)
  Object.defineProperty(Vue.prototype, '$props', propsDef)
  Vue.prototype.$set = set
  Vue.prototype.$delete = del
  Vue.prototype.$watch = function () { ... }
}

除此之外,這里還在Vue原型上掛載了比較常見的三個(gè)方法:$set溶锭,$delete宝恶,$watch

eventsMixin

nodeEventEmitter類似,eventsMixin實(shí)現(xiàn)了四個(gè)方法:$on,$off,$once,$emit垫毙,用于監(jiān)聽霹疫,觸發(fā),銷毀事件综芥。

export function eventsMixin (Vue: Class<Component>) {
  const hookRE = /^hook:/
  Vue.prototype.$on = function () { ... }
  Vue.prototype.$once = function () { ... }
  Vue.prototype.$off = function () { ... }
  Vue.prototype.$emit = function () { ... }
}

lifecycleMixin

lifecycleMixin實(shí)現(xiàn)了三個(gè)方法:_update方法非常重要丽蝎,它主要負(fù)責(zé)將vnode生成真實(shí)節(jié)點(diǎn)。

export function lifecycleMixin (Vue: Class<Component>) {
  // 更新膀藐,將 vnode 生成 真實(shí)節(jié)點(diǎn)
  Vue.prototype._update = function () { ... }
  // 強(qiáng)制刷新
  Vue.prototype.$forceUpdate = function () { ... }
  // 銷毀
  Vue.prototype.$destroy = function () { ... }
}

renderMixin

renderMixin主要做了三項(xiàng)工作

export function renderMixin (Vue: Class<Component>) {
  installRenderHelpers(Vue.prototype)

  Vue.prototype.$nextTick = function (fn: Function) {
    return nextTick(fn, this)
  }
  
  Vue.prototype._render = function (): VNode {
    return vnode
  }
}
  1. installRenderHelpers函數(shù)用于添加render相關(guān)方法屠阻,在編譯環(huán)節(jié)最后生成的代碼,都是由這些方法拼接而成的代碼额各,所以也是非常的重要国觉,在這里先混個(gè)眼熟。
  target._o = markOnce
  target._n = toNumber
  target._s = toString
  target._l = renderList
  target._t = renderSlot
  target._q = looseEqual
  target._i = looseIndexOf
  target._m = renderStatic
  target._f = resolveFilter
  target._k = checkKeyCodes
  target._b = bindObjectProps
  target._v = createTextVNode
  target._e = createEmptyVNode
  target._u = resolveScopedSlots
  target._g = bindObjectListeners
  target._d = bindDynamicKeys
  target._p = prependModifier
  1. $nextTick方法虾啦,在下一次事件循環(huán)觸發(fā)麻诀,涉及到事件循環(huán)機(jī)制。
  2. _render方法缸逃,用于生成vnode针饥。

Vue的靜態(tài)方法屬性

通過上面5個(gè)init方法我們已經(jīng)了解了許多原型方法的添加過程,但是在Vue中還有很多全局方法需频,比如Vue.component,Vue.use等方法丁眼,它們都是構(gòu)造函數(shù)的靜態(tài)屬性,下面我們看看這些靜態(tài)屬性是如何添加的昭殉。與尋找Vue的起始位置過程恰恰相反苞七,這次我們從Vue的起始文件出發(fā),看看最后導(dǎo)出的Vue是怎樣的挪丢。

/src/core/index.js文件

這是第一層引入Vue構(gòu)造函數(shù)的文件

import { initGlobalAPI } from './global-api/index'

initGlobalAPI(Vue)

// ... 中間省略

Vue.version = '__VERSION__'

這里我們看一下initGlobalAPI方法保屯,打開core/global-api/index.js文件

export function initGlobalAPI (Vue: GlobalAPI) {
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

  // 2.6 explicit observable API
  Vue.observable = <T>(obj: T): T => {
    observe(obj)
    return obj
  }

  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })

  Vue.options._base = Vue

  extend(Vue.options.components, builtInComponents)

  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  initAssetRegisters(Vue)
}

這里掛載了很多靜態(tài)方法,Vue中大多數(shù)的全局方法都在這個(gè)位置添加的嗡呼,這里我們著重分析一下options

  import builtInComponents from '../components/index'  

  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })

  Vue.options._base = Vue

  extend(Vue.options.components, builtInComponents)  

可以看出壁榕,在Vue構(gòu)造函數(shù)上添加了一個(gè)options屬性(注意!這里是靜態(tài)屬性任内,為構(gòu)造函數(shù)所有撵渡,區(qū)別于在實(shí)例化傳入的options)。隨后又通過遍歷ASSET_TYPES死嗦,在options上添加了components,directives,filters方法趋距。另外還添加了_base,指向當(dāng)前構(gòu)造函數(shù)越除。最后通過extend方法將builtInComponents合并到options.components當(dāng)中节腐。這里的builtInComponents實(shí)際上就是Vue自帶的組件外盯,即keep-alive組件。所以最終Vue.options的內(nèi)容如下:

// Vue.options 內(nèi)容
{
    components: {
    KeepAlive
  },
  filters: {},
  directives: {},
  _base: Vue
}

這里之所以額外提起翼雀,是因?yàn)樵诤罄m(xù)選項(xiàng)合并時(shí)饱苟,會使用此處的options進(jìn)行合并。

/src/platforms/web/runtime/index.js文件

這里是第二層引入Vue的文件锅纺,主要給Vue處理平臺相關(guān)的一些方法

import Vue from 'core/index'
import config from 'core/config'
import { extend, noop } from 'shared/util'
import { mountComponent } from 'core/instance/lifecycle'
import { devtools, inBrowser } from 'core/util/index'

import {
  query,
  mustUseProp,
  isReservedTag,
  isReservedAttr,
  getTagNamespace,
  isUnknownElement
} from 'web/util/index'

import { patch } from './patch'
import platformDirectives from './directives/index'
import platformComponents from './components/index'

// install platform specific utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement

// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)

Vue.prototype.__patch__ = inBrowser ? patch : noop
Vue.prototype.$mount = function () { ... }

export default Vue

這里首先給Vue.config添加了一系列方法掷空,注意,這些方法之所以在這里添加而不是在core/index.js文件里添加囤锉,是因?yàn)檫@里的方法都與平臺相關(guān)坦弟,不同的平臺的方法實(shí)現(xiàn)也會不一樣。

extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)

這兩個(gè)extend實(shí)際上進(jìn)一步擴(kuò)充了Vue.options方法官地,擴(kuò)充后的內(nèi)容如下

// Vue.options 內(nèi)容
{
    components: {
    KeepAlive,
    // 新增 platformComponents
    Transition,
    // 新增 platformComponents
    TransitionGroup
  },
  filters: {},
  directives: {
    // 新增 platformDirectives
    model,
    // 新增 platformDirectives
    show
  },
  _base: Vue
}

這也是為什么我們可以不用注冊也能全局使用v-model,v-show的原因了酿傍,因?yàn)?code>Vue已經(jīng)幫我們?nèi)肿粤恕?/p>

/src/platforms/web/entry-runtime-with-compiler.js文件

這是最后一層引入Vue

import Vue from './runtime/index'
...

const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
    
    ...
    
  return mount.call(this, el, hydrating)
}

Vue.compile = compileToFunctions

export default Vue

這里主要是重新實(shí)現(xiàn)了$mount方法,但是為什么原先在runtime/index.js文件里實(shí)現(xiàn)了$mount方法驱入,這里又要重新實(shí)現(xiàn)一遍呢赤炒?因?yàn)?code>runtime/index.js里的$mount與編譯是無關(guān)的,無法處理template模板代碼亏较,而這里重寫的$mount實(shí)際上還是調(diào)用了runtime/index.js里的$mount莺褒,但是在此之前,增加了從templaterender的編譯過程雪情。

實(shí)例化過程

前面已經(jīng)將Vue的各種方法屬性掛載完畢遵岩,現(xiàn)在則是需要進(jìn)行實(shí)例化了,也就是調(diào)用之前提到的_init方法巡通。打開/src/core/instance/init.js文件尘执,代碼如下:

Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    ...

    // 1. 合并options
    if (options && options._isComponent) {
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
  
    ...

    // 2. 初始化數(shù)據(jù)
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')

    // 3. 掛載
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }

在初始化的過程中,主要分為三個(gè)階段:

階段一:合并選項(xiàng)宴凉,將 Vue.options和傳入的options進(jìn)行合并

階段二:初始化數(shù)據(jù)誊锭,并對數(shù)據(jù)進(jìn)行響應(yīng)式處理

階段三:編譯代碼,得到render函數(shù)弥锄,將vnode生成真實(shí)節(jié)點(diǎn)丧靡,并掛載到界面

由于這部分比較核心,且難以理解籽暇,這里僅做了解温治,后續(xù)會逐一進(jìn)行分析。

Vue的整體設(shè)計(jì)

通過上面的分析图仓,我們已經(jīng)對Vue原型方法Vue靜態(tài)方法屬性但绕,Vue實(shí)例化過程有了大致的了解救崔,下面我們用張圖總結(jié)下整體的內(nèi)容惶看,也就是Vue整體的設(shè)計(jì)思路。

image.png

總結(jié)下來就是:

  1. 構(gòu)建一個(gè)具有完備功能的構(gòu)造函數(shù)六孵,因此在上面添加各個(gè)模塊需要的方法屬性纬黎。包括原型方法屬性和靜態(tài)方法屬性。
  2. 進(jìn)行實(shí)例化劫窒,在實(shí)例化過程中進(jìn)行各種處理本今,其中包括:選項(xiàng)合并,數(shù)據(jù)響應(yīng)式處理主巍,編譯冠息,虛擬DOM更新等等。

這里的描述比較籠統(tǒng)孕索,旨在從整體上來對Vue進(jìn)行一個(gè)了解逛艰。在接下來的章節(jié)我們會詳細(xì)分析實(shí)例化的整個(gè)過程,從而由點(diǎn)及面的了解Vue搞旭。下一章節(jié)我們將開始Vue核心代碼的正式學(xué)習(xí)散怖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市肄渗,隨后出現(xiàn)的幾起案子镇眷,更是在濱河造成了極大的恐慌,老刑警劉巖翎嫡,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欠动,死亡現(xiàn)場離奇詭異,居然都是意外死亡钝的,警方通過查閱死者的電腦和手機(jī)翁垂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硝桩,“玉大人沿猜,你說我怎么就攤上這事⊥爰梗” “怎么了啼肩?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衙伶。 經(jīng)常有香客問我祈坠,道長,這世上最難降的妖魔是什么矢劲? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任赦拘,我火速辦了婚禮,結(jié)果婚禮上芬沉,老公的妹妹穿的比我還像新娘躺同。我一直安慰自己阁猜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布蹋艺。 她就那樣靜靜地躺著剃袍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捎谨。 梳的紋絲不亂的頭發(fā)上民效,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音涛救,去河邊找鬼畏邢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛州叠,可吹牛的內(nèi)容都是我干的棵红。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼咧栗,長吁一口氣:“原來是場噩夢啊……” “哼逆甜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起致板,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤交煞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后斟或,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體素征,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年萝挤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了御毅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怜珍,死狀恐怖端蛆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情酥泛,我是刑警寧澤今豆,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站柔袁,受9級特大地震影響呆躲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捶索,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一插掂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦辅甥、人聲如沸箩祥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至底瓣,卻和暖如春谢揪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捐凭。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工拨扶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茁肠。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓患民,卻偏偏與公主長得像,于是被迫代替她去往敵國和親垦梆。 傳聞我的和親對象是個(gè)殘疾皇子匹颤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 作者:lihongxun945github.com/lihongxun945/myblog/issues/23 這...
    grain先森閱讀 856評論 0 4
  • 入口文件 vue-2.6.11\src\platforms\web\entry-runtime-with-comp...
    愛吃饅頭不吃辣閱讀 720評論 0 0
  • Vue2 源碼分析 基于 Vue 2.6.10 版本vue2.0 在實(shí)現(xiàn)“響應(yīng)數(shù)據(jù)綁定”的同時(shí)引入了 virtua...
    YBFQ_WH閱讀 316評論 0 0
  • 因?yàn)樽罱覀兘M內(nèi)有個(gè)分享主題,即vue2的源碼學(xué)習(xí)分享托猩,我們幾個(gè)人分別分享幾個(gè)不同部分印蓖,但是雖然我們的分工是每個(gè)人...
    阿go閱讀 1,732評論 0 0
  • 源碼版本:v2.1.10 分析目標(biāo) 通過閱讀源碼,對 Vue2 的基礎(chǔ)運(yùn)行機(jī)制有所了解京腥,主要是: Vue2 中數(shù)據(jù)...
    NARUTO_86閱讀 12,257評論 6 26