创建项目
- 创建仓库并上传到Github仓库中
git init
git commit -m 'init'
- 声明软件许可
Create new file => LICENSE => Choose a license template => MIT License => Review and submit => Commit new file => Create pull request => Merge pull request => Confirm merge => Delete branch
- 初始化项目
npm init
version: 0.0.1
description: 这是一个UI框架
keywords: vue,ui
author: Layouwen
license: MIT
- 安装Vue
npm i vue
- 设置unsigned
选中”Allow unsigned requests”
创建第一个全局组件
创建button.js
Vue.component('g-button', {
template: `
<button>hi</button>
`
})
在index.html中引用
<g-button>
<script src="./button.js"></script>
添加g-button的基本样式
.g-button{
padding: 0 1em;
height: var(--button-height);
font-size: var(--font-size);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
background: var(--button-bg);
}
.g-button:hover {
border-color: var(--border-color-hover);
}
.g-button:active {
background-color: var(--button-active-bg);
}
.g-button:focus {
outline: none;
}
将button改为单文件组件
<template>
<button class="g-button">按钮</button>
</template>
<script>
export default {}
</script>
<style lang="scss">
.g-button {
padding: 0 1em;
height: var(--button-height);
font-size: var(--font-size);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
background: var(--button-bg);
&:hover {
border-color: var(--border-color-hover);
}
&:active {
background-color: var(--button-active-bg);
}
&:focus {
outline: none;
}
}
</style>
去iconfont添加图标,并应于进去
使用slot插槽自定义按钮文字,使用props自定义icon名字、icon位置
button.js
<template>
<div>
<button class="g-button" :class="{[`icon-${iconPosition}`]: true}">
<svg v-if="icon" class="icon">
<use :xlink:href="`#icon-${icon}`"></use>
</svg>
<div class="content">
<slot></slot>
</div>
</button>
</div>
</template>
<script>
export default {
props: ['icon', 'iconPosition']
}
</script>
index.html
<g-button>
按钮
</g-button>
<g-button icon="settings">
按钮
</g-button>
<g-button icon="settings" icon-position="right">
按钮
</g-button>
将Props改写为对象形式,更好控制其类型
props: {
icon: {},
iconPosition: {
type: String,
default: 'left'
}
}
将svg代码改为Icon组件
添加loading状态
添加button-group组件
<g-button-group>
<g-button icon="left">上一页</g-button>
<g-button>1</g-button>
<g-button>2</g-button>
<g-button>3</g-button>
<g-button icon="right" icon-position="right">下一页</g-button>
</g-button-group>
检测button-group中的元素是否合法
mounted() {
for(let node of this.$el.children) {
let name = node.nodeName.toLowerCase()
if(name != 'button') {
console.warn(`g-button-group 中应该只含有 button, 而你的是 ${name}`)
}
}
}
使用chai作单元测试
npm i -D chai
npm i -D chai-spies
添加自动测试
npm i -D karma karma-chrome-launcher karma-mocha karma-sinon-chai mocha sinon sinon-chai karma-chai karma-chai-spies
根目录创建karma.conf.js
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha', 'sinon-chai'],
client: {
chai: {
includeStack: true
}
},
// list of files / patterns to load in the browser
files: [
'dist/**/*.test.js',
'dist/**/*.test.css'
],
// list of files / patterns to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
})
}
创建 test目录 button.test.js 文件
const expect = chai.expect;
import Vue from 'vue'
import Button from '../src/button'
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: 'settings'
}
}).$mount()
const useElement = vm.$el.querySelector('use')
expect(useElement.getAttribute('xlink:href')).to.equal('#icon-settings')
vm.$destroy()
})
it('可以设置loading.', () => {
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'settings',
loading: true
}
}).$mount()
const useElements = vm.$el.querySelectorAll('use')
expect(useElements.length).to.equal(1)
expect(useElements[0].getAttribute('xlink:href')).to.equal('#icon-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: 'settings',
}
}).$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: 'settings',
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: 'settings',
}
}).$mount()
const callback = sinon.fake();
vm.$on('click', callback)
vm.$el.click()
expect(callback).to.have.been.called
})
})
修改 package.json 的 scripts 参数
"scripts": {
"dev-test": "parcel watch test/* --no-cache & karma start",
"test": "parcel build test/* --no-minify && karma start --single-run"
},
开始测试
npm run test
npm run dev-test