自定义一个Vue组件并发布成npm 包

3,510 阅读3分钟

文件

VueCheckbox.vue

<template lang="html">
  <div>
    <input
      v-bind="$attrs"
      :checked="isChecked || $attrs.checked"
      :value="value"
      type="checkbox"
      v-on="listeners">

    <span>
      <slot/>
    </span>

  </div>
</template>

<script>
export default {
  name:'VueCheckbox',
  inheritAttrs: false,
  props:{
    value:{},
    bridgeValue:{
      type:[Boolean,Array,String,Number,Object],
      default:false
    }
  },
  computed:{
    listeners() {
      return {
        // ...this.$listeners,
        change: (evt) => {
          this.change(evt)
        }
      }
    },
    isChecked() {
      return Array.isArray(this.value) ? this.value.includes(this.bridgeValue) : this.value
    }
  },
  methods:{
    change(evt){
      if(Array.isArray(this.value)){

          // Copy Array
          const value = this.value.slice(0)
          if(this.value.includes(this.bridgeValue)){
            value.splice(value.indexOf(this.bridgeValue),1)
            this.$emit('input', value)
            this.$emit('change', value)
          } else {
            value.push(this.bridgeValue)
            this.$emit('input', value)
            this.$emit('change', value)
          }

      } else if (typeof(this.bridgeValue) == 'string' ) {

          if(this.value == this.bridgeValue){
            this.$emit('input', null)
            this.$emit('change', null)
          } else {
            this.$emit('input', this.bridgeValue)
            this.$emit('change', this.bridgeValue)
          }

      }
      else {
        this.$emit('input', !this.value)
        this.$emit('change',evt)
      }

    }
  }
}
</script>

vueCheckbox.js

import component from './VueCheckbox.vue'

function install (Vue) {
  Vue.component(component.name, component)
}

export default  install

编译前测试

指令

vue serve .\test.vue

文件 test.vue

<template lang="html">
  <div>
    <div>
      {{form.checked}}
    </div>
    <ul>
    <li v-for="(item, index) in options" :key="index">
      <vue-checkbox v-model="form.checked" :bridgeValue="item" >{{ item.name }}</vue-checkbox>
    </li>
    </ul>
  </div>
</template>

<script>
import VueCheckbox from 'VueCheckbox'
export default {
  data: () => ({
    form: {
      checked: []
    },
    options: [
      { id: 1, name: 'A' },
      { id: 2, name: 'B' },
      { id: 3, name: 'C' },
    ]
  }),
  components:{
    VueCheckbox
  }
}
</script>

编译入口

#\index.js   ## example-1
//default导出。整体以插件形式导出
import VueCheckbox from './vueCheckbox.js'

function install(Vue)  {
 //如果是多个component可以将以下use过程写在for循环
  Vue.use(VueCheckbox)
}

//浏览器环境,打包成umd方式
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

export default install

//以上由于是单组件 不考虑打包成umd方式时可以简写为以下形式
//export  { default } from './vueCheckbox.js'
#\index.js   ## example-2
//named导出,可以做到按需导入
export { default as VueCheckbox } from './vueCheckbox.js'

  
// import VueCheckbox from './vueCheckbox.js'
// export {  VueCheckbox }
#\index.js   ## example-3
//只有一个组件,default导出,不以插件形式,使用时使用Vue.component进行全局注册或者使用组件的components选项加载组件
import VueCheckbox from './VueCheckbox.vue'
export default VueCheckbox;
if (typeof window !== 'undefined' && window.Vue) {
    Vue.component(VueCheckbox.name, VueCheckbox)
}

编译指令

vue build -t lib .\index.js --name vuecheckbox 

打包

使用npm pack指令 其中package.json中要指明主入口main
文件package.json

{
  "name": "VueCheckbox",
  "version": "1.0.0",
  "description": "",
  "main": "dist/vuecheckbox.common.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

使用测试

umd方式测试

demo.html

<meta charset="utf-8">
<title>demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="./vuecheckbox.umd.js"></script>

<div id="app">
  <div>
    <div>
      {{form.checked}}
    </div>
    <ul>
    <li v-for="(item, index) in options" :key="index">
      <vue-checkbox v-model="form.checked" :bridge-value="item" >{{ item.name }}</vue-checkbox>
    </li>
    </ul>
  </div>
</div>
<script>
 
var app= new Vue({
  el: '#app',
  data: {
    form: {
      checked: []
    },
    options: [
      { id: 1, name: 'A' },
      { id: 2, name: 'B' },
      { id: 3, name: 'C' },
    ]
  }
})
</script>

node下的CommonJS环境测试

使用vue ui创建使用的项目,测试文件参考上文中的test.vue

方式一

lerna 多项目仓库 (monorepo)

方式二

npm pack 打包成后Vuecheckbox-xxx.tgz再到使用的项目中npm install VueCheckbox-xxx.tgz 注意使用npm version patch更新版本号

方式三

npm pack 打包时将源文件也打包到Vuecheckbox-xxx.tgz再到使用的项目中npm install 然后修改node_modules\VueCheckbox源文件重复build过程进行调试

使用方式

对于example-1,使用方式为

import Vue from 'vue'
import VueCheckbox from 'VueCheckbox'

Vue.use(VueCheckbox)

对于example-2,使用方式为

import Vue from 'vue'
import {VueCheckbox} from 'VueCheckbox'

Vue.use(VueCheckbox)

对于example-3,使用方式为

##全局
import VueCheckbox from 'VueCheckbox'
Vue.component('VueCheckbox',VueCheckbox);
##局部注册
import VueCheckbox from 'VueCheckbox'
export default {
 ...
 components:{
    VueCheckbox
  }
}

npm包发布

略...请参考安稳-学习系列:一分钟教你发布npm包
我发布的示例

参考

  1. 深入解析ES Module(一):禁用export default object
  2. 深入解析ES Module(二):彻底禁用default export
  3. ES Module export
  4. CommonJS Module export
  5. vuejs-Vue.use( plugin )
  6. Vue CLI-构建目标
  7. 如何用 Vue-CLI 3 打包 npm 包
  8. 使用npm发布一个vue组件