2.最俗學(xué)習(xí)之-Vue源碼學(xué)習(xí)-引入篇(中)

源碼地址

引入Vue后進(jìn)行了global-api的初始化,那么現(xiàn)在就到了第二步的初始化,文件入口為:

src\entries\web-runtime.js

首先是4個(gè)方法綁定在Vue.config上


isUnknownElement     --方法解釋看methods realizes目錄  源碼在platforms\web\util\element.js
isReservedTag        --方法解釋看methods realizes目錄  源碼在platforms\web\util\element.js
getTagNamespace      --這個(gè)方法就不做解釋了比較簡單     源碼在platforms\web\util\element.js
mustUseProp          --方法解釋看methods realizes目錄  源碼在platforms\web\util\attrs.js

然后這里到了extend方法,這個(gè)和Vue.extend不一樣的,我們來看一下src\shared\util


export function extend (to: Object, _from: ?Object): Object {
  for (const key in _from) {
    to[key] = _from[key]
  }
  return to
}

好吧,這個(gè)就是object的繼承吧,把后者的屬性賦值給前者,最后返回前者,然后我們找到這兩個(gè)東西

  • platforms/web/runtime/directives/index

  • platforms/web/runtime/components/index

這兩個(gè)文件夾里面有6個(gè)js文件,很熟悉的東東,就是常用的v-model,v-show,transition組件了,在上
一篇有提到過的


// 還記得Vue.options這個(gè)值是這樣的

Vue.options = {
    components: {
      KeepAlive: {
        
      },
      // 這兩個(gè)是Vue自帶的,在另一個(gè)地方初始化的,這里暫時(shí)這樣理解就好,存在這兩個(gè)方法的
      Transition: {
        
      },
      TransitionGroup: {
        
      },
      my-component: {
        
      }
    },
    directives: {
      // 這兩個(gè)是Vue自帶的,在另一個(gè)地方初始化的,這里暫時(shí)這樣理解就好,存在這兩個(gè)方法的
      model: {

      },
      show: {

      },
      // 如果經(jīng)過了第一種方法注冊指令,那么就會添加下面一個(gè)了
      demo: {
        bind: function () {
          // some methods
        }
      }
    },
    filters: {}
}

那么自帶的東東就是在這里初始化的了通過這兩個(gè)操作,這里水平有限,暫時(shí)擱著 - -#

  • extend(Vue.options.directives, platformDirectives)

  • extend(Vue.options.components, platformComponents)

然后到了Vue.prototype.patch

這個(gè)東西涉及太多,包括vdom和渲染rander等等,水平有限,暫時(shí)擱著 - -#

主要就是看這個(gè)Vue.prototype.$mount

這里有個(gè)query(el),這個(gè)源碼在platforms\web\util\index.js里面,主要就是獲取el這個(gè)dom元素

然后執(zhí)行this._mount(el, hydrating),這個(gè)方法后續(xù)再講,這個(gè)是Vue實(shí)例啟動了的方法,至于第二個(gè)
參數(shù)hydrating,<span style="font-weight: bold;margin-bottom: 10px;color: #FF0000">這個(gè)貌似是服務(wù)端渲染才要用到的,個(gè)人猜想</span>

然后再到了同目錄下的web-runtime-with-compiler.js文件,這個(gè)文件重寫了$mount方法,查了下資料以及
官方的說法大概就是,獨(dú)立構(gòu)建時(shí)帶有模板編譯功能的初始化方法,還是直接看代碼吧

首先const mount = Vue.prototype.$mount緩存了上面的$mount方法,然后重寫,query(el)獲取dom,
然后判斷dom不能是body標(biāo)簽或者h(yuǎn)tml標(biāo)簽,獲取this.$options,這個(gè)實(shí)際上就是new Vue傳入的參數(shù)
后面講數(shù)據(jù)綁定的時(shí)候會經(jīng)常用到,這里舉個(gè)栗子說明一下吧:


var options = {
  el: '#app',
  data () {
    return {
      msg: 'hello world'
    }
  }
}

new Vue(options)

// 這個(gè)就是這個(gè)options,一個(gè)對象字面量,然后有if (!options.render)這樣的一個(gè)判斷,這里要
// 說下Vue的三種寫法:Render函數(shù),template模板,el綁定

第一種:Render函數(shù)


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Render函數(shù)</title>
</head>
<body>
  <div id="app">
  
  </div>
</body>
<script type="text/javascript" src="vue.js"></script>
<script>

var options = {
  el: '#app',
  data () {
    return {
      msg: 'hello world'
    }
  },
  render: function (createElement) {
    return createElement('h1', this.msg)
  }
}


new Vue(options)


</script>
</html>

// 這種寫法就是最底層的寫法,性能最好,但是難以理解,這里方法還有更復(fù)雜的方式,后面的兩種寫法
// 最后會經(jīng)過一些列的算法,比如AST解析再轉(zhuǎn)換成render函數(shù),最后還是得出這樣的形式,這里這種方
// 法不討論了

第二種:template模板,這里又有三種情況


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>template模板</title>
</head>
<body>
  <div id="app">
  
  </div>
</body>
<script type="text/javascript" src="vue.js"></script>
<script>

var options = {
  el: '#app',
  data () {
    return {
      msg: 'hello world'
    }
  },
  template: '<h1 style="color: red;">{{msg}}</h1>'
}

new Vue(options)


