0. 最终效果
1. 第一步:需求分析
- 参考一下别人的 Button,AntD,Bulma、Element、iView、Vuetify 等
- 总结需求
- 可以有不同的等级(level)
- 可以是链接,可以是文字
- 可以 click、focus、鼠标悬浮
- 可以改变 size:大中小
- 可以禁用(disabled)
- 可以加载中(loading)
2. 第二步:API 设计
<button
@click="?"
@focus="?"
@mouseover="?"theme="button or link or text"level="main or normal or minor"size="big normal small"disabledloading
>button>
3. 第三步:写代码
步骤
写 HTML
写 CSS
写 JS
测试
改写代码
再测试
再改写
再测试
再改写
再测试
再改写
……
4. 开始写代码
- 在 lib 目录创建 Button.vue 组件
- Button.vue, 按钮初步使用 slot 占位
5. Vue3 属性绑定细节
- 通过$attrs 将全部属性事件绑定到指定的某元素
// ButtonDemo.vue
button 示例
示例1
@click="onClick"
@focus="onClick"
@mouseover="onClick"
size="small"
>你好 >
- Vue 3 属性绑定小结
- 默认所有属性都绑定到根元素
- 使用 inheritAttrs: false 可以取消默认绑定
- 使用 $attrs 或者 context.attrs 获取所有属性
- 使用 v-bind="$attrs" 批量绑定属性
- 使用 const {size, level, ...xxx} = context.attrs 将属性分开
6. props 和 attrs 的区别
- props 要先声明才能取值,attrs 不用先声明
- props 不包含事件,attrs 包含
- props 没有声明的属性,会跑到 attrs 里
- props 支持 string 以外的类型,attrs 只有 string 类型
- ButtonDemo.vue
button 示例
示例1
@click="onClick"
@focus="onClick"
@mouseover="onClick"
size="small"
disabled
>你好 >
7. 如何让 Button 支持 theme 属性,theme 的值为 button/link/text
9. UI 库的 CSS 注意事项
- 不能使用 scoped
- 因为 data-v-xxx 中的 xxx 每次运行可能不同
- 必须输出稳定不变的 class 选择器,方便使用者覆盖
- 必须加前缀
.button 不行,很容易被使用者覆盖
.gulu-button 可以,不太容易被覆盖
.theme-link 不行,很容易被使用者覆盖
.gulu-theme-link 可以,不太容易被覆盖
10. CSS 最小影响原则
- CSS 绝对不能影响库使用者
- 在 lib 里面新建 gulu.scss
[class^="gulu-"],
[class*=" gulu-"]* {
//
//任何元素属性里面有个class是gulu-开头,或者class的第二个或者第三个含有gulu-
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 16px;
font-family: -apple-system, "Noto Sans", "Helvetica Neue", Helvetica,
"Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC",
"Hiragino Sans GB", "Noto Sans CJK SC", "Source Han Sans SC",
"Source Han Sans CN", "Microsoft YaHei", "Wenquanyi Micro Hei",
"WenQuanYi Zen Hei", "ST Heiti", SimHei, "WenQuanYi Zen Hei Sharp",
sans-serif;
}
在 main.ts 引入,需要注意引入顺序
import "./lib/gulu.scss";
import "./index.scss";
import { createApp } from "vue";
// @ts-ignore
import App from "./App.vue";
11. 支持 theme 属性
&.gulu-theme-link {
border-color: transparent;
box-shadow: none;
color: $blue;
&:hover,
&:focus {
color: lighten($blue, 10%);
}
}
&.gulu-theme-text {
border-color: transparent;
box-shadow: none;
color: inherit;
&:hover,
&:focus {
background: darken(white, 5%);
}
}
12. 让 button 支持 size 属性
size 的值为 big / normal / small
// Button.vue
13. 让 button 支持 level 属性
level 的值为 main / normal / minor / danger
ButtonDemo
button 示例
示例1
你好你好你好你好
示例2
大大大普普通小小小
大大大普普通小小小
大大大普普通小小小
示例3
主要按钮普通按钮危险按钮
主要链接按钮普通链接按钮危险链接按钮
主要文字按钮普通文字按钮危险文字按钮
14. 让 button 支持 disabled
disabled 的值为 true / false用法
"true" />
Button.vue
ButtonDemo.vue
// 省略其他代码
示例4
禁用按钮禁用链接按钮禁用按钮
15. 让 button 支持 loading,loading 值为 true / false
ButtonDemo.vue
// 省略代码
示例5
加载中加载完毕
Button.vue
16. 知识点总结
Vue 属性继承
默认属性传给根元素inheritAttrs: false 禁用之v-bind="$attrs" 或 context.attrsprops V.S. attrs库的 CSS 要求
不能用 scoped每个 CSS 类要加前缀CSS 最小影响原则其他
如何做 loading 动画