05 - Vue3 UI Framework - Button 组件
官网基本做好了,接下来开始做核心组件
返回阅读列表点击 这里
目录准备
在项目 src 目录下创建 lib 文件夹,用来存放所有的核心组件吧。然后再在 lib 文件夹下创建 Button.vue 文件。
您也可以进行结构化设计,比如,这里就不进行了。
|-lib
|-Button
|- Button.vue
|- Button.ts
|_ Button.scss
需求分析
惯例先行需求分析
- 多种类基础
Button,包含警告、成功、危险等 - 允许设置
Button为禁用状态 - 不止有传统
Button,还可以有文字或链接形式 - 当处于加载中,
Button应当显示 - 有不同的尺寸可供选择
- 应当允许更换颜色
- 当鼠标放置于
Button上、鼠标按下未松开、处于加载中等状态时,应当变更背景色 - 允许用户自定义
Button上显示的文本
那么可以整理出以下参数表格
| 参数 | 含义 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| level | 默认类型 | string | default / plain / primary / success / info / warning / danger | default |
| disabled | 是否禁用 | boolean | false / true | false |
| theme | 式样 | string | button / link / text | button |
| loding | 是否加载中 | boolean | false / true | false |
| size | 尺寸 | string | middle / small / large | middle |
| color | 颜色 | string | 任意合法颜色值 | #f3678e |
第 7 条,可以通过设置一个遮罩层来实现,只要遮罩层变色,背景色也等效变色
第 8 条,可以通过插槽实现,注意 vue3 不建议使用具名插槽
骨架
容易得到如下骨架
<template>
<button
class="jeremy-button"
:theme="theme"
:level="level"
:size="size"
:style="{ '--color': color }"
:disabled="disabled"
:loading="loading"
>
<div class="jeremy-button-mask"></div>
<span class="jeremy-button-loadingIndicator" v-if="loading"></span>
<slot></slot>
</button>
</template>
首先,本质应当是一个 button 元素,在此基础上,将参数列表中整理出来的每个参数,都使用 v-bind 绑定到 button 上
注意,此处绑定 color,必须是如上例一样,绑定到 --color 属性上,才可以在 css 中使用 css3 语法 var() 读取,在 css 小节会再解释,此处略
之后,在 button 内
- 放置一个遮罩层,用于变色
- 放置一个”加载中”的动画,用于在加载中状态下显示
- 放置一个默认插槽,用于传递用户自定义的文本
然后为上述元素配置各自的 class 名称,骨架就完成了。
功能
显然,参数列表中整理出来的内容,一定来自引用该组件的地方的传入,先根据参数列表,写好 ts 声明:
declare const props: {
theme?: "button" | "link" | "text";
level?:
| "default"
| "plain"
| "primary"
| "success"
| "info"
| "warning"
| "danger";
size?: "middle" | "small" | "large";
color: string;
disabled: boolean;
loading: boolean;
};
然后在 export default 中,写入我们的参数
export default {
install: function (Vue) {
Vue.component(this.name, this);
},
name: "JeremyButton",
props: {
theme: {
type: String,
default: "button",
},
level: {
type: String,
default: "default",
},
size: {
type: String,
default: "middle",
},
color: {
type: String,
default: "#8c6fef",
},
disabled: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
},
};
对于事件绑定,因为我们设计的组件只有一个唯一的根元素,所以对于外部传递过来的事件,会自动绑定到组件的根元素上面。
样式表
注意 :UI 库的样式表一般不要加 scoped 修饰符,为了尽可能减少对用户样式表的影响,方便用户 DIY
特别注意 : button 元素会有默认黑色外边框,不属于 border,必须通过 outline: none; 才能消除
然后,我们使用 css3 的 var() 语法,取得我们通过 ts 绑定到 style 上的 --color 属性
为什么是 --color 而不是 color ?因为 var() 语法要求这个参数必须是 -- 开头,才可以正常访问到
对于遮罩层,采用淡出到白色即可实现,原理此处不解释了
最后,对于多种不同的 button,可以使用 scss 提供的 mixin / include 语法来实现,完整代码如下:
$theme-color: var(--color);
$base-mask: fade-out(#fff, 0.7);
$active-mask: fade-out(#fff, 0.5);
$h: 32px;
$radius: 4px;
@keyframes jeremy-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.jeremy-button {
position: relative;
display: inline-block;
padding: 10px 16px;
color: white;
border-radius: $radius;
border: none;
font-size: 16px;
cursor: pointer;
white-space: nowrap;
transition: background-color 250ms;
outline: none;
:focus {
outline: none;
}
> .jeremy-button-mask {
position: absolute;
display: inline-block;
height: 100%;
width: 100%;
left: 0;
top: 0;
border-radius: $radius;
&:hover {
background: $base-mask;
}
}
&[loading="true"],
&[disabled] {
cursor: not-allowed;
> .jeremy-button-mask {
pointer-events: none;
}
}
> .jeremy-button-loadingIndicator {
width: 14px;
height: 14px;
display: inline-block;
margin-right: 4px;
border-radius: 8px;
border-style: solid;
border-width: 2px;
animation: jeremy-spin 1s infinite linear;
}
}
@mixin layout($color) {
$loading-color: fade-out(black, 0.7);
background: $color;
&:active {
> .jeremy-button-mask {
background: $active-mask;
}
}
> .jeremy-button-loadingIndicator {
border-color: $loading-color $loading-color $loading-color transparent;
}
&[loading="true"],
&[disabled] {
> .jeremy-button-mask {
background: $base-mask;
}
}
}
.jeremy-button[theme="button"] {
$color: $theme-color;
@include layout($color);
}
.jeremy-button:not([theme="button"]) {
padding: 0;
background: white;
color: black;
&:hover {
color: $theme-color;
}
}
.jeremy-button[theme="link"] {
text-decoration: underline;
}
.jeremy-button[level="plain"] {
$base-color: $theme-color;
@include layout(white);
color: black;
> .jeremy-button-mask {
border: 1px solid rgb(187, 187, 187);
}
&:not([loading="true"]):not([disabled]) {
&:hover {
> .jeremy-button-mask {
border: 1px solid $base-color;
}
color: $base-color;
}
}
}
.jeremy-button[level="primary"] {
$color: #29adfa;
@include layout($color);
}
.jeremy-button[level="success"] {
$color: rgb(103, 194, 58);
@include layout($color);
}
.jeremy-button[level="info"] {
$color: #808080;
@include layout($color);
}
.jeremy-button[level="warning"] {
$color: rgb(230, 162, 60);
@include layout($color);
}
.jeremy-button[level="danger"] {
$color: rgb(245, 108, 108);
@include layout($color);
}
.jeremy-button[size="large"] {
padding: 14px 24px;
}
.jeremy-button[size="small"] {
padding: 6px 10px;
}
以上,button 组件就完成了! :happy:
测试一下

感谢阅读
05 - Vue3 UI Framework - Button 组件的更多相关文章
- 06 - Vue3 UI Framework - Dialog 组件
做完按钮之后,我们应该了解了遮罩层的概念,接下来我们来做 Dialog 组件! 返回阅读列表点击 这里 需求分析 默认是不可见的,在用户触发某个动作后变为可见 自带白板卡片,分为上中下三个区域,分别放 ...
- 10 - Vue3 UI Framework - Tabs 组件
标签页是非常常用的组件,接下来我们来制作一个简单的 Tabs 组件 返回阅读列表点击 这里 需求分析 我们先做一个简单的需求分析 可以选择标签页排列的方向 选中的标签页应当有下划线高亮显示 切换选中时 ...
- 08 - Vue3 UI Framework - Input 组件
接下来再做一个常用的组件 - input 组件 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 input 组件有两种类型,即 input 和 textarea 类型 当类型为 ...
- 09 - Vue3 UI Framework - Table 组件
接下来做个自定义的表格组件,即 table 组件 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 基于原生 table 标签的强语义 允许用户自定义表头.表体 可选是否具有边框 ...
- 11 - Vue3 UI Framework - Card 组件
卡片是非常常用也是非常重要的组件,特别是在移动端的众多应用场景中,随便打开一个手机 App ,您会发现充斥着各种各样的卡片. 所以,我们也来制作一个简易的 Card 组件 返回阅读列表点击 这里 需求 ...
- 00 - Vue3 UI Framework - 阅读辅助列表
阅读列表 01 - Vue3 UI Framework - 开始 02 - Vue3 UI Framework - 顶部边栏 03 - Vue3 UI Framework - 首页 04 - Vue3 ...
- 07- Vue3 UI Framework - Switch 组件
为了更好的提升用户体验,我们这里再做一个很常用的开关组件 switch 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 switch 组件应分为选中/未被选中,两种状态 可以通过 ...
- 04 - Vue3 UI Framework - 文档页
官网的首页做完了,接下来开始做官网的文档页 返回阅读列表点击 这里 路由设计 先想想我们需要文档页通向哪些地方,这里直接给出我的设计: 所属 子标题 跳转路径 文件名(*.vue) 指南 介绍 /do ...
- 01 - Vue3 UI Framework - 开始
写在前面 一年多没写过博客了,工作.生活逐渐磨平了棱角. 写代码容易,写博客难,坚持写高水平的技术博客更难. 技术控决定慢慢拾起这份坚持,用作技术学习的阶段性总结. 返回阅读列表点击 这里 开始 大前 ...
随机推荐
- SpringCloud 2020.0.4 系列之 Stream 延迟消息 的实现
1. 概述 老话说的好:对待工作要有责任心,不仅要完成自己的部分,还要定期了解整体的进展. 言归正传,我们在开发产品时,常常会遇到一段时间后检查状态的场景,例如:用户下单场景,如果订单生成30分钟后, ...
- Java设计模式之(四)——原型模式
1.什么是原型模式 Specify the kinds of objects to create using a prototypical instance,and create new object ...
- MySQL 1064 错误
ERROR 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MySQL s ...
- [hdu6987]Cycle Binary
定义$x$为$s$的周期,当且仅当$\forall 1\le i\le |s|-x,s_{i}=s_{i+x}$(字符串下标从1开始) 令$per(s)$为$s$的正周期构成的集合,$\min p ...
- 【HTML】基础
HTML基础 2019-07-23 10:16:28 by冲冲 在线编辑HTML/CSS/JS效果,实时查看效果 https://c.runoob.com/front-end/61 1. 概念 ① ...
- go 自定义http.Client - 动态修改请求Body
前言 在对接Alexa Smart Home时,有的请求Payload中需要传入Access Token,但是这个Token是由OAuth2 Client管理的,封装Payload时并不知道Acces ...
- 面向对象编程之Python学习一
在实际的程序设计中,使用Java面向对象编程方法编写算法能够很清楚的理解其来龙去脉. 习惯了面向对象思维,学习Python也自然使用这种思维. 目前,由于Python很多软件包能够容易的获取和利用,人 ...
- redis的RDB和AOF两种持久化机制
思维导图:我的redis基础知识汇总 RDB持久化机制的优点 (1)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的 ...
- Codeforces 1270E - Divide Points(构造+奇偶性)
Codeforces 题目传送门 & 洛谷题目传送门 显然,直接暴力枚举是不可能的. 考虑将点按横纵坐标奇偶性分组,记 \(S_{i,j}=\{t|x_t\equiv i\pmod{2},y_ ...
- [R] ignore.case区分大小写参数
字符串操作的函数(如contains),很多都包含ignore.case参数,默认是T,即不分大小写,稍不注意就会掉坑里,最好的习惯是下意识地加入这个参数. 举个例子: 我要选择An的列,就用下面这个 ...