前言
- vue.js作為前端三大框架之一,它的快速開發(fā)特點深受開發(fā)者的喜愛。通常,我們使用vue.js會集成Router、Axios、Vuex、Element-UI等插件,那么你知道它們是如何無縫對接vue.js的嗎?接下來,我們參考Router插件無縫對接vue.js的原理來手動開發(fā)一個插件,并以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() 構造方法的參數(shù)中,為什么添加了router,難道這樣就能無縫集成vue.js了嗎?我們不得而知,但是從官網(wǎng)插件部分內容來看[點擊查看],還需要使用類似Vue.use(router)的代碼來將路由集成至vue.js中。那么,這段代碼是在哪里被執(zhí)行的呢?我們從main.js中開始看,可以看到這么一段代碼:
import router from './router'
于是我們定位至router文件夾中去,發(fā)現(xiàn)內部存在一個index.js文件,其內部就是我們定義路由的內容:
其中,我們很容易發(fā)現(xiàn),內部執(zhí)行了這么一段代碼:
Vue.use(Router)
突然發(fā)現(xiàn),好像是符合官網(wǎng)的規(guī)則。那為什么還需要在main.js中的new Vue()有參構造方法中傳入router呢?這里又涉及到了Vue.js的全局混入的知識點[點擊查看]
根據(jù)全局混入知識點可知,它有缺點:每當創(chuàng)建一個Vue實例時,都會進行混入。白話來講就是:每創(chuàng)建一個Vue實例,都會調用上圖的created鉤子函數(shù)。從上述圖中的代碼來看,console.log(myOption)這行代碼的執(zhí)行是有條件的,只有當前vue實例的$options對象中的myOption屬性為true才能正常執(zhí)行。那么我們是不是可以大致猜測下:router插件集成vue.js的原因就是基于插件 + 混入來實現(xiàn)的? 可以自己做個實驗:把main.js中Vue的構造方法中的router刪除后,看項目還是否能夠正常路由至HelloWorld頁面?
二、如何自定義插件
- 可以細看官網(wǎng)demo。說實話,vue.js官網(wǎng)真的很nice,基本上所有vue.js的功能都可以在官網(wǎng)中找到demo(讀到這里的你,是否發(fā)覺官網(wǎng)的重要性了呢?)?,F(xiàn)在,咱們直接利用官網(wǎng)的demo,來實現(xiàn)一個插件,包含如下功能:
1.擁有一個SayHi組件,其中擁有一個叫content的props,默認值為avengerEug。
實現(xiàn)的功能 :在瀏覽器中渲染出: Hi {{ content }} (其中content為默認值或傳入的值)
2.擁有一個avenger-eug的指令,傳入一個字體的style顏色樣式
實現(xiàn)的功能:當傳入red時,標簽中的字體顏色變成紅色
3.擁有一個全局彈框方法
實現(xiàn)的功能:當我們執(zhí)行this.$myMessage('Hello')時,會在頁面彈出一個alert框,且內容為Hello
實現(xiàn)步驟
第一:創(chuàng)建如下圖所示的目錄結構:

- 第二:在src/myPlugin/index.js文件中填充如下內容:
export default {
install: (Vue) => {
Vue.mixin({
created: function () {
// 當在vue的構造方法中,存在avengerEug這個key時,就會
// 創(chuàng)建全局組件、指令和方法
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鉤子函數(shù)')
}
})
Vue.directive('avenger-eug', {
bind(el, binding, vnode, oldVnode) {
if (binding.value) {
el.style.color = binding.value
}
}
})
}
}
})
}
}
- 第三:在main.js中添加如下代碼:
- 第四:校驗:
由上可知,我們使用插件 + 混入的方式將自己寫的插件給集成到了當前項目中了。這里提一句:為什么我們寫的組件、指令、方法都能在其他組件中不需要注冊而直接使用呢?還記得官網(wǎng)中對插件章節(jié)的描述么?它要求第一個參數(shù)為Vue對象,而且必須要在new Vue代碼之前執(zhí)行Vue.use相關的代碼。那只有一個說法能夠說明,那就是在執(zhí)行new Vue構造方式時,內部對所有的插件進行了遍歷,并把自己作為參數(shù),調用每個插件的install方法,而此時的this就是全局Vue對象。 可能有人會問:我想把我的插件發(fā)布至npm中,后續(xù)其他項目直接使用npm install my-plugin時就能把上述的三個功能給加到項目中去,那該怎么辦?咱們繼續(xù)往下看。
三、如何跨項目依賴自己的插件
在第二章中,我們實現(xiàn)了自定義的插件,并且集成到當前項目中去了。那么要如何跨項目依賴自己編寫的插件呢?這里就需要把自己的插件打成包發(fā)布至npm中去了。不急,咱們來搞定它!
-
步驟如下:
1.使用vuecli2.0腳手架搭建簡單版本vue.js項目(防止插件依賴過多的類庫)
# 注意,項目名必須唯一,不然在發(fā)布時會報403錯誤,npm認為你要更新別人的插件
# 但是發(fā)現(xiàn)不是同一個人,所以會報無權限
vue init webpack-simple my-plugin-avenger
ps: 上述的項目名為my-plugin-avenger,先記住它,后續(xù)我們在npm install 和 import都需要用到它。
2.編寫自定義插件,為了方便,我直接copy第二章創(chuàng)建插件的代碼,最終內容如下所示:
3.創(chuàng)建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文件,指定插件入口
// 修改如下配置。因為需要發(fā)布, 因此需要將這個字段改為 false
`"private": false, `
// 新增如下配置。當在第三方使用類庫, 使用 import MyPluginAvenger from 'my-plugin-avenger'時, 會根據(jù)插件的package.json的main入口找文件
"main": "dist/build.js",
6.執(zhí)行npm install引入依賴
7.執(zhí)行npm run build打包
8.自己在npm中注冊賬號(若已有賬號,此步驟忽略)
>9.設置`npm config set registry http://registry.npmjs.org/`命令配置npm源
>10.執(zhí)行` npm adduser `命令綁定賬號,輸入如下信息:
**Username: your name
Password: your password
Email: yourmail**
11.更新項目中的README.md文件內容,描述該插件
有何用,如何使用(當在npm官網(wǎng)查找插件時,可以看到)。本人圖方便,未更改。
12.執(zhí)行
npm publish命令發(fā)布npm包
13.npm官網(wǎng)查看發(fā)布的插件
14.跨項目依賴,在項目中執(zhí)行: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.在任意頁面使用第二章所說的組件、指令和全局函數(shù),
你會發(fā)現(xiàn),成功了!
四、總結
- 在npm發(fā)布的過程中,會出現(xiàn)一些其他錯誤,如下:
| 錯誤 | 原因 |
|---|---|
| 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官網(wǎng)查看包名是否被占用 |
| You cannot publish over the previously published versions | 每次發(fā)布時需要更新版本, 修改package.json文件的version字段即可. |
| npm publish時經(jīng)常報403 | 可以確認下注冊的賬號是否在郵箱中驗證完畢,或確認發(fā)布的項目名是否唯一 |
- I am a slow walker, but I never walk backwards.