前言
- vue.js作为前端三大框架之一,它的快速开发特点深受开发者的喜爱。通常,我们使用vue.js会集成Router、Axios、Vuex、Element-UI等插件,那么你知道它们是如何无缝对接vue.js的吗?接下来,我们参考Router插件无缝对接vue.js的原理来手动开发一个插件,并以npm的方式导入项目中。你准备好了吗?(ps:接下来的内容,你需要有ES6语法基础、Vue.js插件,混入,组件,指令相关知识点才能看懂)
一、vue-router集成vue.js的原理
- 我们知道,在使用vue-cli2.0脚手架搭建vue.js项目时,它支持Router的选项,如下所示:
当我们输入Y时,Router插件就在项目中生效了。如果我们要添加路由,直接修改router/index.js文件即可,如下所示(为HelloWorld页面再添加一个路由):
毋庸置疑,在使用vue-cli2.0脚手架搭建项目时,针对于Router这个插件内部肯定做了很多事,今天咱们不深究到底做了哪些事,咱们来探究下main.js的内容:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
// 这里用了ES6的简便语法,
// 实际为: router: router, 当key和value的名称一致时,可以省略冒号
router,
components: { App },
template: '<App/>'
})
有一个可疑点,就是在传入new Vue() 构造方法的参数中,为什么添加了router,难道这样就能无缝集成vue.js了吗?我们不得而知,但是从官网插件部分内容来看[点击查看],还需要使用类似Vue.use(router)
的代码来将路由集成至vue.js中。那么,这段代码是在哪里被执行的呢?我们从main.js中开始看,可以看到这么一段代码:
import router from './router'
于是我们定位至router文件夹中去,发现内部存在一个index.js文件,其内部就是我们定义路由的内容:
其中,我们很容易发现,内部执行了这么一段代码:
Vue.use(Router)
突然发现,好像是符合官网的规则。那为什么还需要在main.js中的new Vue()
有参构造方法中传入router呢?这里又涉及到了Vue.js的全局混入的知识点[点击查看]
根据全局混入知识点可知,它有缺点:每当创建一个Vue实例时,都会进行混入。白话来讲就是:每创建一个Vue实例,都会调用上图的created钩子函数。从上述图中的代码来看,console.log(myOption)
这行代码的执行是有条件的,只有当前vue实例的$options对象中的myOption属性为true才能正常执行。那么我们是不是可以大致猜测下:router插件集成vue.js的原因就是基于插件 + 混入来实现的? 可以自己做个实验:把main.js中Vue的构造方法中的router删除后,看项目还是否能够正常路由至HelloWorld页面?
二、如何自定义插件
- 可以细看官网demo。说实话,vue.js官网真的很nice,基本上所有vue.js的功能都可以在官网中找到demo(读到这里的你,是否发觉官网的重要性了呢?)。现在,咱们直接利用官网的demo,来实现一个插件,包含如下功能:
1.拥有一个SayHi组件,其中拥有一个叫content的props,默认值为avengerEug。
实现的功能 :在浏览器中渲染出: Hi {{ content }} (其中content为默认值或传入的值)
2.拥有一个avenger-eug的指令,传入一个字体的style颜色样式
实现的功能:当传入red时,标签中的字体颜色变成红色
3.拥有一个全局弹框方法
实现的功能:当我们执行this.$myMessage('Hello')时,会在页面弹出一个alert框,且内容为Hello
实现步骤
第一:创建如下图所示的目录结构:
- 第二:在src/myPlugin/index.js文件中填充如下内容:
export default {
install: (Vue) => {
Vue.mixin({
created: function () {
// 当在vue的构造方法中,存在avengerEug这个key时,就会
// 创建全局组件、指令和方法
if (this.$options.avengerEug) {
Vue.prototype.$myMessage = function (params) {
window.alert(params)
}
Vue.component('SayHi', {
template: '<h1> Hi {{ content }} </h1>',
props: {
content: {
type: String,
default: () => { return 'avengerEug' }
}
},
created() {
console.log('调用了SayHi组件的created钩子函数')
}
})
Vue.directive('avenger-eug', {
bind(el, binding, vnode, oldVnode) {
if (binding.value) {
el.style.color = binding.value
}
}
})
}
}
})
}
}
- 第三:在main.js中添加如下代码:
- 第四:校验:
由上可知,我们使用插件 + 混入的方式将自己写的插件给集成到了当前项目中了。这里提一句:为什么我们写的组件、指令、方法都能在其他组件中不需要注册而直接使用呢?还记得官网中对插件
章节的描述么?它要求第一个参数为Vue对象,而且必须要在new Vue代码之前执行Vue.use相关的代码。那只有一个说法能够说明,那就是在执行new Vue构造方式时,内部对所有的插件进行了遍历,并把自己作为参数,调用每个插件的install方法,而此时的this就是全局Vue对象。 可能有人会问:我想把我的插件发布至npm中,后续其他项目直接使用npm install my-plugin时就能把上述的三个功能给加到项目中去,那该怎么办?咱们继续往下看。
三、如何跨项目依赖自己的插件
在第二章中,我们实现了自定义的插件,并且集成到当前项目中去了。那么要如何跨项目依赖自己编写的插件呢?这里就需要把自己的插件打成包发布至npm中去了。不急,咱们来搞定它!
-
步骤如下:
1.使用vuecli2.0脚手架搭建简单版本vue.js项目(防止插件依赖过多的类库)
# 注意,项目名必须唯一,不然在发布时会报403错误,npm认为你要更新别人的插件
# 但是发现不是同一个人,所以会报无权限
vue init webpack-simple my-plugin-avenger
ps: 上述的项目名为my-plugin-avenger,先记住它,后续我们在npm install 和 import都需要用到它。
2.编写自定义插件,为了方便,我直接copy第二章创建插件的代码,最终内容如下所示:
3.创建src/index.js文件(为了将插件打包),如下所示:
4.修改webpack.config.js文件
// 对应的修改内容如下:
module.exports = {
entry: './src/index.js',
output: {
// 模块名, 其他类库使用require的方式引用的原因就是配置了这个
library: 'my-plugin-avenger',
// libraryTarget会生成不同umd的代码,可以只是commonjs标准的,也可以是指amd标准的,也可以只是通过script标签引入的
libraryTarget: 'umd',
umdNamedDefine: true, // 会对 UMD 的构建过程中的 AMD 模块进行命名。否则就使用匿名的 define
// 后面内容省略
},
// 后面内容省略
}
> 5.修改package.json文件,指定插件入口
// 修改如下配置。因为需要发布, 因此需要将这个字段改为 false
`"private": false, `
// 新增如下配置。当在第三方使用类库, 使用 import MyPluginAvenger from 'my-plugin-avenger'时, 会根据插件的package.json的main入口找文件
"main": "dist/build.js",
6.执行npm install引入依赖
7.执行npm run build打包
8.自己在npm中注册账号(若已有账号,此步骤忽略)
>9.设置`npm config set registry http://registry.npmjs.org/`命令配置npm源
>10.执行` npm adduser `命令绑定账号,输入如下信息:
**Username: your name
Password: your password
Email: yourmail**
11.更新项目中的README.md文件内容,描述该插件
有何用,如何使用
(当在npm官网查找插件时,可以看到)。本人图方便,未更改。
12.执行
npm publish
命令发布npm包
13.npm官网查看发布的插件
14.跨项目依赖,在项目中执行:npm i my-plugin-avenger
15.在项目的main.js中加入如下代码:
import MyPluginAvenger from 'my-plugin-avenger'
Vue.use(MyPluginAvenger)
// 并在vue构造器中添加avengerEug: true
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>',
avengerEug: true
})
16.在任意页面使用第二章所说的组件、指令和全局函数,
你会发现,成功了!
四、总结
- 在npm发布的过程中,会出现一些其他错误,如下:
错误 | 原因 |
---|---|
no_perms Private mode enable, only admin can publish this module | 默认镜像非官方的, 需要重新设置.命令: npm config set registry http://registry.npmjs.org |
npm publish failed put 500 unexpected status code 401 | 没有登录,需要登录: npm login 即可 |
npm ERR! you do not have permission to publish "your module name". Are you logged in as the correct user? | 包名被占用, 需要重新命名. 命名之前最好先去npm官网查看包名是否被占用 |
You cannot publish over the previously published versions | 每次发布时需要更新版本, 修改package.json文件的version字段即可. |
npm publish时经常报403 | 可以确认下注册的账号是否在邮箱中验证完毕,或确认发布的项目名是否唯一 |
- I am a slow walker, but I never walk backwards.