从零搭建组件库

从零搭建Vue组件库

一.组件库的划分

我们的划分以elementUi为基准分为

  • Basic:ButtonIcon图标Layout布局container布局容器...

  • Form: InputRadiocheckboxDatePickerUpload...

  • Data:TableTreePagination...

  • Notice:AlertLoadingMessage...

  • Navigation: TabsDropdownNavMenu...

  • Others:Popover,DialoginifiniteScrollCarousel...

二.通过Vue-Cli初始化项目

vue create m-ui
? Check the features needed for your project:
 (*) Babel # babel配置
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 (*) CSS Pre-processors # css预处理器
 ( ) Linter / Formatter
 (*) Unit Testing # 单元测试
 ( ) E2E Testing
> Sass/SCSS (with dart-sass)  
  Sass/SCSS (with node-sass)
  Less
  Stylus

为什么选择dart-sass?

? Pick a unit testing solution:
> Mocha + Chai # ui测试需要使用karma
  Jest

三.目录结构配置

│  .browserslistrc # 兼容版本
│  .gitignore
│  babel.config.js # babel的配置文件
│  package-lock.json
│  package.json
│  README.md      
├─public
│      favicon.ico
│      index.html 
├─src
│  │  App.vue 
│  │  main.js
│  │  
│  ├─packages # 需要打包的组件
│  │      button.vue
│  │      icon.vue
│  │      index.js # 所有组件的入口
│  │       
│  └─styles # 公共样式
│          _var.scss      
└─tests # 单元测试
    └─unit
            button.spec.js

四.编写插件入口

import Button from './button.vue';
import Icon from './icon.vue';

const install = (Vue) =>{ // 对外暴露install方法
    Vue.component(Button.name,Button);
    Vue.component(Icon.name,Icon);
}

if(typeof window.Vue !== 'undefined'){
    install(Vue);
}
export default {
    install
}
import mUi from  './packages';
Vue.use(mUi)

我们可以通过插件的方式去引入我们的组件库

五.编写Button组件

实现功能规划

  • 按钮的基本用法
  • 图标按钮
  • 按钮加载中状态
  • 按钮组的实现

准备备用样式

$border-radius: 4px;

$primary: #409EFF;
$success: #67C23A;
$warning: #E6A23C;
$danger: #F56C6C;
$info: #909399;


$primary-hover: #66b1ff;
$success-hover: #85ce61;
$warning-hover: #ebb563;
$danger-hover: #f78989;
$info-hover: #a6a9ad;

$primary-active: #3a8ee6;
$success-active: #5daf34;
$warning-active: #cf9236;
$danger-active: #dd6161;
$info-active: #82848a;
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

(1).实现按钮的基本用法

使用type属性来定义 Button 的样式。




(2).图标按钮

带图标的按钮可增强辨识度(有文字)或节省空间(无文字)。

使用iconfont添加图标

创建图标组件:






(3).按钮加载中状态

要设置为 loading 状态,只要设置loading属性为true即可。



(4).按钮组的实现

以按钮组的方式出现,常用于多项类似操作。





六.搭建测试环境

我们需要测试ui渲染后的结果。需要在浏览器中测试,所有需要使用Karma

Karma配置

(1)安装karma

npm install --save-dev @vue/test-utils karma karma-chrome-launcher karma-mocha karma-sourcemap-loader karma-spec-reporter karma-webpack mocha karma-chai

(2)配置karma文件

karma.conf.js

var webpackConfig = require('@vue/cli-service/webpack.config')

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],
    files: ['tests/**/*.spec.js'],
    preprocessors: {
      '**/*.spec.js': ['webpack', 'sourcemap']
    },
    autoWatch: true,
    webpack: webpackConfig,
    reporters: ['spec'],
    browsers: ['ChromeHeadless']
  })
}
{
  "scripts": {
    "test": "karma start"
  }
}

单元测试

import {
    shallowMount
} from '@vue/test-utils';
import {
    expect
} from 'chai'
import Button from '@/packages/button.vue'
import Icon from '@/packages/icon'

