vue中组件封装

284 阅读3分钟

之前只是简单的了解了组件开发的过程,今天在本地自己实现了一个。现在记录一下过程。以下过程中使用vue-cli3

创建项目

创建项目的过程中去掉eslint。保留babelrc

vue create elBtn  // elBtn是我的插件名称

修改对应的配置

src中的配置

新建packages文件夹,对应创建button.vue和index.js
button.vue对应的组件的内容

<template>
  <div>
    我是一个button
  </div>
</template>

<script>
export default {
  name: 'el-btn',
}
</script>

<style>

</style>

index.js中的配置

import elBtn from './button'
let components = {elBtn}
const install = function(Vue){
  for(let key in components){
    Vue.component(components[key].name,components[key])
  }
}
// 判断是否直接引入文件,如果是,就不用vue.use
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

// 导出install方法
export default {
  install
}

vue.config.js中的配置

const path = require('path')
module.exports = {
  pages: {
    index: {
      // 修改项目入口文件
      entry: 'src/packages/index.js',
      template: 'public/index.html',
      filename: 'index.html'
    }
  },
  // 扩展webpack配置,使webpages加入编译
  chainWebpack: config => {
    config.module
      .rule('js')
      .include.add(path.resolve(__dirname, 'packages')).end()
      .use('babel')
      .loader('babel-loader')
      .tap(options => {
        return options
      })
  }
}

package.json中的配置

{
  "name": "tst",
  "version": "0.1.0",
  "private": false,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lib": "vue-cli-service build --target lib src/packages/index.js"
  },
  "dependencies": {
    "core-js": "^3.10.1",
    "vue": "^2.6.12"
  },
  // 配置import引入时的路径,若果没有引入,会导致import的时候没有内容,同样在下面本地测试也会有问题-----问题看下面本地测试部分
  "main": "dist/tst.umd.js",
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.5.12",
    "@vue/cli-service": "^4.5.12",
    "vue-template-compiler": "^2.6.12"
  },
   // 指定打包后发布到npm的文件名,没指定则不传,package.json是默认上传的
  "files": [
    "dist",
    "src/packages"
  ],
  "author":{
    "name":"",
    "CSDN":"",
    "github":""
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

本地测试

编译

elBtn目录下执行npm run lib的命令,可以编译对应的dist文件。

tgz包

elBtn目录下执行npm pack的命令,生成对应的tgz包

在其他项目中测试

在测试项目中执行npm install ../elBtn/elBtn-0.1.0.tgz 可以安装elBtn下的内容。和使用npm install 远端的仓库是一个意思,../elBtn/elBtn-0.1.0.tgz是我本地tag所在的目录。其实通过研究发现当我们使用npm install远端的组件时候,也是通过将压缩包下载到.npm文件下然后解压到node-modules的目录下。参考阮一峰老师的文章
然后执行import elBtn from 'elBtn' Vue.use(elBtn)就可以使用组件啦。

可能存在的问题

可能在use的时候出现下面的问题,经过我几个小时的研究发现,在button.vue中export的时候忘记写上name的属性,或者name的属性是空,就会有下面的问题。

Uncaught TypeError: Cannot read property 'toLowerCase' of undefined

发布到npm仓库


1.npm官网注册自己的账号名和密码 
2.npm adduser 使用你的账号和密码邮箱登录、这里npm依赖下载的地址要使用npm官方地址,其他地址会导致登录不成功
3.npm publish 发布,同样npm unpublish 就会对应删除包
4.npm install 就会安装上对应的包

在解决上面可能存在问的问题的时候,深入思考了下install的相关原理

  • 在import对应封装的组件时候,其实返回的是下面的对象

image.png

  • import当前测试项目的注册组件
// button.js
import TopBtn from './button'
TopBtn.install = function (Vue) {
  Vue.component('TopBtn', TopBtn)
}
export default TopBtn

// main.js中引入
import TopBtn from './components/index.js'
Vue.use(TopBtn)

main.js中的topBtn的返回结果 image.png
vue.use的时候,会去找到install方法,将其中的内容注入到vue实例上。

  • use的源码
import { toArray } from '../util/index'

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    // 判断当前的plugin是否注册,已经注册直接返回
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }
    // 没有注册的进行plugin的install
    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this)
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }
}