zoukankan      html  css  js  c++  java
  • Vue.js 源码分析(五) 基础篇 方法 methods属性详解

     methods中定义了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>

    显示的样式为:

    当我们点击按钮后变为了:

    methods方法中的上下文为当前实例,也就是this为当前实例。

     注:不应该使用箭头函数来定义 method 函数 (例如ChangeMessage:()=>this.message="Hello Vue")。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.message 将是 undefined。

     源码分析


      Vue实例后会先执行_init()进行初始化(4579行)时,会执行initState()进行初始化,如下:

    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()定义如下:

    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的实现是比较简单的。

  • 相关阅读:
    EMF:Ecore模型
    30天敏捷生活:开篇
    30天敏捷生活(5):形成个人价值观
    GMF:图形定义模型(Graphical definition model)介绍
    30天敏捷结果(11):高效能、慢生活
    读书笔记:心智的力量
    GMP:了解GMF引擎功能(Graphical Modeling Framework)
    GEF:应用示例列表
    30天敏捷结果(9):使用必须、应该、可以来确定每天事情的优先级
    Eclipse:Eclipse平台技术概述
  • 原文地址:https://www.cnblogs.com/greatdesert/p/11038026.html
Copyright © 2011-2022 走看看