describe('button.vue', () => {
    it('1.测试slot是否能正常显示', () => {
        const wrapper = shallowMount(Button, {
            slots: {
                default: 'm-ui'
            }
        })
        expect(wrapper.text()).to.equal('m-ui')
    })
    it('2.测试传入icon属性', () => {
        const wrapper = shallowMount(Button, {
            stubs: {
                'm-icon': Icon
            },
            propsData: {
                icon: 'edit' // 传入的是edit 测试一下 edit是否ok
            }
        })
        expect(wrapper.find('use').attributes('href')).to.equal('#icon-edit')
    })
    it('3.测试传入loading,是否能,控制loading属性', () => {
        const wrapper = shallowMount(Button, {
            stubs: {
                'm-icon': Icon
            },
            propsData: {
                loading: true // 传入的是edit 测试一下 edit是否ok
            }
        })
        expect(wrapper.find('use').attributes('href')).to.eq('#icon-loading');
        expect(wrapper.find('button').attributes('disabled')).to.eq('disabled');
    })
    it('4.测试点击按钮', () => {
        const wrapper = shallowMount(Button, {
            stubs: ['m-icon']
        })
        wrapper.find('button').trigger('click')
        expect(wrapper.emitted('click').length).to.eq(1);
    });
    // 5.测试前后图标
    it('5.测试前后图标', () => {
        const wrapper = shallowMount(Button, {
            stubs: {
                'm-icon': Icon
            },
            slots:{
                default:'hello'
            },
            attachToDocument: true,
            propsData: {
                iconPosition: 'left',
                icon: 'edit'
            }
        });
        let ele = wrapper.vm.$el.querySelector('span');
        expect(getComputedStyle(ele, null).order).to.eq('2');
        wrapper.setProps({
            iconPosition: 'right'
        });
        return wrapper.vm.$nextTick().then(() => {
            expect(getComputedStyle(ele, null).order).to.eq('1');
        });
    });
})

七.打包组件

(1)配置打包命令

"lib": "vue-cli-service build --target lib --name m-ui  ./src/packages/index.js"

(2)配置运行入口

"main": "./dist/m-ui.umd.min.js"

(3)link到全局下

npm link

八.使用VuePress搭建文档

VuePress基本配置:

(1).安装

npm install vuepress -D

(2).配置scripts

{
    "docs:dev": "vuepress dev docs",
    "docs:build": "vuepress build docs"
}

(3).初始化docs

增加入口页面README.MD

---
home: true
actionText: 欢迎 →
actionLink: /components/button
features:
- title: 搭建自己的组件库
  details: 从0搭建自己的组件库
---

(4).配置导航

增加config.js

module.exports = {
    title: 'm-ui', // 设置网站标题
    description: 'ui 库', //描述
    dest: './build', // 设置输出目录
    port: 1234, //端口
    themeConfig: { //主题配置
        nav: [{
                text: '主页',
                link: '/'
            }, // 导航条
        ],
        // 为以下路由添加侧边栏
        sidebar: {
            '/components/': [{
                    collapsable: true,
                    children: [
                        'button'
                    ]
                }
            ]
        }
    }
}

(5).初始化配置文件 .vuepress

enhanceApp.js

  • 安装包

    npm install element-ui highlight.js node-sass sass-loader --save
    
  • link组件库

    npm link m-ui
    
import Vue from 'vue';
import Element from 'element-ui'; // 引入elementUi
import 'element-ui/lib/theme-chalk/index.css'

import hljs from 'highlight.js'
import 'highlight.js/styles/googlecode.css' //样式文件

import mUi from 'm-ui' // 要编写对应的文档的包
import 'm-ui/dist/m-ui.css'
Vue.directive('highlight',function (el) {
  let blocks = el.querySelectorAll('pre code');
  blocks.forEach((block)=>{
    hljs.highlightBlock(block)
  })
})
export default ({
  Vue,
  options, 
  router,
  siteData
}) => {
  Vue.use(Element);
  Vue.use(mUi)
}

(6).覆盖默认样式

styles/palette.styl

$codeBgColor = #fafafa // 代码背景颜色

$accentColor = #3eaf7c
$textColor = #2c3e50

$borderColor = #eaecef
$arrowBgColor = #ccc
$badgeTipColor = #42b983
$badgeWarningColor = darken(#ffe564, 35%)
$badgeErrorColor = #DA5961

.content pre{  margin: 0!important;}

.theme-default-content:not(.custom){
    max-width: 1000px !important;
}

(7).创建components目录

创建demo-block可收缩代码块






(8).编写对应组件的md文件


# Button组件
常用的操作按钮。
## 基础用法
基础的按钮用法。


::: slot source

:::

使用type属性来定义 Button 的样式。

::: slot highlight
​```html
默认按钮 主要按钮 成功按钮 信息按钮 警告按钮 危险按钮
​``` :::

九.发布到npm

配置.npmignore配置文件

npm addUser
npm publish

十.推送到git

添加npm图标 https://badge.fury.io/for/js

git remote add origin 
git push origin master

你可能感兴趣的:(从零搭建组件库)