基于 Element 二次封装
前言
之前在网上找过的好多都是基于 vue-cli 2.x 的,而使用 vue-cli 4 的文章比较少,所以我在自己尝试的时候把几篇文章结合了一下,调出来了我想要的模式,也就是 Vue Cli 4 + element-ui + 多个二次封装组件。 最终想要的是 element-ui 这种感觉的,很多组件可以在不同项目中复用。
一. 初始化项目
1. 安装 cli
这里我们使用官方的 vue-cli 初始化一个 Vue 项目
npm install -g @vue/cli
# or
yarn global add @vue/cli
# 创建项目
vue create admin-ui
2. 安装 element-ui
# 此处安装了 element 的指定版本
npm install [email protected]
这里使用官方提供的插件安装:
在插件列表搜索 element
注意:搜索插件下载的时候,Chrome 设置里的语言设置为英文,设置可参考 《Vue UI 可视化窗口修改语言》

在这里我选的手动导入,图中是全部导入

然后在项目中,src 目录下新建一个 plugins 文件夹,新建个 element.js 文件,如果想手动引入,就在这里添加要依赖的组件,这里是为了调试组件:
import Vue from 'vue';
import {
  Button,
  Dialog
} from 'element-ui';
Vue.use(Button);
Vue.use(Dialog);
二. 规划目录结构
1. 调整目录
我们需要一个目录存放文件,一个目录存放示例,按照以下方式对目录进行改造。
.
...
|-- examples // 原 src 目录,改成 examples 用作示例展示
|-- packages // 新增 packages 用于编写存放组件
...
.

2. 配置项目以支持新的目录结构
我们通过上一步的目录改造后,会遇到两个问题
- src 目录更名为 examples,导致项目无法运行
 - 新增 packages 目录,该目录未加入 webpack 编译
 
注:cli3 提供一个可选的
vue.config.js配置文件。如果这个文件存在则他会被自动加载,所有对项目和 webpack 的配置,都在这个文件中。
2.2.1 重新配置入口,修改配置中的 pages 选项
新版 Vue CLI 支持使用 vue.config.js 中的 pages 选项构建一个多页面的应用。
这里使用 pages 修改入口到 examples
/**
 * @Description: vue.config
 */
module.exports = {
  // 修改 src 目录为 examples 目录
  pages: {
    index: {
      entry: 'examples.main.js',
      template: 'public/index.html',
      filename: 'index.html',
    },
  },
};
2.2.2 支持对 packages 目录的处理,修改配置中的 chainWebpack 选项
- packages 是我们新增的一个目录,默认是不被 webpack 处理的,所以需要添加配置对该目录的支持。
 - chainWebpack 是一个函数,会接受一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。
 
/**
 * @Description: vue.config
 */
module.exports = {
  // 修改 src 为 examples
  pages: {
    index: {
      entry: 'examples/main.js',
      template: 'public/index.html',
      filename: 'index.html',
    },
  },
  // 扩展 webpack 配置,使 packages 加入编译
  chainWebpack: (config) => {
    config.module
      .rule('js')
      .include
      .add('packages')
      .end()
      .use('babel')
      .loader('babel-loader')
      .tap((options) => {
        // 修改它的选项...
        return options;
      });
  },
};
三. 编写组件
以上我们已经配置好对新目录框架的支持,接下来我们尝试编写组件。以下我们以一个已经发布到 npm 的小插件作为示例。
创建一个新的组件
- 在 
examples的同级下新建packages目录,在这里添加自己封装要发布的组件。 - 在 
packages目录下,所有的单个组件都以文件夹的形式存储。所以,这里创建一个目录button/ - 在 
button/目录下创建src/目录存储组件源码。 - 在 
button/目录下创建index.js文件对外提供组件的引用。 

修改 /packages/button/index.js 文件,注册单独的该组件,方便使用时可以单独引用:对外提供引用
/**
 * @Description: 对外提供组件引用
 */
// 导入组件,组件必须声明 name
import adminButton from './src/button';
// 为组件提供 install 安装方法,供按需引入
adminButton.install = function (Vue) {
  Vue.component(adminButton.name, adminButton);
};
// 默认导出组件
export default adminButton;
2. 整合所有组件
- 整合所有组件,对外导出,即一个完整的组件库。
 - 修改 
/packages/index.js文件,对整个组件库进行导出 
/**
 * @Description: 整合所有的组件,对外导出,即一个完整的组件库
 */
