Vue:自定义插件Vue.use()、Vue.component()、Vue.extend()的一点学习

最近看了一下Vue自定义插件的步骤,记录一下:

一、Vue.use()

网上比较多的例子是创建一个loading组件,我们也从这里开始学习

	// 第一步:定义loading组件
	// 在loading/loading.vue文件中定义一个简单的组件内容
	...
	
	// 第二步:定义loading的install方法
	// loading/index.js
	import LoadingComponent from './loading.vue'
	
	const Loading = {
	  install: function (Vue) {
	    Vue.component('Loading', LoadingComponent)
	  }
	}
	export default Loading


	// 第三步:在入口文件中使用插件
	// main.js
	import Loading from './components/loading'
	Vue.use(Loading)

	// 第四步:我们可以在全局使用Loading组件了

二、Vue.use() 源码解读

Vue.use() 需要在调用 new Vue() 启动应用之前完成

	// Vue源码文件路径:src/core/global-api/use.js
	
	import { toArray } from '../util/index'
	
	export function initUse (Vue: GlobalAPI) {
	
      // 接收的plugin参数的限制是Function | Object两种类型		          
	  Vue.use = function (plugin: Function | Object) {
	  
	    // vue首先判断这个插件是否被注册过,不允许重复注册
	    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
	    if (installedPlugins.indexOf(plugin) > -1) { 
	      return this
	    }
	
	    // 将我们传入的参数整理成数组
	    // additional parameters
	    const args = toArray(arguments, 1)
	    
	    // 将Vue对象添加到这个数组的起始位置args.unshift(this),这里的this 指向Vue对象
	    args.unshift(this)
	    
	    // 如果我们传入的plugin(Vue.use的第一个参数)的install是一个方法。
	    // 就是说如果我们传入一个对象,对象中包含install方法,那么我们就调用这个plugin的install方法
	    // 并将整理好的数组当成参数传入install方法中。
	    if (typeof plugin.install === 'function') {
	      plugin.install.apply(plugin, args)
	    } else if (typeof plugin === 'function') {

		  // 如果我们传入的plugin就是一个函数
		  // 那么我们就直接调用这个函数并将整理好的数组当成参数传入。
	      plugin.apply(null, args)
	    }
	    installedPlugins.push(plugin) 	// 给这个插件添加至已经添加过的插件数组中,标示已经注册过
	    return this 	// 返回Vue对象
	  }
	}

三、疑问及回答

  • (1)
    Q:既然Vue.component()本身就是全局API,为什么还需要使用Vue.use()来封装为插件呢?
    A:我们可以在插件的install方法中做很多事情,不仅仅是 全局注册组件,还包括

     	import Vue from 'vue';		
     	const plugin = {
     	  install (Vue, options) {		   
     	    Vue.myGlobMethod = function () {};	 // 添加全局方法或者属性		   
     	    Vue.directive();			 // 添加全局指令	
     	    Vue.mixin();							 // 添加混入		    
     	    Vue.prototype.$xxx = function () {};		// 添加实例方法		   
     	    Vue.component()		 			// 注册全局组件
     	    Vue.filters()                   // 注册过滤
     	  }
     	}
    

    之所以使用Vue.use()是因为我们可以在 install 的文件里做更多配置相关的工作,main.js 不会变的臃肿,更方便管理。

     // main.js
     	import Vue from 'vue'
     	import base from './base.js'
     	Vue.use(base)
     	
     	import echarts from './echarts.js'
     	Vue.use(echarts)
     	
     	new Vue({
     	 ...
     	})
         
     // echarts.js    
     	import Echarts from 'echarts'
     	export default {
     	 install(Vue){
     	  Vue.prototype.$echarts = Echarts
     	 }
     	}
     	
     // base.js
     	import a from './a'
     	import b from './b'
     	let components = { a, b }
     	const installBase = {
     	 install (Vue) {
     	  Object.keys(components).map(key => Vue.component(key, components[key]))
     	 }
     	}
    
  • (2)
    Q:Vue.use()时传入的参数plugin参数的限制是Function | Object两种类型,有什么差异呢?
    A:这个问题的答案引用自:https://segmentfault.com/a/1190000012296163

     	export const Plugin = {
         install(Vue) {
             Vue.component...
             Vue.mixins...
             Vue...
             // 我们也可以在install里面执行其他函数,Vue会将this指向我们的插件
             console.log(this)  // {install: ...,utils: ...}
             this.utils(Vue)    // 执行utils函数
             console.log(this.COUNT) // 0
         },
         utils(Vue) {
             Vue...
             console.log(Vue)  // Vue
         },
         COUNT: 0    
     }
     // 我们可以在这个对象上添加参数,最终Vue只会执行install方法,而其他方法可以作为封装install方法的辅助函数
     
     const test = 'test'
     export function Plugin2(Vue) {
         Vue...
         console.log(test)  // 'test'
         // 注意如果插件编写成函数形式,那么Vue只会把this指向null,并不会指向这个函数
         console.log(this)  // null
     }
     // 这种方式我们只能在一个函数中编写插件逻辑,可封装性就不是那么强了      
    
  • (3)题外话
    Q:Vue.extend 和 Vue.component 的差别?
    A:理解Vue.extend()和Vue.component()是很重要的:
    由于Vue本身是一个构造函数(constructor),Vue.extend()是一个继承于方法的类(class),参数是一个包含组件选项的对象。它的目的是创建一个Vue的子类并且返回相应的构造函数。
    而Vue.component()实际上是一个类似于Vue.directive()和Vue.filter()的注册方法,它的目的是给指定的一个构造函数与一个字符串ID关联起来。之后Vue可以把它用作模板,实际上当你直接传递选项给Vue.component()的时候,它会在背后调用Vue.extend()。

    Vue.extend 返回的是一个扩展实例构造器,也就是预设了部分选项的Vue实例构造器。其主要用来服务于Vue.component
    在这里插入图片描述

     <template>
       <my-footer></my-footer>
       <footer-view></footer-view>
     </template>
     
     <script>
       let Footer = Vuew.extend({
         data(){
           return {
             footerName:'happy chinese valentine's day~'
           }
         },
         template:'<div>{{footerName}}</div>'
       });
       
       // 法一:
       Vue.component('footer-view',Footer);
       
       // 法二:
       // new Footer({
       //   data:{
       //     '...':''
       //   }
       // }).$mount('my-footer')
     </script>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值