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 - 开始
写在前面 一年多没写过博客了,工作.生活逐渐磨平了棱角. 写代码容易,写博客难,坚持写高水平的技术博客更难. 技术控决定慢慢拾起这份坚持,用作技术学习的阶段性总结. 返回阅读列表点击 这里 开始 大前 ...
随机推荐
- DECODE 与CASE WHEN 的比较
1.DECODE 只有Oracle 才有,其它数据库不支持; 2.CASE WHEN的用法, Oracle.SQL Server. MySQL 都支持; 3.DECODE 只能用做相等判断,但是可以配 ...
- [uoj76]懒癌
为了方便,称患有懒癌的狗为"坏狗" 记$Q_{i}$为第$i$个人能观察的狗集合,$S$为坏狗集合,那么第$k$天第$i$个人能得到的信息有且仅有$S\ne \empty$.$S\ ...
- [bzoj1032]祖码
先将连续的一段相同的点连起来,然后考虑对于一段区间,分两种情况:1.首尾两点再同时消掉,必然要先将去掉首尾的一段消掉后再消2.首尾两点再不同时刻消掉,那么必然存在一个断点k,使得k左右无关(题目中的错 ...
- idea给类增加注释
File-->Settings-->Editor-->File and Code Templates 找到class #if (${PACKAGE_NAME} && ...
- 理解ASP.NET Core - 过滤器(Filters)
注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 Filter概览 如果你是从ASP.NET一路走过来的,那么你一定对过滤器(Filter)不陌 ...
- 强化学习之MountainCarContinuous(注册自己的gym环境)
目录 1. 问题概述 2. 环境 2.1 Observation & state 2.2 Actions 2.3 Reward 2.4 初始状态 2.5 终止状态- Episode Termi ...
- JavaScript Sanitizer API:原生WEB安全API出现啦
10月18号, W3C中网络平台孵化器小组(Web Platform Incubator Community Group)公布了HTML Sanitizer API的规范草案.这份草案用来解决浏览器如 ...
- CF611F New Year and Cleaning
题意 CF611F New Year and Cleaning 想法 这个题是\(NOIP2020\)的弱化版.. 我们把所有在二维上的点都一起考虑,那么所有点对于一个步骤的移动是相当于这些所有点所组 ...
- 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)
洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\).我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...
- python17进程
import os import time from multiprocessing.dummy import Process def so_sth(name): print("进程名称{} ...