从0创建Vue-UI轮子

313 阅读2分钟

一、创建项目,取名peg-top

  1. 初始化
yarn init
  1. 安装vue
yarn add vue
  1. 安装parcel
yarn add parcel-bundler -D

在这里,当我运行npx parcel index.html的时候我的命令栏出现了报错,显示我的taobao源里没有该包,然后如下全局安装

yarn global add parcel-bundler 
  1. 打包
parcel index.html --no-cache

写入脚本,在package.json里添加

"scripts":{
    "start":"rm -rf dist && parcel index.html --no-cache"
}

二、写第一个轮子

  1. Button.vue组件

组件的template<g-icon/><slot></slot>组成,同时做了一个toggle,当点击就会切换到loading的icon,再次点击就会切到当前icon。

slot插槽用于写入button按钮的的文字

  1. Icon.vue组件

Icon.vue就是封装<svg></svg>,如果有客户需要单独使用某个icon,就可以使用<g-icon name="XXX"></g-icon>

三、代码测试

  1. 安装,配置

yarn add karma karma-chrome-launcher karma-mocha karma-sinon-chai mocha sinon sinon-chai karma-chai karma-chai-spies -D

  • Karma([ˈkɑrmə] 卡玛)是一个测试运行器,它可以呼起浏览器,加载测试脚本,然后运行测试用例

  • Mocha([ˈmoʊkə] 摩卡)是一个单元测试框架/库,它可以用来写测试用例

  • Sinon(西农)是一个 spy / stub / mock 库,用以辅助测试(使用后才能理解)

然后需要添加karma.conf.js文件,进行测试配置。

  1. BDD测试

创建一个test目录,里面的一个文件为button.test.js

const expect = chai.expect;
import Vue from 'vue'
import Button from '../src/Button.vue'

Vue.config.productionTip = false
Vue.config.devtools = false

describe('Button', () => {
    it('存在.', () => {
        expect(Button).to.be.ok
    })
    it('可以设置icon.', () => {
        const Constructor = Vue.extend(Button)
        const vm = new Constructor({
            propsData: {
                icon: 'setting'
            }
        }).$mount()
        const useElement = vm.$el.querySelector('use')
        expect(useElement.getAttribute('xlink:href')).to.equal('#i-setting')
        vm.$destroy()
    })
    it('可以设置loading.', () => {
        const Constructor = Vue.extend(Button)
        const vm = new Constructor({
            propsData: {
                icon: 'setting',
                loading: true
            }
        }).$mount()
        const useElements = vm.$el.querySelectorAll('use')
        expect(useElements.length).to.equal(1)
        expect(useElements[0].getAttribute('xlink:href')).to.equal('#i-loading')
        vm.$destroy()
    })
    it('icon 默认的 order 是 1', () => {
        const div = document.createElement('div')
        document.body.appendChild(div)
        const Constructor = Vue.extend(Button)
        const vm = new Constructor({
            propsData: {
                icon: 'setting',
            }
        }).$mount(div)
        const icon = vm.$el.querySelector('svg')
        expect(getComputedStyle(icon).order).to.eq('1')
        vm.$el.remove()
        vm.$destroy()
    })
    it('设置 iconPosition 可以改变 order', () => {
        const div = document.createElement('div')
        document.body.appendChild(div)
        const Constructor = Vue.extend(Button)
        const vm = new Constructor({
            propsData: {
                icon: 'setting',
                iconPosition: 'right'
            }
        }).$mount(div)
        const icon = vm.$el.querySelector('svg')
        expect(getComputedStyle(icon).order).to.eq('2')
        vm.$el.remove()
        vm.$destroy()
    })
    it('点击 button 触发 click 事件', () => {
        const Constructor = Vue.extend(Button)
        const vm = new Constructor({
            propsData: {
                icon: 'setting',
            }
        }).$mount()

        const callback = sinon.fake();
        vm.$on('click', callback)
        vm.$el.click()
        expect(callback).to.have.been.called
    })
})

再在package.json里添加如下脚本并运行测试

  "scripts": {
    "dev-test": "parcel watch test/* --no-cache & karma start",
    "test": "rm -rf dist && parcel build test/* --no-cache --no-minify && karma start --single-run"
    }
  1. 持续集成

如果组件在本地测试成功,则将代码在travis-ci上做持续集成,如果全是通过,最后就可以发布第一个版本的npm包了,其他组件步骤类似。