工作中经常会遇到很多相同的功能开发,这种情况下大家都会有ctrl+c+v,这样会导致大量冗余的代码,有经验的开发者会把它抽成组件,统一封装,如果其它同事也需要呢,那就可以把组件发布到npm上。
使用VUE-CLI3方式开发组件
第一步:创建项目并编写myToast组件
开始编写一个 toast 组件
myToast.vue
创建一个目录myToast,先编写组件内容,具体代码如下:
<template>
<transition name="alert-fade">
<div id="toast"
v-show="visible"
class="dialog-tips dialog-center">
{{message}}
</div>
</transition>
</template>
<script>
export default {
data () {
return {
visible: false,
message: ''
}
}
}
</script>
<style lang="scss" scoped>
.alert-fade-enter-active,
.alert-fade-leave-active {
transition: opacity 0.3s;
}
.alert-fade-enter,
.alert-fade-leave-to {
opacity: 0;
}
.dialog-tips {
position: fixed;
z-index: 100;
min-width: 100px;
padding: 15px;
border-radius: 15px;
white-space: nowrap;
background-color: rgba(0,0,0,1);
box-shadow: 0px 8px 30px 0 rgba(0, 0, 0, 0.363);
text-align: center;
color: #fff;
font-size: 15px
}
.dialog-center {
top: 20%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
index.js
接着编写组件入口文件index.js
import myToast from './myToast.vue'
const toast = {}
toast.install = Vue => {
// 扩展 vue 插件
const ToastCon = Vue.extend(myToast)
const ins = new ToastCon()
// 挂载 dom
ins.$mount(document.createElement('div'))
// 添加到 body 后面
document.body.appendChild(ins.$el)
// 给 vue 原型添加 toast 方法
Vue.prototype.$toast = (msg, duration = 3000) => {
// 我们调用的时候 赋值 message
// 将 visible 设置为 true
// 默认 3s 之后 设置 为 false 关闭 toast
ins.message = msg
ins.visible = true
setTimeout(() => {
ins.visible = false
}, duration)
}
}
export default toast
在该组件中,需要先引入之前的组件文件,并编写插件需要的install方法,在方法中添加$toast方法到vue实例对象上,这样在所有vue实例中都可以调用了。
组件引入
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import toast from './components/myToast'
Vue.use(toast)
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
组件使用
打开views/Home.vue文件,引入全局组件
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<button v-on:click="greet">Greet</button>
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'Home',
components: {
HelloWorld
},
methods: {
greet(){
this.$toast('my toast test!')
}
}
}
</script>
效果如下:
第二步:重构项目 for component build
创建一个项目,之后将 src 目录改成 examples 这样会导致项目跑不起来,为啥是因为 vue-cli3 内置配置了自动回去找 src 文件夹,然后再新建一个 packages 文件夹,这样就把目录准备好了,如图所示
下面解决项目跑不起来的问题,主要在 vue.config.js 配置项目的入口文件
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
// 修改 src 为 examples
pages: {
index: {
entry: "examples/main.js",
template: "public/index.html",
filename: "index.html"
}
},
// 组件样式内联
css: {
extract: false
},
// 扩展 webpack 配置,使 packages 加入编译
chainWebpack: config => {
config.resolve.alias
.set('@', resolve('examples'))
.set('~', resolve('packages'))
config.module
.rule('eslint')
.exclude.add(path.resolve('lib'))
.end()
.exclude.add(path.resolve('examples/docs'))
.end()
config.module
.rule('js')
.include
.add('/packages/')
.end()
.include.add(/examples/)
.end()
.use('babel')
.loader('babel-loader')
.tap(options => {
// 修改它的选项...
return options
})
}
};
注意:这里可以不用把src改名,上面的配置也只需要css内联处理,如下:
// 组件样式内联
css: {
extract: false
}
第三步:配置 package.json
主要是配置包导出入口 main,还有打包成 lib
{
"name": "big-bear-toast",
"version": "0.1.0",
"main": "packages/myToast/index.js",
"scripts": {
"lib": "vue-cli-service build --target lib --name toast --dest lib packages/myToast/index.js",
"serve": "vue-cli-service serve --hot",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"node-sass": "^6.0.0",
"sass-loader": "^10.2.0",
"vue-template-compiler": "^2.6.11"
}
}
vue-cli-service build
Usage: vue-cli-service build [options] [entry|pattern]
Options:
--mode 指定环境模式 (default: production)
--dest 指定输出目录 (default: dist)
--modern 构建两个版本的 js 包:一个面向支持现代浏览器的原生 ES2015+ 包,以及一个针对其他旧浏览器的包。
--target 允许您以项目库或Web组件的形式在项目内部构建任何组件 app | lib | wc | wc-async (default: app) ???
--name lib或者web组件库的名称 (default: "name" in package.json or entry filename)
--no-clean 在构建项目之前不要删除输出目录(dist)
--report 生成report.html以帮助分析包内容
--report-json 生成report.json来帮助分析包内容
--watch 监听 - 当有改变时 自动重新打包~
第四步:在根目录创建packages
在根目录创建packages并把myToast移动到这里,然后把main.js中路径改下,如下
执行打包生成lib
接着把生成的包引入到main.js中,如下npm run lib
第五步:注册npm账号
首先要登录npm官网进行注册
按照上边的要求输入的全名、用户名、邮箱、密码进行注册
输入完成后点击下边的注册就可以创建自己的npm账号成功
值得注意的地方是,如果你的 npm 镜像是 淘宝镜像或者其他的镜像,此时应该切换会 npm
npm install -g cnpm --registry=https://registry.npm.taobao.org
npm config set registry https://registry.npmjs.org
npm config set registry https://registry.npm.taobao.org
第六步:npm 登录及发布
输入命令npm login
如下:
组件发布,在项目根目录执行
npm publish
项目中 package.json 配置了 private: true要改为false或者删除该项目.
发布成功!
组件测试
安装发布的组件
注意:要新建一个工程,不能在原发布工程中install
npm i big-bear-toast
第七步:完善插件说明文档
主要是修改README.md
,大概内容如下:
常见问题收集
接下来就是遇到的问题了,每个问题都包含报错信息,请善用ctrl + f
搜索,下文报错中涉及到自己包名的我都替换为了your-package
。
邮箱未验证
npm ERR! publish Failed PUT 403 npm ERR! code E403 npm ERR! you must verify your email before publishing a new package: https://www.npmjs.com/email-edit : your-package
这个是注册后没有验证邮箱,登录自己邮箱找到对应的邮件确认就好了。注意别选错了,注册 npm 时会发给你两个邮件,我当时就是眼瞎没有看到第二个。如果验证邮件过期的话登录自己的 npm 主页重新发一个就好了。
没有权限发布
npm ERR! publish Failed PUT 403 npm ERR! code E403 npm ERR! You do not have permission to publish "your-package". Are you logged in as the correct user? : your-package
你的包和别人的包重名了,npm 里的包不允许重名,所以去 npm 搜一下,改个没人用的名字就可以了。
需要登录
npm ERR! code ENEEDAUTH npm ERR! need auth auth required for publishing npm ERR! need auth You need to authorize this machine using
npm adduser
后面已经注明了,输入npm adduser
重新登录就可以了,过程和npm login
一样,这个问题在你切换了 npm 源之后或登录过期后都有可能发生。
只有管理员才有权限发布
npm ERR! publish Failed PUT 403 npm ERR! code E403 npm ERR! [no_perms] Private mode enable, only admin can publish this module [no_perms] Private mode enable, only admin can publish this module: your-package
这个是你的源设置成第三方源的时候才有可能发生,比如设置了淘宝源就可能会导致该问题。只要把源改回默认的就可以了,如下:
npm config set registry http://registry.npmjs.org
包名过于类似
npm ERR! publish Failed PUT 403 npm ERR! code E403 npm ERR! Package name too similar to existing packages; try renaming your package to '@hopgoldy/auto-git' and publishing with 'npm publish --access=public' instead : your-package
如果npm上已经有了不少和你的包名类似的包,就会出现这个问题,在package.json
中修改你的包名就可以了
无法发布到私有包
npm ERR! publish Failed PUT 402 npm ERR! code E402 npm ERR! You must sign up for private packages :
这个当你的包名为@your-name/your-package
时才会出现,原因是当包名以@your-name
开头时,npm publish
会默认发布为私有包,但是 npm 的私有包需要付费,所以需要添加如下参数进行发布:
npm publish --access public