<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          new Vue 發(fā)生了什么?

          共 3744字,需瀏覽 8分鐘

           ·

          2022-04-07 23:06


          const app = new Vue({  template: '
          hello world
          '
          ,
          el: '#app'})


          Vue實際上是一個類

          function Vue (options) {  if (!(this instanceof Vue)) {    // 必須通過new來調(diào)用    warn('Vue is a constructor and should be called with the `new` keyword')  }  // 注意options參數(shù),是創(chuàng)建實例時候傳入的對象  this._init(options)}


          可以看到?Vue?只能通過 new 關鍵字初始化,然后會調(diào)用?this._init?方法。

          Vue.prototype._init = function (options) {  const vm = this  vm._self = vm??//?這些代碼之后再講  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')
          // 先看這行代碼 if (vm.$options.el) { vm.$mount(vm.$options.el) }}


          先看$mount

          // 先緩存之前的$mount方法const mount = Vue.prototype.$mount//?再重寫$mount方法Vue.prototype.$mount = function (el) {  const options = this.$options  if (template) {    const { render, staticRenderFns } = compileToFunctions(template, {      shouldDecodeNewlines,      shouldDecodeNewlinesForHref,      delimiters: options.delimiters,      comments: options.comments    }, this)    options.render = render // render很重要,在后面會用到    options.staticRenderFns = staticRenderFns  }  return mount.call(this, el, hydrating) // 開始掛載}


          注意compileToFunctions是把template轉(zhuǎn)換成render函數(shù),怎么轉(zhuǎn)的看下下面

          const compiler = require('vue-template-compiler')let str = `
          999
          `

          console.log(compiler.compile(str))


          發(fā)現(xiàn)包含ast和render這兩個屬性。注意這個render我們之后會用到

          {  ast: {    type: 1,    tag: 'div',    attrsList: [],    attrsMap: { 'v-if': 'msg' },    rawAttrsMap: {},    parent: undefined,    children: [ [Object] ],    if: 'msg',    ifConditions: [ [Object] ],    plain: true,    static: false,    staticRoot: false,    ifProcessed: true  },  render: `with(this){return (msg)?_c('div',[_v("999")]):_e()}`,  staticRenderFns: [],  errors: [],  tips: []}


          之前的$mount方法

          Vue.prototype.$mount = function (el) {  el = el && query(el)  return mountComponent(this, el)}


          終于來到了重點mountComponent方法

          export function mountComponent () {  callHook(vm, 'beforeMount')  let updateComponent  updateComponent = () => {    const name = vm._name    const id = vm._uid    const startTag = `vue-perf-start:${id}`    const endTag = `vue-perf-end:${id}`
          mark(startTag) const vnode = vm._render() // 重點 mark(endTag) measure(`vue ${name} render`, startTag, endTag)
          mark(startTag) vm._update(vnode, hydrating) // 重點 mark(endTag) measure(`vue ${name} patch`, startTag, endTag) } new Watcher(vm, updateComponent, noop, { before () { if (vm._isMounted) { callHook(vm, 'beforeUpdate') } } }, true /* isRenderWatcher */)}


          mountComponent 核心就是先實例化一個渲染W(wǎng)atcher,在它的回調(diào)函數(shù)中會調(diào)用 updateComponent 方法,在此方法中調(diào)用 vm._render 方法先生成虛擬 Node,最終調(diào)用 vm._update 更新 DOM。


          Watcher 在這里起到兩個作用,一個是初始化的時候會執(zhí)行回調(diào)函數(shù),另一個是當 vm 實例中的監(jiān)測的數(shù)據(jù)發(fā)生變化的時候執(zhí)行回調(diào)函數(shù),這塊兒我們會在之后的章節(jié)中介紹。


          Vue 的?_render?方法,它用來把實例渲染成一個虛擬 Node。

          Vue.prototype._render = function () {  const vm = this  const { render, _parentVnode } = vm.$options  let vnode  try {    vnode = render.call(vm._renderProxy, vm.$createElement)  } catch (e) {}}


          這段代碼最關鍵的是?render?方法的調(diào)用,我們在平時的開發(fā)工作中手寫?render?方法的場景比較少,而寫的比較多的是?template?模板,在之前的?mounted?方法的實現(xiàn)中,會把?template?編譯成?render?方法,但這個編譯過程是非常復雜的,我們不打算在這里展開講,之后會專門花一個章節(jié)來分析 Vue 的編譯過程。


          在 Vue 的官方文檔中介紹了?render?函數(shù)的第一個參數(shù)是?createElement

          render: function (createElement) {  return createElement('div', {     attrs: {        id: 'app'      },  }, this.message)}


          再回到?_render?函數(shù)中的?render?方法的調(diào)用:

          vnode = render.call(vm._renderProxy, vm.$createElement)


          可以看到,render?函數(shù)中的?createElement?方法就是?vm.$createElement?方法。實際上,vm.$createElement?方法定義是在執(zhí)行?initRender?方法的時候。


          export function initRender (vm) {  vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)  vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)}

          結(jié)合我們之前的render


          瀏覽 29
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄片在线视频 | 青青草黄色视频 | 国产一区二区三区无码 | 青草福利 | 黄色电影免费网站麻豆 |