zoukankan      html  css  js  c++  java
  • Vue源码学习(二)-----自定义组件

    1、Vue插件的功能

    • 添加全局方法或者属性,例如vue-custom-element;
    • 添加全局资源:指令/过滤器或者过渡等;
    • 通过全局混入来添加一些组件选项,例如vue-router;
    • 添加vue实例方法,将其加到原型上;
    • 一个组件库,提供自己的API,同时提供上面提到的一个或者多个功能,例如Element-ui提供自己的API;

    2、Vue的钩子函数

    • 源码中(/src/core/instance/index.js),Vue是一个构造函数,所以我们需要使用new的方式创建一个关于Vue的实例,如果是生产环境或者不是Vue的实例,将发出警告,然后通过Vue实例上的_init()方法进行Vue的初始化;
      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)
      }
    • _init()方法是Vue通过prototype来实现的一个原型属性,Vue先调用了initLifecycle(vm)、initEvents(vm)、initRender(vm)这三个方法,用于初始化生命周期、事件和渲染函数,且发生在beforeCreated钩子函数之前,在Vue中几乎所有的钩子(errorCaptured除外)函数执行都是通过callHook(vm: Component, hook: string) 来调用的;
      Vue.prototype._init = function (options?: Object) {
          ...
          // expose real self
          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)
          }
       }
    • callHook()方法根据传入的hook从实例中拿到对应的回调函数数组(/packages/vue-template-compiler/browser.js下的 LIFECYCLE_HOOKS),然后再执行,步骤如下:
      • 把所有同类钩子先合并成数组(一个实例通过mixins可能有很多个相同钩子),然后存放在 vm.$options,类似于mixin,然后遍历执行;
      • 使用
        //callHook的作用就是执行用户自定义的钩子函数,并将钩子中this指向指为当前的组件实例
        export function callHook(vm:Component, hook:String) {
            //vm为当前vue实例,hook为钩子函数名称
            pushTarget(); //为了避免在某些生命周期钩子中使用 props 数据导致收集冗余的依赖
          //获取对相应的钩子函数内容
            var handlers = vm.$options[hook];
            if (handlers) {
                for (var i = 0, j = handlers.length; i < j; i++) {
                    try {
                        // 直接调用
                        handlers[i].call(vm);
                    } catch (e) {
                        handleError(e, vm, (hook + " hook"));
                    }
                }
            }
            // 钩子函数事件emit
            if (vm._hasHookEvent) {
                vm.$emit('hook:' + hook);
            }
            popTarget();//为了避免在某些生命周期钩子中使用 props 数据导致收集冗余的依赖
        }

    3、插件的开发流程

    • 如果插件是一个对象,必须暴露一个install方法,如果是一个函数,自己则会被作为install方法
      Myplugin.install = (Vue,options) => {
      //添加全局方法或者属性
      Vue.globalMethod = () => {}
      //添加全局资源
      Vue.directive(directiveName,{})
      //注入组件选项
      Vue.mixin({})
      //添加实例方法
      Vue.prototype.commonMethod = () => {}

              注意:首先根据installed属性来判断插件是否被注册,防止二次注册,然后利用Vue.mixin使插件在beforeCreate(即组件实例化之前)注册,在destoryed中销毁组件,最后利用defineProperty;让复制关系为已读,且不会被人为修改,结尾还是用Vue.component方法注册router-view与router-link两个组件;

    • 在new Vue()(即组件实例化之前)使用全局方法Vue.use(),执行时自动执行install方法,用来安装插件,多次调用,只会注册一次;
      注意:Vue上定义use方法,参数可以是Object或者Function,逻辑:先判断插件是否注册过,防止重复注册,然后使用工具类的方法toArray拿到use中从1-剩余的参数,最后根据是
      Object或者Function执行对应的install方法,并记录该组件已经被注册过(将参数放入一个数组中)。

    4、遇到的问题

      暂无

  • 相关阅读:
    移动端疫情展示
    第四周学习总结
    构建之法阅读笔记二
    第三周学习总结
    AJAX学习篇
    jQuery学习篇
    软件工程开课第二周——介绍篇
    【Spring】DispatcherServlet的启动和初始化
    【设计模式】模板方法模式小解
    【Mybatis】MyBatis调用带有返回结果、output参数的存储过程上与ibatis的区别
  • 原文地址:https://www.cnblogs.com/wxh0929/p/13839758.html
Copyright © 2011-2022 走看看