Vue 2.0 源碼分析(五) 基礎篇 方法 methods屬性詳解

用法css


 methods中定義了Vue實例的方法,官網是這樣介紹的:html

例如::vue

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
    <title>Document</title>
</head>
<body>
    <div id="app">{{message}}<button @click="ChangeMessage">測試按鈕</button></div>
    <script>
        new Vue({
            el:'#app',
            data:{message:"Hello World!"},
            methods:{
                ChangeMessage:function(){this.message="Hello Vue!";}
            }
        })
    </script>
</body>
</html>

顯示的樣式爲:app

當咱們點擊按鈕後變爲了:函數

methods方法中的上下文爲當前實例,也就是this爲當前實例。oop

 注:不該該使用箭頭函數來定義 method 函數 (例如ChangeMessage:()=>this.message="Hello Vue")。理由是箭頭函數綁定了父級做用域的上下文,因此 this 將不會按照指望指向 Vue 實例,this.message 將是 undefined。源碼分析

 源碼分析測試


  Vue實例後會先執行_init()進行初始化(4579行)時,會執行initState()進行初始化,以下:this

function initState (vm) { //第3303行
  vm._watchers = [];
  var opts = vm.$options;
  if (opts.props) { initProps(vm, opts.props); }
  if (opts.methods) { initMethods(vm, opts.methods); }        //若是定義了methods,則調用initMethods初始化data
  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);
  }
}

 initMethods()定義以下:spa

function initMethods (vm, methods) {   //第3513行 var props = vm.$options.props;
  for (var key in methods) {                 //遍歷methods對象,key是每一個鍵,好比例子裏的ChangeMessage
    {
      if (methods[key] == null) {         //若是值爲null,則報錯
        warn(
          "Method \"" + key + "\" has an undefined value in the component definition. " +
          "Did you reference the function correctly?",
          vm
        );
      } 
      if (props && hasOwn(props, key)) {     //若是props中有同名屬性,則報錯
        warn(
          ("Method \"" + key + "\" has already been defined as a prop."),
          vm
        );
      }
      if ((key in vm) && isReserved(key)) {   //若是key是以$或_開頭則,也報錯
        warn(
          "Method \"" + key + "\" conflicts with an existing Vue instance method. " +
          "Avoid defining component methods that start with _ or $."
        );
      }
    }
    vm[key] = methods[key] == null ? noop : bind(methods[key], vm);             //若是key對應的值不是null,則執行bind()函數
  }
}

執行bind()函數,參數1爲對應的函數體,參數2是當前的Vue實例,bind()函數定義在第196行,以下:

function polyfillBind (fn, ctx) {            //當Function的原型上不存在bind()函數時,自定義一個函數實現一樣的功能,用apply()或call()來實現
  function boundFn (a) {
    var l = arguments.length;
    return l
      ? l > 1
        ? fn.apply(ctx, arguments)
        : fn.call(ctx, a)
      : fn.call(ctx)
  }

  boundFn._length = fn.length;
  return boundFn
}

function nativeBind (fn, ctx) {             //調用Function的原型上的bind()方法,上下文聞ctx
  return fn.bind(ctx)
}

var bind = Function.prototype.bind             //若是Function的原型上有bind方法,則調用該方法,不然用自定義的polyfillBind()方法
  ? nativeBind
  : polyfillBind;

相比較其它API,method的實現是比較簡單的。

相關文章
相關標籤/搜索