// 导入组件
import adminButton from './button';
// 存储组件列表
const components = [
  adminButton,
];
// 定义 install 方法,接收 Vue 作为参数。如果使用 use 注册插件,则所有的组件都将被注册
const install = function (Vue) {
  // 判断是否安装
  if (install.installed) return;
  // 遍历注册全局组件
  components.forEach((component) => {
    Vue.component(component.name, component);
  });
};
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
}
// export default暴露出来的组件只能在使用时全局引入。
export default {
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
  install,
  adminButton,
};
// export暴露出来可以在使用时按需引入
export {
  adminButton,
};
四. 编写示例
1. 在示例中导入组件库
import Vue from 'vue';
import ElementUI from 'element-ui';
import App from './App.vue';
import router from './router';
import UI from '../packages/index'; // 导入组件库
import 'element-ui/lib/theme-chalk/index.css'; 
Vue.use(ElementUI);
Vue.use(UI); // 注册组件库
Vue.config.productionTip = false;
new Vue({
  router,
  render: (h) => h(App),
}).$mount('#app');
2. 在示例中使用组件库中的组件
在上一步使用 Vue.use() 全局注册后,即可在任意页面直接使用了,而不需另外引入。当然也可以按需引入
<template>
 <admin-button type="primary">主要按钮</admin-button>
</template>
五. 发布到 npm
到此为止,我们一个完整的组件库已经开发完成了,接下来就是发布到 npm 以供后期使用。
1. 新增编译库命令
在库模式中,Vue 是外置的,这意味着即使在代码中引入了 Vue,打包后的文件也是不包含 Vue 的。
以下我们在 package.json 里的 script 中新增一条命令 npm run lib
--target→ 构建目标,默认为应用模式。这里修改为lib启用库模式。--dest→ 输出目录,默认 dist。这里我们改成lib[entry]→ 最后一个参数为入口文件,默认为src/App.vue。这里我们指定编译packages/组件目录。
"scripts": {
    "lib": "vue-cli-service build --target lib --name vcolorpicker --dest lib packages/index.js",
}
执行编译库命令
npm run lib

2. 配置 npm 发布字段
name、version、description、main、author、private、license
以下为参考设置
main是最重要的,这里的路径要和npm run lib构建出来的目录和文件名对应上。
{
  "name": "admin-ui",
  "version": "0.1.0",
  "description": "基于 Vue + element-ui 的组件库封装",
  "private": false,
  "main": "lib/admin-ui.common.js" 
 }
3. 设置忽略发布文件
添加 .npmignore 文件,设置忽略发布文件
我们发布到 npm 中,只有编译后的 lib 目录、package.json、README.md 才是需要被发布的。所以我们需要设置忽略目录和文件。
和 .gitignore 的语法一样,具体需要提交什么文件,看各自的实际情况。
# 忽略指定文件
.*
*.md
*.yml
*.map
yarn-error.log*
vue.config.js
babel.config.js
# 忽略目录
examples/
packages/
public/
build/
node_modules/
src/
test/
core/
packages/
4. 登录 npm
首先需要到 npm 上注册一个账号,注册过程略。此处为发布到私服 npm
# 使用私有仓库源
nrm use sync
# 登录
npm login
# 执行发布命令
npm publish
六. 快速使用
1. 安装
npm install admin-ui
2. 如何使用
在 main.js 中写入以下内容
import Vue from 'vue';
// element 完整应用
import Element from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(Element);
// admin ui 完整应用
import AdminUi from 'admin-ui';
import 'admin-ui/lib/admin-ui.css';
// admin ui 按需引用
import { adminButton } from 'admin-ui';
Vue.use(adminButton);
Vue.component(adminButton.name, adminButton);
七. 附赠配置例子
{
  "name": "maucash",
  "description": "maucash中常用组件抽取",
  "version": "1.0.2",
  "author": "kuangshp <[email protected]>",
  // 开源协议
  "license": "MIT",
  // 因为组件包是公用的,所以private为false
  "private": false,
  // 配置main结点,如果不配置,我们在其他项目中就不用import XX from '包名'来引用了,只能以包名作为起点来指定相对的路径
  "main": "dist/maucash.js",
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },
  "dependencies": {
    "axios": "^0.18.0",
    "iview": "^2.14.1",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "vue": "^2.5.11"
  },
  // 指定代码所在的仓库地址
  "repository": {
    "type": "git",
    "url": "[email protected]:maucash/maucash.git"
  },
  // 指定打包后,包中存在的文件夹
  "files": [
    "dist",
    "src"
  ],
  // 指定关键词
  "keywords": [
    "vue",
    "maucash",
    "code",
    "maucash code"
  ],
  // 项目官网的地址
  "homepage": "https://github.com/kuangshp/maucash",
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-3": "^6.24.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.7",
    "file-loader": "^1.1.4",
    "node-sass": "^4.5.3",
    "sass-loader": "^6.0.6",
    "vue-loader": "^13.0.5",
    "vue-template-compiler": "^2.4.4",
    "webpack": "^3.6.0",
    "webpack-dev-server": "^2.9.1"
  }
}