</script>
</html>

// 這是第一種情況
// 這種寫法因?yàn)闆]有render函數(shù),則會進(jìn)入if語句里面,然后這里let template = options.template獲取
// 字符串模板后就直接進(jìn)入compileToFunctions這個(gè)方法了


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>template模板</title>
</head>
<body>
  <div id="app">

  </div>
</body>
<script type="text/javascript" src="vue.js"></script>

<script id="my-tel">
  `<h1 style="color: blue;">{{msg}}</h1>`
</script>

<script>

var options = {
 el: '#app',
 data () {
   return {
     msg: 'hello world'
   }
 },
 template: '#my-tel'
}

new Vue(options)


</script>
</html>

// 這是第二種情況
// 這種寫法因?yàn)闆]有render函數(shù),則會進(jìn)入if語句里面,然后進(jìn)入if (template.charAt(0) === '#')
// idToTemplate方法執(zhí)行,方法解釋見methods realizes目錄
// 之后就直接進(jìn)入compileToFunctions這個(gè)方法了


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>template模板</title>
</head>
<body>
  <div id="app">

  </div>

  <template id="typeByMe">
    <div>
      <p style="color: red">{{msg}} No.1</p>
      <p style="color: blue">{{msg}} No.2</p>
    </div>
  </template>
</body>
<script type="text/javascript" src="vue.js"></script>
<script>

var options = {
  el: '#app',
  data () {
    return {
      msg: 'hello world'
    }
  },
  template: document.getElementById('typeByMe')
}

new Vue(options)

</script>
</html>

// 第三種則走if (template.nodeType)這里,這個(gè)就很好理解了,因?yàn)檫@里的template是dom節(jié)點(diǎn)
// 所以里面直接就獲取innerHTML了,和第二種差不多,只是這里自己手動獲取了dom節(jié)點(diǎn)
// 之后就直接進(jìn)入compileToFunctions這個(gè)方法了

第三種:el綁定方法,這種便是我們最常用的了


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>el綁定</title>
</head>
<body>
  <div id="app">
    <p style="color: blue">{{msg}}</p>
  </div>
</body>
<script type="text/javascript" src="vue.js"></script>
<script>

var options = {
  el: '#app',
  data () {
    return {
      msg: 'hello world'
    }
  }
}

new Vue(options)

</script>
</html>

// 這種則走template = getOuterHTML(el)這個(gè)方法,這里el就是dom節(jié)點(diǎn),通過query(el)方法獲取的
// getOuterHTML方法就在下面,獲取元素的el元素的html片段,最后template也是一段字符串模板了
// 之后就直接進(jìn)入compileToFunctions這個(gè)方法了,這個(gè)方法先不看了,很復(fù)雜

// 這個(gè)方法返回對象{ render, staticRenderFns },然后綁定在options上面

// options.render = render   也就是下面這個(gè)方法

function anonymous() {
  with(this){return _c('div',{attrs:{"id":"app"}},[_c('p',{staticStyle:{"color":"blue"}},[_v(_s(msg))])])}
}

這個(gè)并不是一個(gè)自定義的方法名字,它的創(chuàng)建其實(shí)是這樣子的,算是一種比較特殊的創(chuàng)建函數(shù)方式

var code = 'var co = 12;co = co + 1;return co'

var a = new Function(code)

console.log(a)

輸出 =>
function anonymous() {
  var co = 12;co = co + 1;return co
}

console.log(a())

輸出 => 13

最后還是調(diào)用先前緩存下來的mount方法,這個(gè)下一節(jié)再說

關(guān)于這個(gè)可以參考這位大神的文章

【Vue源碼探究二】從 $mount 講起,一起探究Vue的渲染機(jī)制

<p style="font-weight: bold;margin-bottom: 10px;color: #FF0000">剩下的幾個(gè)問題</p>


Vue.set = set                       // 涉及到Vue的數(shù)據(jù)響應(yīng)式系統(tǒng),先保留
Vue.delete = del                    // 涉及到Vue的數(shù)據(jù)響應(yīng)式系統(tǒng),先保留
Vue.nextTick = util.nextTick        // 水平有限,看不懂 - -#
initMixin(Vue)                      // 這個(gè)后面再講
initExtend(Vue)                     // 水平有限,看不懂 - -#


extend(Vue.options.directives, platformDirectives)  // 水平有限,看不懂 - -#
extend(Vue.options.components, platformComponents)  // 水平有限,看不懂 - -#
Vue.prototype.__patch__                             // 水平有限,看不懂 - -#
compileToFunctions                                  // 水平有限,看不懂 - -#


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 源碼版本:v2.1.10 分析目標(biāo) 通過閱讀源碼,對 Vue2 的基礎(chǔ)運(yùn)行機(jī)制有所了解,主要是: Vue2 中數(shù)據(jù)...
    NARUTO_86閱讀 12,577評論 6 26
  • 源碼地址 前方高能?。。?這只是一篇個(gè)人學(xué)習(xí)Vue.js源碼的筆記,并非教程,鑒于個(gè)人水平有限,可能存在錯(cuò)誤,還望...
    木子tar閱讀 545評論 0 0
  • 安裝好之后,新建工程打開終端 1.cd 到項(xiàng)目地址? ? ~ git:(master) ?cd /User...
    紗云閱讀 355評論 0 0

友情鏈接更多精彩內(nèi)容