vue 简易ui组件库随记
组件库官网
源码地址
github许可
进入仓库>点击create newfile >输入LICENSE
使用css变量
//:root为根元素
:root{
--button-height: 32px;
--font-size: 14px;
--button-bg: white;
--button-active-bg: #eee;
--border-radius: 4px;
--color: #333;
--border-color: #999;
--border-color-hover: #666;
}
开发者使用-D,用户不用-D
vue安装
运行时 + 编译器 vs. 只包含运行时
如果你需要在客户端编译模板 (比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板),就将需要加上编译器,即完整版:
// 需要编译器
new Vue({
template: '<div>{{ hi }}</div>'
})
// 不需要编译器
new Vue({
render (h) {
return h('div', this.hi)
}
})
当使用 vue-loader 或 vueify 的时候,*.vue 文件内部的模板会在构建时预编译成 JavaScript。你在最终打好的包里实际上是不需要编译器的,所以只用运行时版本即可。
因为运行时版本相比完整版体积要小大约 30%,所以应该尽可能使用这个版本。如果你仍然希望使用完整版,则需要在打包工具里配置一个别名:
webpack
module.exports = {
// ...
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js' // 用 webpack 1 时需用 'vue/dist/vue.common.js'
}
}
}
Rollup
const alias = require('rollup-plugin-alias')
rollup({
// ...
plugins: [
alias({
'vue': require.resolve('vue/dist/vue.esm.js')
})
]
})
Browserify
添加到你项目的 package.json:
{
// ...
"browser": {
"vue": "vue/dist/vue.common.js"
}
}
Parcel
在你项目的 package.json 中添加:
{
// ...
"alias": {
"vue" : "./node_modules/vue/dist/vue.common.js"
}
}
运行
parcel index.html --no-cache
caniuse是什么?
使用此工具,可以快速查看网站上的特定技术是否与特定浏览器兼容的问题,可帮助您更轻松地做出设计和开发决策。该网站主要由Alexis Deveria建立和维护, Lennart Schoors设计。CanIUse是一个开源项目,任何人都可以有助于为促进信息的数据库,甚至小的努力。
使用该工具很简单。通过对属性、参数或功能的简单搜索,caniuse.com将准确地告诉您哪些浏览器和版本支持该技术。 CanIUse还可以让您了解您正在寻找的属性的变体。这样你就知道哪些浏览器支持哪些类型的媒体查询。
以及到什么程度。兼容性图表不仅表明浏览器是否支持该技术,还表明是否支持某些版本的部分兼容性。
BDD 行为驱动开发
TDD 测试驱动开发
Assert 断言
单元测试
使用chailjs查看网址
mock,,使用chai spies
行内块元素 对不齐解决方案
*{display: inline-flex;}
felx布局
//order改变顺序子元素
.icon { order: 2; margin-right: 0; margin-left: .1em;}
vue的position
export default {
props:{
iconName:{},
iconPosition:{
type:String,
default:"left",
//validator:检测外部数据的值
validator(value){
console.log(value)
}
}
}
}
:**
控制台输出警告
console.log.warn()
单元测试
安装(chai)查看chai
npm i -D chai@4.1.2
使用 chai.expect 添加四个测试用例
/单元测试
import chai from 'chai'
const expect = chai.expect
{
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'setup'
}
})
vm.$mount()
const useElement = vm.$el.querySelector('use')
const href = useElement.getAttribute('xlink:href')
expect(href).to.eq('#i-setup')
vm.$el.remove()
vm.$destroy()
}
{
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'setup',
loading:true
}
})
vm.$mount()
const useElement = vm.$el.querySelector('use')
const href = useElement.getAttribute('xlink:href')
expect(href).to.eq('#i-loading')
vm.$el.remove()
vm.$destroy()
}
{
const div = document.createElement('div')
document.body.appendChild(div)
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'setup',
}
})
vm.$mount(div)
const svg = vm.$el.querySelector('svg')
const {order} = window.getComputedStyle(svg)
expect(order).to.eq('1')
vm.$el.remove()
vm.$destroy()
}
{
const div = document.createElement('div')
document.body.appendChild(div)
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'setup'
}
})
vm.$mount(div)
const svg = vm.$el.querySelector('svg')
const {order} = window.getComputedStyle(svg)
expect(order).to.eq('2')
vm.$el.remove()
vm.$destroy()
}
{
const div = document.createElement('div')
document.body.appendChild(div)
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'setup',
iconPosition:'right'
}
})
vm.$mount(div)
vm.$on('click',()=>{
console.log()
})
}
测试click的执行函数 安装chai的常见
安装(chai- spies )
npm i -D chai-spies@1.0.0
测试click执行函数
import chai from 'chai'
import spies from "chai-spies"
chai.use(spies)
const expect = chai.expect
{
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'setup',
}
})
vm.$mount()
//模拟事件执行函数
let spy = chai.spy(function (){})
vm.$on('click',spy)
const button = vm.$el
button.click()
expect(spy).to.have.been.called()
}
自动化测试
使用 Karma + Mocha做单元测试
- Karma(
[ˈkɑrmə]卡玛)是一个测试运行器,它可以呼起浏览器,加载测试脚本,然后运行测试用例 - Mocha(
[ˈmoʊkə]摩卡)是一个单元测试框架/库,它可以用来写测试用例 - Sinon(西农)是一个 spy / stub / mock 库,用以辅助测试(使用后才能理解)
步骤
安装各种工具
npm i -D karma karma-chrome-launcher karma-mocha karma-sinon-chai mocha sinon sinon-chai karma-chai karma-chai-spies
创建 karma 配置
// 新建 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: ['ChromeHeadless'],
// 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('#i-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('#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: '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
"scripts": {
"dev-test": "parcel watch test/* --no-cache & karma start",
//打包test下的以及文件,不要缓存,不要压缩
//使用karma打开测试用例,配置文件是新建 karma.conf.js,内容如下
"test": "parcel build test/* --no-minify && karma start --single-run"
},
运行测试脚本
要么使用 npm run test 一次性运行
要么使用 npm run dev-test 进行 watch 运行
效果
如此一来,在开发的时候新开一个命令行窗口运行 npm run dev-test 就可以实时查看测试结果。
如果只想看一次结果,就只用运行 npm run test
持续集成测试(.travis )
根目录下创建
//新建.travis.yml文件
language: node_js
node_js:
- "8"
addons:
chrome: stable
sudo: required
before_script:
- "sudo chown root /opt/google/chrome/chrome-sandbox"
- "sudo chmod 4755 /opt/google/chrome/chrome-sandbox"
测试ui库
创建vue项目是报错
ERROR Error: spawn yarn ENOENT
Error: spawn yarn ENOENT
spawn yarn ENOENT
这是因为yarn找不到,而且设置的默认包管理是yarn
可以修改成npm
方式:一、直接在C盘用户名/.vuerc文件进行修改,将 "packageManager"改为"npm"
{
"useTaobaoRegistry": false,
"packageManager": "npm"
}
发布 npm 包
1 确保你的代码测试通过了
npm run test 全部是绿色(原谅色)才行。
2 上传代码到 npmjs.org
-
更新 package.json
- 在 package.json 里将版本号改为 0.0.1
{ "name": "golong-ui", "version": "0.0.9", }- 创建 index.js,在 index.js 里将你想要导出的内容全部导出
//上传的文件目录 "files": [ "dist/*" ], //文件入口 "main": "dist/index.js", -
去 www.npmjs.com/ 注册一个账户
-
确认一下邮箱(必须)
-
在 gulu 项目根目录运行 npm adduser 或者 npm login 登录npm
- 如果错误提示里面含有 registry.npm.taobao.org 则说明你的 npm 源目前为淘宝源,需要更换为 npm 官方源
-
运行 npm publish:上传
使用自己的包
- 预测其他使用你的包的人会怎么使用
- 使用 vue-cli
- 使用 webpack
- 使用 parcel
- 分别使用这些方式来使用自己的包(我们只以 vue-cli 为例)
- 使用过程中我们发现报错说 import 语法有问题,那时因为 node 目前确实不支持 import,我们需要用 babel 转译 import
- 你可以要求使用者自己用 babel 来转译
- 你也可以转义好了再给他用
npx parcel build index.js --no-minify(本来不应该加 --no-minify 的,奈何不加会有 bug,HTML 压缩把 slot 标签全删了)- 将 package.json 的 main 改为 dist/index.js
- 使用过程中我们发现报错说 import 语法有问题,那时因为 node 目前确实不支持 import,我们需要用 babel 转译 import
本地测试不用发布
- 使用 npm link 或者 yarn link 来加速调试
- 你每次修改源码之后,有两条路让别人得到最新效果
- 更新 package.json 里的 version,然后 npm publish。别人通过 npm update xxx 来更新。
- 如果你只是为了本地调试,可以在项目目录使用 npm link,然后在使用之处运行 npm link xxx,就是最新了
- 你每次修改源码之后,有两条路让别人得到最新效果
图标(shields)
git branch(创建爱你分支)
git checkout(切换分支)
scss for Each的使用
@for $n from 1 through 24 {
&.#{$class-prefix}#{$n} {
width: $n/24*100%;
}
}
什么代码需要重构
1 用到两次以上的代码
2一眼看,看不同的代码
scss不能用除法?
解决方法:
vue动画的简单用法
<template>
<transition name="g-aside">
<div class="g-aside" v-if="has">
<slot></slot>
<button @click="has=false">点击</button>
</div>
</transition>
</template>
<script lang="ts">
export default {
name: "Aside",
data(){
return{
has:true
}
}
};
</script>
<style lang="scss" scoped>
.g-aside{
}
.g-aside-enter-active, .g-aside-leave-active {
transition: margin 1s;
}
.g-aside-enter, .g-aside-leave-to{
margin-left: -150px;
}
</style>
Vue插件
插件
插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:
- 添加全局方法或者 property。如:vue-custom-element
- 添加全局资源:指令/过滤器/过渡等。如 vue-touch
- 通过全局混入来添加一些组件选项。如 vue-router
- 添加 Vue 实例方法,通过把它们添加到
Vue.prototype上实现。 - 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成:
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
new Vue({
// ...组件选项
})
也可以传入一个可选的选项对象:
Vue.use(MyPlugin, { someOption: true })
Vue.use 会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。
Vue.js 官方提供的一些插件 (例如 vue-router) 在检测到 Vue 是可访问的全局变量时会自动调用 Vue.use()。然而在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use():
// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
var Vue = require('vue')
var VueRouter = require('vue-router')
// 不要忘了调用此方法
Vue.use(VueRouter)
开发插件
Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
项目中创建的插件
//MyPlugin.js文件
import Toast from "./Toast";
let currentToast
export default {
install(Vue,options){
Vue.prototype.$toast =(message,toastOptions)=>{
if(currentToast){
currentToast.clear()
}
currentToast=createToast({Vue,message,propsData:toastOptions})
}
}
}
使用插件
//引入MyPlugin.js
import MyPlugin from "./MyPlugin";
//使用
Vue.use(MyPlugin)