来看看vue中插件实现吧

插件是什么

在vue的文档中有写插件的作用是为 【 Vue 添加全局功能 】
同时对插件的功能范围没有严格的要求,主要有以下几种

  1. 添加全局方法或者属性。如:vue-custom-element
  2. 添加全局资源:指令/过滤器/过渡等。如 vue-touch
  3. 通过全局混入来添加一些组件选项。如 vue-router
  4. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
  5. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
如何使用插件

用全局方法 Vue.use() 使用插件。它需要在调用 new Vue() 启动应用之前完成

Vue.use(MyPlugin, { someOption: true }) // 存在可选的第二个参数
开发插件

Vue规定,Vue.js 的插件应该暴露一个 install 方法,这里跟vue在初始化时调用的 initUse 有关,在这个函数里初始化里 Vue.use

插件这样写:

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或属性
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}

在Vue里使用插件,需要使用Vue.use引入,下面是Vue对于Vue.use的实现,Vue.use 会执行插件的install函数

function initUse (Vue) {
  Vue.use = function (plugin) {
    var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    } 
    // toArray 拿到use传递的除第一个插件外的参数
    var args = toArray(arguments, 1);
    // 绑定this
    args.unshift(this); // 将Vue放再第一位,当install的参数传入
    // 判断是否存在install,
    // install是对象的方法,执行install
    // 插件是function,直接执行执行
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args);
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args);
    }
    installedPlugins.push(plugin);
    return this
  };
}
function toArray (list, start) {
  start = start || 0;
  var i = list.length - start;
  var ret = new Array(i);
  while (i--) {
    ret[i] = list[i + start];
  }
  return ret
}
一般写插件要暴露处出来一个install方法,在用Vue.use(插件)时,会执行install函数

我们使用的vue-router就是一个插件,我们一起来实现一个vue-router需要做些什么吧

第一步,下载一个vue-router看看是怎么使用的

下载并引入

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../Home.vue'   // 自己写一个

Vue.use(VueRouter)

const routes = [
	 {
	    path: '/',
	    name: 'Home',
	    component: Home
	 }
 ]
const router = new VueRouter({
  routes
})

export default router

vue-router分为 hash 和 history 两种模式
hash 使用的是windows.onhashchange事件
history 使用的是h5出来的history借口中的popState,pushState外,刷新需要后端配置对应的路由

第二步,分析里面的功能

我们引入的vue-router是什么?
是一个函数,首先要有install方法,被use引入,还需要用new VueRouter这样的方式去调用,同时接收路由参数routes

同时,还需要实现
对于路由跳转 router-link,查看最后渲染出来的,是一个a标签
路由对应的内容渲染,router-view

还需要了解路由的两种形式hash和history
hash主要根据 hashchange 这个事件
history 根据history接口中的popState,pushState

我们先简单的实现一个hash模式

第三步,项目结构

定义一个js文件,定义一个VueRouter,同时在实现install方法

class VueRouter {
	//  监听url变化,响应路由改变渲染对应的内容
}
VueRouter.install = function(_Vue) {
	// 实现router-link,router-view组件
}
export default VueRouter
第四步,依次实现,并验证效果
class VueRouter {
	//  监听url变化,响应路由改变渲染对应的内容
	constructor(options) {
	    this.$options = options
	    this.routeMap = {}
	    
		// 把路由和组件的对应关系找出来
	    this.$options.routes.forEach((route) => {
	      this.routeMap[route.path] = route.component
	
	      if (route.children) {
	        this.getRoute(route.children)
	      }
	    })
	    
    	// 数据响应式 current
   		Vue.util.defineReactive(this, 'current', '')
		window.addEventListener('hashchange', this.onHashChange.bind(this))
	}
  	onHashChange() {
  		this.current = window.location.hash.slice(1) || '/'
  	}
  	getRoute(routess) {
	    routess.forEach((route) => {
	      this.routeMap[route.path] = route.component
	      if (route.children) {
	        this.getRoute(route.children)
	      }
	    })
  }
}
VueRouter.install = function(_Vue) {
	Vue = _Vue
	
//  router的挂载,这样我们后面可以访问到,因为调用use之后,才会 new VueRouter,所以需要在组件创建之前把router挂载在vue上
	Vue.mixin({
		beforeCreate() {
	      if (this.$options.router) {
	        Vue.prototype.$router = this.$options.router
	      }
	    },
	  })
	  
// 实现router-link,router-view组件
	Vue.component('router-link', {
	    props: {
	      to: {
	        type: String,
	        required: true,
	      },
	    },
	    render(h) {
	      return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
	    },
	})
	Vue.component('router-view', {
	    render(h) {
	      // 获取要渲染的组件
	      let component = null
	      let { routeMap, current } = this.$router
	      if (routeMap[current]) {
	        component = routeMap[current]
	      }
	      return h(component)
	    },
	})
}
export default VueRouter
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值