Week-8 前端 Doc
本周主要讲解如何制作快速现代化的界面,并添加动画和过渡效果。
圣诞夜
圣诞节到了,公司内充满了快活的空气,大家约好晚上一起去逛街。就在这时,社长上网的时候发现其他公司的页面都变成了红色 + 现代风格,而自家公司还是古董风。于是他要求青叶学一下怎么美化外观再下班。青叶从海子前辈口中得知组件库是搭建 UI 好东西。最后她快速完成了任务和并大家一起欣赏了圣诞夜的街景。
动画和过渡效果
首先我们来看看什么是动画和过渡效果。在 web 开发中,动画和过渡效果是提高用户体验的重要手段。动画是指元素在一段时间内从一个状态平滑过渡到另一个状态,如元素的移动、旋转、缩放等;过渡效果是指元素在显示或隐藏时的平滑过渡,如淡入淡出、滑动、弹跳等。通过添加动画和过渡效果,可以使页面更加生动、有趣,提高用户的参与感和满意度。
我们接下来学习 vue 自带的一些动画效果和组件间切换的过渡效果。看下面一个演示例子,请在你的电脑上也跟着做一遍。
创建一个新的 vue 项目, pnpm create vue@latest
,然后删除自动创建的 /src/assets/main.css
文件,以免干扰我们的页面样式。
components/
目录下创建 Father.vue
, Son1.vue
, Son2.vue
三个 Vue 组件,代码如下:
Father.vue
<template>
<div class="father">
<nav class="nav">
<button
v-for="tab in tabs"
:key="tab.name"
@click="currentTab = tab.component"
:class="['btn', currentTab === tab.component ? 'btn-primary' : '']"
>
{{ tab.name }}
</button>
</nav>
<transition-group name="fade" mode="out-in">
<component :is="currentTab" :key="currentTab" />
</transition-group>
</div>
</template>
<script>
import Son1 from './Son1.vue'
import Son2 from './Son2.vue'
export default {
name: 'Father',
components: { Son1, Son2 },
data() {
return {
currentTab: 'Son1',
tabs: [
{ name: 'Animation Gallery', component: 'Son1' },
{ name: 'List Transitions', component: 'Son2' }
]
}
}
}
</script>
<style scoped>
.nav {
margin-bottom: 2rem;
padding: 1rem;
border-bottom: 1px solid #e2e8f0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Son1.vue
<!-- Son1.vue -->
<template>
<div class="animation-gallery">
<div class="controls">
<button
v-for="(_, name) in animations"
:key="name"
@click="toggleAnimation(name)"
class="btn"
>
切换 {{ formatName(name) }}
</button>
</div>
<div class="demos">
<!-- 淡入淡出 -->
<div class="demo-section">
<h3>淡入淡出</h3>
<transition name="fade">
<div v-if="animations.fade" class="demo-box">
淡入/淡出
</div>
</transition>
</div>
<!-- 滑动 -->
<div class="demo-section">
<h3>滑动</h3>
<transition name="slide">
<div v-if="animations.slide" class="demo-box">
滑入/滑出
</div>
</transition>
</div>
<!-- 缩放 -->
<div class="demo-section">
<h3>缩放</h3>
<transition name="scale">
<div v-if="animations.scale" class="demo-box">
缩放入/缩出
</div>
</transition>
</div>
<!-- 旋转 -->
<div class="demo-section">
<h3>旋转</h3>
<transition name="rotate">
<div v-if="animations.rotate" class="demo-box">
旋转入/旋出
</div>
</transition>
</div>
<!-- 翻转 -->
<div class="demo-section">
<h3>翻转</h3>
<transition name="flip">
<div v-if="animations.flip" class="demo-box">
翻转入/翻出
</div>
</transition>
</div>
<!-- 弹跳 -->
<div class="demo-section">
<h3>弹跳</h3>
<transition name="bounce">
<div v-if="animations.bounce" class="demo-box">
弹跳入/弹出
</div>
</transition>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Son1',
data() {
return {
animations: {
fade: true,
slide: true,
scale: true,
rotate: true,
flip: true,
bounce: true
}
}
},
methods: {
toggleAnimation(name) {
this.animations[name] = !this.animations[name]
},
formatName(name) {
return name.charAt(0).toUpperCase() + name.slice(1)
}
}
}
</script>
<style scoped>
.animation-gallery {
padding: 1rem;
}
.controls {
margin-bottom: 2rem;
}
.demos {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.demo-box {
background: #3b82f6;
color: white;
padding: 2rem;
border-radius: 0.5rem;
text-align: center;
}
/* 淡入淡出 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/* 滑动 */
.slide-enter-active,
.slide-leave-active {
transition: all 0.5s ease;
}
.slide-enter-from,
.slide-leave-to {
transform: translateX(100%);
opacity: 0;
}
/* 缩放 */
.scale-enter-active,
.scale-leave-active {
transition: all 0.5s ease;
}
.scale-enter-from,
.scale-leave-to {
transform: scale(0);
opacity: 0;
}
/* 旋转 */
.rotate-enter-active,
.rotate-leave-active {
transition: all 0.5s ease;
}
.rotate-enter-from,
.rotate-leave-to {
transform: rotate(180deg);
opacity: 0;
}
/* 翻转 */
.flip-enter-active,
.flip-leave-active {
transition: all 0.5s ease;
}
.flip-enter-from,
.flip-leave-to {
transform: perspective(400px) rotateY(90deg);
opacity: 0;
}
/* 弹跳 */
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
Son2.vue
<template>
<div class="list-demo">
<div class="controls">
<button @click="addItem" class="btn">添加项目</button>
<button @click="removeItem" class="btn">移除项目</button>
<button @click="shuffleItems" class="btn">打乱项目</button>
</div>
<div class="list-container">
<transition-group name="list" tag="ul" class="demo-list">
<li
v-for="item in items"
:key="item.id"
class="list-item"
>
{{ item.text }}
<button
@click="removeSpecificItem(item.id)"
class="btn-remove"
>
×
</button>
</li>
</transition-group>
</div>
</div>
</template>
<script>
export default {
name: 'Son2',
data() {
return {
nextId: 1,
items: [
{ id: 0, text: '初始项目' }
]
};
},
methods: {
addItem() {
this.items.push({ id: this.nextId++, text: `项目 ${this.nextId}` });
},
removeItem() {
this.items.pop();
},
shuffleItems() {
this.items = this.items.sort(() => Math.random() - 0.5);
},
removeSpecificItem(id) {
this.items = this.items.filter(item => item.id !== id);
}
}
};
</script>
<style scoped>
.list-demo {
padding: 1rem;
}
.demo-list {
list-style: none;
padding: 0;
margin: 2rem 0;
}
.list-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
margin: 0.5rem 0;
background: white;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
transition: all 0.3s;
}
.list-item:hover {
transform: translateX(5px);
border-color: #3b82f6;
}
.btn-remove {
padding: 0.25rem 0.5rem;
border: none;
background: none;
color: #ef4444;
cursor: pointer;
font-size: 1.25rem;
}
/* 列表过渡效果 */
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from {
opacity: 0;
transform: translateX(30px);
}
.list-leave-to {
opacity: 0;
transform: translateX(-30px);
}
/* 确保移动时的平滑过渡 */
.list-move {
transition: transform 0.5s ease;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
App.vue
<template>
<div id="app">
<Father />
</div>
</template>
<script>
import Father from './components/Father.vue'
export default {
name: 'App',
components: {
Father
}
}
</script>
<style>
#app {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
-webkit-font-smoothing: antialiased;
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.demo-section {
margin: 2rem 0;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
}
.btn {
padding: 0.5rem 1rem;
margin: 0.25rem;
border: 1px solid #e2e8f0;
border-radius: 0.375rem;
background: white;
cursor: pointer;
transition: all 0.2s;
}
.btn:hover {
background: #f7fafc;
}
.btn-primary {
background: #3b82f6;
color: white;
border-color: #2563eb;
}
.btn-primary:hover {
background: #2563eb;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
运行这个项目并按页面中的按钮来播放一下动画,体验一下过渡效果和动画效果。
在这里,我们为两个子组件的切换添加了淡入淡出的效果;在 Son1
中演示了页面元素的旋转,滑动,弹跳等动画;在 Son2
中演示了列表项添加、移除、移动时的动画效果。
具体实现方式
1. 淡入淡出动画(Fade)
淡入淡出是最基本的动画效果之一,用于元素的出现和消失时的平滑过渡。在 Vue 中,我们可以使用 <transition>
或 <transition-group>
组件来实现这一效果。
实现步骤:
- 定义动画类: Vue 的过渡机制依赖于 CSS 类来控制动画的开始和结束。对于淡入淡出效果,我们定义了
.fade-enter-active
、.fade-leave-active
、.fade-enter-from
和.fade-leave-to
四个类。 - 设置过渡属性: 在
.fade-enter-active
和.fade-leave-active
中,我们设置了transition: opacity 0.5s ease;
,这表示在进入和离开时,透明度将在 0.5 秒内平滑过渡。 - 控制透明度:
.fade-enter-from
和.fade-leave-to
将元素的透明度设为 0,确保元素在过渡开始时是透明的。
代码解读:
/* 淡入淡出 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
2
3
4
5
6
7
8
9
10
通过以上设置,当元素进入时,从透明度 0 逐渐变为 1,实现淡入效果;当元素离开时,从透明度 1 逐渐变为 0,实现淡出效果。
2. 滑动动画(Slide)
滑动动画用于元素在水平或垂直方向上的移动过渡。在本例中,我们实现了水平滑动效果。
实现步骤:
- 定义动画类: 类似于淡入淡出,我们定义了
.slide-enter-active
、.slide-leave-active
、.slide-enter-from
和.slide-leave-to
。 - 设置过渡属性: 使用
transition: all 0.5s ease;
使所有可过渡的属性在 0.5 秒内平滑过渡。 - 控制位置和透明度: 在
.slide-enter-from
中,元素从translateX(100%)
和opacity: 0
开始,滑入视图;在.slide-leave-to
中,元素滑出视图并变得透明。
代码解读:
/* 滑动 */
.slide-enter-active,
.slide-leave-active {
transition: all 0.5s ease;
}
.slide-enter-from,
.slide-leave-to {
transform: translateX(100%);
opacity: 0;
}
2
3
4
5
6
7
8
9
10
11
当元素进入时,它会从右侧滑入;当元素离开时,它会向左侧滑出,同时透明度减少。
3. 缩放动画(Scale)
缩放动画使元素在进入或离开时放大或缩小,增加视觉动感。
实现步骤:
- 定义动画类: 定义
.scale-enter-active
、.scale-leave-active
、.scale-enter-from
和.scale-leave-to
。 - 设置过渡属性: 使用
transition: all 0.5s ease;
实现平滑过渡。 - 控制缩放和透明度: 在
.scale-enter-from
中,元素从scale(0)
和opacity: 0
开始放大;在.scale-leave-to
中,元素缩小并变得透明。
代码解读:
/* 缩放 */
.scale-enter-active,
.scale-leave-active {
transition: all 0.5s ease;
}
.scale-enter-from,
.scale-leave-to {
transform: scale(0);
opacity: 0;
}
2
3
4
5
6
7
8
9
10
11
元素在进入时会从无到有逐渐放大至原始大小;在离开时则相反。
4. 旋转动画(Rotate)
旋转动画使元素在进入或离开时进行旋转,增加动态效果。
实现步骤:
- 定义动画类: 定义
.rotate-enter-active
、.rotate-leave-active
、.rotate-enter-from
和.rotate-leave-to
。 - 设置过渡属性: 使用
transition: all 0.5s ease;
。 - 控制旋转和透明度: 在
.rotate-enter-from
中,元素从rotate(180deg)
和opacity: 0
开始旋转进入;在.rotate-leave-to
中,元素旋转 180 度并变得透明。
代码解读:
/* 旋转 */
.rotate-enter-active,
.rotate-leave-active {
transition: all 0.5s ease;
}
.rotate-enter-from,
.rotate-leave-to {
transform: rotate(180deg);
opacity: 0;
}
2
3
4
5
6
7
8
9
10
11
元素在进入时会旋转 180 度并逐渐显现;在离开时则旋转 180 度并逐渐消失。
5. 翻转动画(Flip)
翻转动画通过 3D 效果使元素在进入或离开时进行翻转,增强视觉冲击力。
实现步骤:
- 定义动画类: 定义
.flip-enter-active
、.flip-leave-active
、.flip-enter-from
和.flip-leave-to
。 - 设置过渡属性: 使用
transition: all 0.5s ease;
。 - 控制 3D 翻转和透明度: 在
.flip-enter-from
中,元素从perspective(400px) rotateY(90deg)
和opacity: 0
开始翻转进入;在.flip-leave-to
中,元素翻转 90 度并变得透明。
代码解读:
/* 翻转 */
.flip-enter-active,
.flip-leave-active {
transition: all 0.5s ease;
}
.flip-enter-from,
.flip-leave-to {
transform: perspective(400px) rotateY(90deg);
opacity: 0;
}
2
3
4
5
6
7
8
9
10
11
通过设置 perspective
和 rotateY
,元素在进入和离开时实现 3D 翻转效果。
6. 弹跳动画(Bounce)
弹跳动画使元素在进入或离开时呈现弹跳效果,增加动感和趣味性。
实现步骤:
- 定义动画类: 定义
.bounce-enter-active
和.bounce-leave-active
。 - 使用关键帧动画: 定义
@keyframes bounce-in
,控制元素的缩放效果。 - 应用动画: 在
.bounce-enter-active
中应用bounce-in
动画,在.bounce-leave-active
中应用反向的bounce-in
动画。
代码解读:
/* 弹跳 */
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
元素在进入时会先快速放大至 1.25 倍,然后回弹到原始大小;在离开时则反向执行相同动画。
通过以上六种动画效果,我们可以为网页元素添加丰富的视觉效果,提高用户体验。在实际开发中,可以根据需求灵活组合和调整这些动画效果,使界面更加生动和有趣。
组件库安装
然而,仅仅添加动画一般无法满足我们开发 web 应用的需求,这时候我们可以调用已有的第三方组件库。下面谈谈组件(按钮,输入框,导航栏,日期选择器,卡片,对话框等)、组件库是什么?别人写好的组件库有多方便?
组件,是指具有特定功能的独立模块,可以重复使用。这里的组件有别于 Vue 中的 component,指的是界面上的一部分,如按钮、输入框、导航栏等。组件库,是指包含多个组件的合集,可以提供丰富的功能和样式,方便开发者快速构建页面。使用组件库的优势就在于,可以减少重复开发,提高开发效率,同时保证界面风格的一致性。
Vue 中有很多优秀的组件库,如 Element Plus、Vuetify、Ant Design Vue 等是比较有名的,它们提供了丰富的组件和功能,和中文的详细文档,可以满足各种开发需求。下面我们以 Vuetify 为例,介绍如何使用组件库。
一般来说,组件库的安装有三种方法:组件库官方脚手架创建项目,包管理器安装并在已有的项目中使用,CDN 引入。一般来说前两种用的比较多,我们下面一一介绍。
官方工具
以 Vuetify 为例,打开 Vuetify 安装页面 即可看到官方对这几种安装方式的介绍。如果要使用官方工具安装,我们执行下面的指令。
pnpm create vuetify
在向导中选择:不使用 typescript,使用 pnpm 作为包管理器
cd 你的项目名
pnpm dev
2
这样就能在项目中直接使用 Vuetify 提供的组件了。
包管理器
接下来是如何在已有项目里安装。在项目目录内执行:
pnpm i vuetify
在 main.js 里添加 vuetify 引入代码即可
import { createApp } from 'vue'
// Vuetify
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import App from './App.vue'
const vuetify = createVuetify({
components,
directives,
})
createApp(App).use(vuetify).mount('#app')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CDN 引入
这种方式适合在简单的项目中使用,不需要安装包管理器,直接在 HTML 文件中引入 Vue 和 Vuetify 的 CDN 链接即可。这种方法并不常用。Vuetify 提供了 CDN 版本的样式和脚本,我们只需要在 HTML 文件中添加以下内容:
<link href="https://cdn.jsdelivr.net/npm/vuetify@3.7.6/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.37/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3.7.6/dist/vuetify.min.js"></script>
2
3
下面将通过一个简单的例子来展示如何在一个 HTML 文件中使用 Vuetify。
- 创建 HTML 文件
创建一个简单的 HTML 文件,通过 CDN 引入 Vue 和 Vuetify,在页面上显示一个 Vuetify 按钮。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuetify CDN 示例</title>
<!-- 引入 Vuetify 的 CSS 样式 -->
<link href="https://cdn.jsdelivr.net/npm/vuetify@3.7.6/dist/vuetify.min.css" rel="stylesheet">
</head>
<body>
<!-- Vue 将会挂载到这个元素 -->
<div id="app"></div>
<!-- 引入 Vue 3 和 Vuetify 的 JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.37/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3.7.6/dist/vuetify.min.js"></script>
<script>
// 从 Vuetify 中获取所需的功能
const { createApp } = Vue;
const { createVuetify } = Vuetify;
// 创建 Vuetify 实例
const vuetify = createVuetify();
// 定义一个简单的 Vue 组件,包含一个 Vuetify 按钮
const Demo = {
template: `
<v-app>
<v-main>
<v-container>
<!-- 使用 Vuetify 的按钮组件 -->
<v-btn color="primary">Vuetify 按钮</v-btn>
</v-container>
</v-main>
</v-app>
`
};
// 创建 Vue 应用并使用 Vuetify
createApp(Demo).use(vuetify).mount('#app');
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2. 解析和说明
引入 Vue 和 Vuetify:
在
<head>
中引入了 Vuetify 的 CSS 样式:html<link href="https://cdn.jsdelivr.net/npm/vuetify@3.7.6/dist/vuetify.min.css" rel="stylesheet">
1在
<body>
结束前引入了 Vue 和 Vuetify 的 JavaScript 文件:html<script src="https://cdn.jsdelivr.net/npm/vue@3.2.37/dist/vue.global.js"></script> <script src="https://cdn.jsdelivr.net/npm/vuetify@3.7.6/dist/vuetify.min.js"></script>
1
2
创建 Vue 组件:
- 我们在
<script>
标签内定义了一个名为Demo
的 Vue 组件。该组件使用了 Vuetify 的<v-btn>
按钮组件,并设置了一个color="primary"
属性,使按钮呈现主色调。 -
v-app
和v-main
是 Vuetify 提供的布局组件,它们确保 UI 元素正确地布局和显示。
- 我们在
创建 Vue 应用:
- 使用
createApp(Demo).use(vuetify).mount('#app')
创建 Vue 应用,并将其挂载到页面上的#app
元素。
- 使用
运行效果
通过上述代码,在浏览器中打开 index.html
文件,你会看到一个主色调的 Vuetify 按钮,点击它会有波纹效果。
与此类似,element plus 也提供了中文文档和包管理器安装、CDN 引入的安装方式,步骤与上文几乎相同,请参阅 Element Plus 安装指南
INFO
对于 element plus,它提供了完整引入和按需引入两种方式,使用包管理器安装完后,请到 Element Plus 快速开始 查看 vite 中的引入两种方式。建议使用按需引入。
使用组件
在项目中安装组件库后,我们接下来学习如何使用它。不同的组件库的语法细节有区别,我们需要随时查阅文档。下面以 Vuetify 为例子,来走一次添加一个组件到页面中的全流程。
INFO
Vuetify 的新版本会默认启用暗色主题,在 src\plugins\vuetify.js
中将 defaultTheme: 'dark'
修改为 light
即可。
我们在项目自动生成的 src\components\HelloWorld.vue
中来做练习,删掉文件内已有的 template
。以一个查询功能为例,我们需要一个输入框和查询按钮。首先就是要在组件库中找到我们想要的组件。
在 vuetify 文档 左侧找到组件,下拉找到输入组件中的单行文本框,打开文档。
文档展示了基本的输入框例子、代码和可用的插槽(可以让我们自己设置的选项)。
文档最顶部的演示代码告诉我们,一个最简单的输入框标签是:
<v-text-field label="标签"></v-text-field>
接下来我们需要定制这个组件。假设我们希望输入框内部有放大镜图标,初始状态显示 “搜索”,点击后显示 “您想查找的是...”。整体风格简洁。
查阅文档中的 “变体” 部分,发现 Solo 样式比较美观,符合场景需求。点击右上角的 “查看源代码” 按钮,查看具体设置。
这样,我们可以确定变体的设置为:
variant="solo"
下一步是添加搜索图标。阅读组件结构部分得知,输入框组件是允许我们在框内前部添加一个图标的,我们在此添加表示搜索的放大镜图标。
接下来我们就可以阅读 “图标” 部分来查看实现方式和语法。在展示区找到我们要的效果,点击 “查看源代码” 按钮,发现在该位置添加图标的语法是:
prepend-inner-icon="mdi-图标名字"
Vuetify 支持多种图标字体(可以理解成图标包),具体可以查看 Vuetify 图标字体。我们接下来用官方推荐的 MDI 图标。来到官网寻找放大镜图标:MDI 图标库
点击想要的图标,复制它的名字 mdi-magnify
并填入我们刚才找到的语法中。
最后是添加占位文字 “您想搜索的是...”。回到 Vuetify 文档,在目录中很容易找到相关语法。
placeholder="文字内容"
最后就是把这些参数组装起来放进文本框标签内,并把用户输入的内容和 Vue 值绑定。假设 keyword 用来保存用户输入的内容。
最终组件如下:
<v-text-field
v-model="keyword"
variant="solo"
prepend-inner-icon="mdi-magnify"
placeholder="您想搜索的是..."
></v-text-field>
2
3
4
5
6
下一步添加搜索按钮或者添加任何组件的步骤都和上述过程一致,大体流程均为:根据业务需要选择合适的组件,在组件库中找到想要的组件,阅读基本写法,阅读该组件支持的各种高级选项并按需要设置。
如果没有找到自己需要的组件,我们可以到 npm 仓库和 GitHub 等平台寻找其他开发者的包,或许会有惊喜。需要注意,组件库并不是万能的。
成熟的组件库为大部分组件提供了强大的 API 和插槽,几乎涵盖了大部分开发需求,非常灵活和强大。因此,阅读文档是非常值得的。
对于 Element Plus 等其他组件库,用法大同小异。下图展示了文档中详细的说明和使用示例。即使遇到尚不完善的组件库,也可以通过阅读官方代码片段了解组件的基本用法。