手把手教你如何写vue.js的插件,跨项目依赖。学不会你来打我!

前言

  • 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.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,468评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,620评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,427评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,160评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,197评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,334评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,775评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,444评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,628评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,459评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,508评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,210评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,767评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,850评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,076评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,627评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,196评论 2 341