1.需求分析

用例图,状态分析

VUE造轮子ui框架(上)-编程知识网

2.UI设计

我们用SKetch进行ui的设计。可以利用symbol来绑定关联等详细操作就不赘述了,设计效果如下图

VUE造轮子ui框架(上)-编程知识网

3.项目初始化

1.先在github上建立gulu仓库,本地电脑创建项目,关联到远程仓库
2.创建README.md 和 LICENSE许可证(许可证可在github上进行创建,具体创建的类型可以看阮一峰老师的经典图)
3.npm init 来简化项目的传输等,记载项目依赖,此时可以进行提交但node_modules依赖包过大,可以创建.gitignore文件进行不上传指定文件
4.这里我们利用parcel来进行构建项目,这里我们进行-D安装,所以在执行命令时需要~.node_modules/.bin/parcel~来找到本地安装的指令才可以进行打包。
出现的问题: (You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.)这是由于vue版本不兼容的原因,我们可以上vue官网找到解决办法

4.button基础样式实现

用到了变量方便用户进行修改样式,css使用scss

//scss//
* {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
:root { //表示根html, 也可以写其他的选择器,在选择器中生效
        --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;
      }
#app {
        margin: 20px;
      }
body {
        font-size: var(--font-size);
      }
      
.g-button {
  font-size: var(--font-size);
  height: var(--button-height);
  padding: 0 1em;
  border-radius: var(--border-radius);
  border: 1px solid var(--border-color);
  background-color: var(--button-bg);
  &:hover {
    border-color: var(--border-color-hover);
  }
  &:active {
    background-color: var(--button-active-bg);
  }
  &:focus {
    outline: none;
  }
}

5.实现按钮添加字体图标

1.去阿里巴巴图标库进行,图标的添加,利用图标库的symbol模式,使用方法可以参考图标库的文档。在图标库中可以进行项目编辑前缀名,批量操做图标的颜色,每个图标大小和名字。

2.让用户添加属性的方式添加字体图标,具体在组件中进行编写,还添加了icon-position属性,让用户自定义图标的左右位置。还需要进行用户传入属性的验证在props中validator进行验证给与用户提示信息。

3.把svg整合到icon.vue中,实现用户可以调用icon组件

为按钮添加loading样式

1.我们先添加loading这一个图标,然后在button组件中对这个图标进行旋转利用到关键帧动画,在icon添加class实现

VUE造轮子ui框架(上)-编程知识网

2.然后进行一些逻辑,包括loading与icon交替显示问题,

VUE造轮子ui框架(上)-编程知识网

3.为按钮添加事件,由于我们用户要动态绑定loading 属性到g-button上,所以我们只需要让vue动态追踪就可以了。但是–出现一个问题: 由于我们按钮组件是自定义的,当用户在组件上绑定点击事件时,浏览器判断不出点击哪里会触发用户定义的点击事件,所以我们需要在组件中自己来找到触发的位置,如下图:

VUE造轮子ui框架(上)-编程知识网

4.button-group组件实现

效果如下:

VUE造轮子ui框架(上)-编程知识网

button-group代码如下

<template>
  <div class="g-button-group"><slot></slot></div>
</template>

<script>
export default {};
</script>

<style scoped lang="scss">
.g-button-group {
  display: inline;
  .g-button {
    border-radius: 0 !important;
    margin-left: -1px; //结局边框加深问题t1, 此时代码可以优化,选择器为不是第一个时候添加
    &:first-child {
      border-top-left-radius: var(--border-radius) !important;
      border-bottom-left-radius: var(--border-radius) !important;
    }
    &:last-child {
      border-top-right-radius: var(--border-radius) !important;
      border-bottom-right-radius: var(--border-radius) !important;
    }
    &:hover { //结局边框加深问题t2
      position: relative;
      z-index: 1; 
    }
  }
}
</style>


单元测试

我们为了检测一个作用明确的单元是否功能正常,我们进行单元测试,即利用代码的方式进行测试,代替了手动测试方式。这样结果更具有准确性。即 测试行为—>结果。 用到了Chai这个库其中的期待和间谍


import chai from 'chai'
import spies from 'chai-spies'

chai.use(spies)
Vue.component('g-button-group', ButtonGroup)	const expect = chai.expect


new Vue({	{
  el: '#app',	  const Constructor = Vue.extend(Button)
  data: {	  const vm = new Constructor({
    loading1: false,	    propsData: {
    loading2: true,	      icon: 'settings'
  }	    }
})	  }).$mount()
  const useElement = vm.$el.querySelector('use')
  expect(useElement.getAttribute('xlink:href')).to.equal('#i-settings')
  vm.$destroy()
}
{
  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()
}
{
  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()
}
{
  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()
}
{
  const Constructor = Vue.extend(Button)
  const vm = new Constructor({
    propsData: {
      icon: 'settings',
    }
  }).$mount()
  const spy = chai.spy(() => {})
    console.log('hi')	  vm.$on('click', spy)
  })	
  vm.$el.click()	  vm.$el.click()
  expect(spy).to.have.been.called()
}	}
}