前端组件库(Element UI)的实现原理:教你如何实现自定义组件库,并打包发布至npm

前言

对Vue组件开发有一定了解,对UI组件库的实现比较感兴趣,想要理解其开发原理,这篇文章可以帮助你实现并发布自己的第一个自定义插件。

Demo地址

建议将demo拉取至本地,结合代码更容易理解:
git地址:https://github.com/Yuwenbinjie/ywbj-ui.git

git clone git@github.com:Yuwenbinjie/ywbj-ui.git
cd ywbj-ui/
npm i
npm run dev

一. 组件库开发流程

1)新建vue项目:

文件目录如下图

.
├── dist # 压缩后文件目录
├── site # 项目结构目录
│   ├── App.vue # 单页应用父组件 
│   └── main.js # 单页应用启动入口文件
├── src # 开发目录
│   ├── assets # 静态文件:scss/image
│   ├── components # 存放公共组件库
│   ├── index.js # 全局注册组件插件
│   └── style.js # 导入scss
├── index.html
├── package.json # 依赖管理
├── webpack.dev.js #项目启动配置文件:npm run dev
├── webpack.config.js #项目打包配置文件:npm run build
└── README.md #README

2)编写自定义组件,封装成插件:

业务组件和功能组件的主要区别

  • slot插槽占位符,可以实现父子组件传参,父组件templet模版可将子组件slot内容替换。当slot未命名时将父组件全部替换,当定义name时,可以实现父组件对子组件的指定位置显示内容或传参;
<div :class="preCls+'-title'" v-show="showTitle">
   <slot name="modal-title">自定义标题</slot>
</div>
<div :class="preCls+'-body'" v-show="showBody">
    <slot name="modal-body">自定义内容</slot>
</div>
  • 定义多个className时,可以将其class作为属性放入对象中,根据是否传入props参数进行判断;
classBtn() {
  let {preCls, type, size, shape} = this
  let className = [
      `${preCls}`,
      {
          [`${preCls}-${type}`]: !!type,
          [`${preCls}-${size}`]: !!size,
          [`${preCls}-${shape}`]: !!shape,
      },
  ]
  return className
}
  • props自定义验证,当没有遵循传入规则时需要对其进行一个预先检查,validator可以通过自定义函数对传入的参数进行校验;
type: {
    type: String,
    default: 'default',//['default',success', 'warning', 'error', 'info']
    validator(value) {
        let types = ['default','success', 'warning', 'error', 'info']
        return types.includes(value) || !value
    }
},
  • 在src/index.js来封装组件,该文件即是webpack配置的入口文件,install是挂载组件的方法,有了它就可以在外部引用并Vue.use一个插件了;
import * as components from './components'
var VuePlugin = {}
VuePlugin.install = function(Vue, options) {
    for(let component in components) {
        Vue.component('yw'+component, components[component]);
    }
}
export default VuePlugin

此时,你已经在本地成功创建好了一个组件库插件,在本地main.js中引入插件和css文件import '@/assets/index.scss', import YwVue from '@'并注册使用Vue.use(YwVue)即可在项目中查看自定义的组件效果。以下步骤将你的插件打包并发布到npm:

3)修改配置项

webpack.config.js:

  • 将src中的index作为入口文件,出口文件(yw.js)必须与pakage.json中的main相同;
 entry: {
   style: './src/style.js',
   yw: './src/index.js',
 },
 output: {
   path: path.resolve(__dirname, './dist'),
   publicPath: '/dist/',
   filename: '[name].js',
   library: 'Yw',
   libraryTarget: 'umd'
 },
  • 通过extract-text-webpack-plugin插件将scss单独打包(yw.css),便于外部引用;
{
     test: /\.scss$/,
     use: ExtractTextPlugin.extract({
        fallback: 'vue-style-loader',
        use: ['css-loader', 'sass-loader']
      })
},
module.exports.plugins = (module.exports.plugins || []).concat([
   new ExtractTextPlugin("yw.css",{allChunks: true}),
   ......
])

pakage.json:

  • main结点是打包后的快捷路径(yw-ui),可以直接引用,无需指定相对的路径(yw-ui/dist/yw.js);
  • 开源协议license为"MIT";
  • 将private设为false组件即可公用;
{
    "name": "ywbj-ui", //包名,npm install ****
    "description": "A components of pc base on vue2.X",
    "version": "1.0.1", //每次打包上传,必须更新版本号
    "author": "yourName <****@**.com>", //输入你的信息和邮箱
    "main": "dist/yw.js", //必须和webpack打包的出口文件名一致
    "license": "MIT", //开源协议
    "private": false, //true为私有,false为公共
}
  • 配置完成后执行npm run build,生成打包文件夹dist;


    dist目录

4)发布到npm

  • 首先在npm官网(https://www.npmjs.com/)注册用户;
  • 将本地npm源设置为https://registry.npmjs.org/ (若为淘宝源则登陆不成功);
  • 进入项目文件夹,执行npm login会要求你输入用户名、密码和邮箱;
  • npm publish将打包后的文件发布到npm,成功后可在官网搜到包名(注意:每次publish之前需要更新pakage.json中的版本号,否则上传不成功);


    包已经上传至npm

二. 安装使用自己的插件

#安装插件
npm install ywbj-ui --save
 
#引入项目中
import YwUI from 'ywbj-ui'
import 'ywbj-ui/dist/yw.css'
Vue.use(YwUI)
 
#组件中直接使用
<yw-button type="success" isDisabled>success</yw-button>

三. 自定义组件API文档

Button按钮组件

参数 说明 类型 可选值 默认值
shape 按钮的形状 string 圆角:circle', 直角:'rectangle' ‘ ’
isDisabled 是否禁用按钮 boolean true/false false
type 按钮的类型 string 'default',success', 'warning', 'error', 'info' default
size 按钮的大小 string 'large', 'medium', 'small' ‘ ’

Modal对话框组件

参数 说明 类型 可选值 默认值
isShow 是否显示 boolean true/false false
width 宽度 number
showTitle 是否显示标题 boolean true/false true
showBody 是否显示主体 boolean true/false true
showFooter 是否显示按钮 boolean true/false true
size 对话框大小 string 'large', 'medium', 'small' 'medium'

四. 引用效果展示


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容