-
29
12月背景
当前项目为vue 2.6 + element-ui 2.14.1, 我们需要开发一个类似表格的表单组件, 可以看到除了表格样式以外,我们还需要嵌套各种表单组件,而组件功能基本与框架功能一致,如果对每个组件都做独立开发,显然是不现实的。所以我们的目标一定是尽量使用原组件
方案一: 使用容器组件或自定义类名, 覆盖原组件样式。
方案二:将element拉到本地,做二次开发
这里我们选择了第二种。
概况
因为项目依赖,所以我们这里拉取的是 element-ui 2.14.1, 如需要其他版本 切换不同的 tag 标签分支即可。
命令
二次开发前我们需要先将项目跑起来,所以需要了解基础的命令
"scripts": { // 包安装 "bootstrap": "yarn || npm i", // 文件构建相关 "build:file": "node build/bin/iconInit.js & node build/bin/build-entry.js & node build/bin/i18n.js & node build/bin/version.js", "build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk", "build:utils": "cross-env BABEL\_ENV=utils babel src --out-dir lib --ignore src/index.js", "build:umd": "node build/bin/build-locale.js", // 清除打包文件 "clean": "rimraf lib && rimraf packages/\*/lib && rimraf test/\*\*/coverage", "deploy:build": "npm run build:file && cross-env NODE\_ENV=production webpack --config build/webpack.demo.js && echo element.eleme.io>>examples/element-ui/CNAME", "deploy:extension": "cross-env NODE\_ENV=production webpack --config build/webpack.extension.js", // 扩展开发 "dev:extension": "rimraf examples/extension/dist && cross-env NODE\_ENV=development webpack --watch --config build/webpack.extension.js", // 组件开发 "dev": "npm run bootstrap && npm run build:file && cross-env NODE\_ENV=development webpack-dev-server --config build/webpack.demo.js & node build/bin/template.js", "dev:play": "npm run build:file && cross-env NODE\_ENV=development PLAY\_ENV=true webpack-dev-server --config build/webpack.demo.js", // 组件打包, 将在本地生成 lib/ 目录 "dist": "npm run clean && npm run build:file && npm run lint && webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js && npm run build:utils && npm run build:umd && npm run build:theme", // 多语言包 "i18n": "node build/bin/i18n.js", "lint": "eslint src/\*\*/\* test/\*\*/\* packages/\*\*/\* build/\*\*/\* --quiet", // 发布,(用不到) "pub": "npm run bootstrap && sh build/git-release.sh && sh build/release.sh && node build/bin/gen-indices.js && sh build/deploy-faas.sh", "test": "npm run lint && npm run build:theme && cross-env CI\_ENV=/dev/ BABEL\_ENV=test karma start test/unit/karma.conf.js --single-run", "test:watch": "npm run build:theme && cross-env BABEL\_ENV=test karma start test/unit/karma.conf.js" },
这里我们一般只用到了,
dev
dist
以及后面我们一个自定命令。项目目录
root/
program/
element-ui/
element目录概览
build/ 构建配置 | 构建脚本
examples/ 文档, 组件用例
src/ 项目源码| 项目入口
packages/ 组件源码
types/ ts类型定义
这里主要关注 examples/, packages/ , 这与我们开发直接相关。
examples/
这里其实是个vue项目,
dev
将运行该工程。examples/
zh-CN/ 中文包
en-US/ 英文包
.... 其他语言包
docs/ 组件文档 | 组件用例
pages/ 页面模板
i18n/ 国际化
components/ 页面公共组件
extension/ 扩展
entry.js 项目入口
nav.config.json 导航配置
router.config.js vue 路由加载器
packages/
这里是我们编写组件的地方,所以组件都以独立目录包的形式存在,方便按需加载。
约定
每个包遵守基础的包结构
\- package - index.js 导出入口 - src/ 源
样式文件
看过组件包后, 会发现包内是不包含样式文件的,样式文件放在了
/packages/theme-chalk/
目录下。 所以其实 element-ui 的样式作为独立的主题包存在。开发自定组件
这里我们以
row
为例子,通过在源组件基础上修改一个自己的新组件z-row
。新建组件目录
// 拷贝row 目录 并重命名为 z-rowmv row - 副本 z-row// 修改组件导出// index.jsimport ZRow from './src/z-row';/\* istanbul ignore next \*/ZRow.install = function(Vue) { Vue.component(ZRow.name, ZRow);};export default ZRow;// 修改源文件名// z-row/src/z-row
修改组件
export default { name: 'ZRow', componentName: 'ZRow', // 修改组件名 props: { tag: { type: String, default: 'div' }, gutter: Number, type: String, justify: { type: String, default: 'start' }, align: { type: String, default: 'top' } }, computed: { style() { const ret = {}; if (this.gutter) { ret.marginLeft = \`-${this.gutter / 2}px\`; ret.marginRight = ret.marginLeft; } return ret; } }, render(h) { return h(this.tag, { class: \[ 'z-row', // 将源 el-row 类名 替换为 z-row, 并替换其他 el- 前缀 this.justify !== 'start' ? \`is-justify-${this.justify}\` : '', this.align !== 'top' ? \`is-align-${this.align}\` : '', { 'z-row--flex': this.type === 'flex' } \], style: this.style }, this.$slots.default);
修改样式
// 进入/packages/theme-chalk/src// copy row.sccs 并更名为 z-row.sccs// 修改样式@import "common/var";@import "mixins/mixins";@import "mixins/utils";// zb 为自定义组件前缀添加器, 具体的实现可以参考 mixins/mixings 的 @mixin b@include zb(row) { // 生成类名 .z-row position: relative; box-sizing: border-box; border: 1px solid #E5E5E5; align-items: stretch; & + &{ border-top: 0; } @include utils-clearfix; @include m(flex) { display: flex; &:before, &:after { display: none; } @include when(justify-center) { justify-content: center; } @include when(justify-end) { justify-content: flex-end; } @include when(justify-space-between) { justify-content: space-between; } @include when(justify-space-around) { justify-content: space-around; } @include when(align-middle) { align-items: stretch; } @include when(align-bottom) { align-items: flex-end; } }
注册组件
打开根目录下的
components.json
{ // 添加新组件 "z-row": "./packages/z-row/index.js", ...}
编写文档/用例
新增文档
// /examples/docs/zh-CN/ 新增 z-layout.md## z-layout 布局 ## 基础使用 \`\`\`html// 编写组件用例<z-row> <z-col :span="24"><div class="grid-content bg-purple-dark"> content </div></z-col></z-row>\`\`\`
注册路由
// examples/nav.config.json// 在组件列表下新增目录配置 { "groupName": "z-ui", "list": \[ { "path": "/z-layout", "title": "z-layout| z-row | z-col" } \] },
运行用例
yarn dev```这样我们就可以看到element-ui 组件目录下新增了我们的自定义组件, 这里是支持热更新的,修改文档的同时,内容也将即时显示。 ## 打包 这里我们希望依然以elemnt官方的方式使用本地的魔改包, 只是添加注册新增的自定义组件。开始使用了`lerna` 但是存在命名冲突的问题, lerna无法通过包名判断安装的是本地包还是线上包,如果只修改package.json 的 elemnt包名,将导致无法正常导入组件的问题, 因为还需要修改打包的配置,这样会比较的麻烦。 所以使用了hack方法, 直接替换项目下 node\_modules 内的 element-ui 文件, 其他也可以直接就在项目下引入已经构建好的 elemnt-ui 打包文件。 ### 生成lib ```javascript yarn dist // 生成
迁移脚本
每次打包后,导出新的包文件会很麻烦,所以可以使用gulp将打包后的文件导入到项目中.
const { series, src, dest } = require('gulp');const packageJson = require('../package.json')const path = require('path')const resolve = \_path => path.resolve(\_\_dirname, \_path)const move = (from, to) => cb => { src(from) .pipe(dest(to)) cb()}const buildTask = (files, target) => files.map(source => { const from = resolve(\`../${source}/\*\*/\*\`) const to = resolve(\`../${target}/${source}/\`) return move(from, to)})function trucks(){ console.log(packageJson.files) const task = buildTask(packageJson.files, packageJson.moveTarger) console.log(task) return series(...task)}module.exports.default = tr