Vue-基础语法(二)
1. 前言
具体细节参考
Vue
官方文档 ,这一章的内容非常重要,我们开发完成之后会通过一个案例将这些知识点全部串起来。
本文主要将讲解 Vue
的基础语法,包括如下内容:
- 条件渲染( v-if 、v-else、v-else-if、v-show)
- 列表渲染( v-for )
- 属性绑定( v-bind、v-model )
- 事件处理( v-on )
- 计算属性( computed )
- 监听器( watch )
- Class 与 Style 绑定
- 任务清单-案例
2. 条件渲染
如下四个条件渲染指令在开发中使用频率非常高,类似于java中的
if
、else
、else-if
。例如,任务状态信息等需求。
v-if
v-else
v-else-if
v-show
2.1. v-if
v-if
:用于条件判断指令,一般用于界面内容的渲染,该指令会走表达式为true
的分支。
2.2. v-else
v-else
: 一般结合v-if
使用,该指令走与v-if
相反的分支。
2.3. v-else-if
v-else-if
:提供的是相应于v-if的,它可以连续多次重复使用。
v-else
和v-else-if
必须紧跟在v-if
或v-else-if
的后面,并且它们只能与相同父元素的v-if
或v-else-if
一起使用。
具体信息如下图
假设,根据 type
类型展示不同的字母。
HTML
模板
1 | <body> |
Vue
实例和数据
1 | <script> |
- 结果信息
2.4. v-show
v-show
:也是条件渲染指令,控制元素显示或者隐藏。 用法与v-if
一致,但不能和v-else
和v-else-if
一起使用。
假设,根据 type
类型展示不同的字母。
HTML
模板
1 | <body> |
Vue
的实例和数据
1 | <script> |
- 结果信息
2.5. v-if
和 v-show
区别
渲染方式
v-if
:当条件为false
时,元素中不会在DOM
中存在,它会被完全移除。v-show
:当条件为false
时,元素仍然在DOM
中存在,但是通过CSS样式将其隐藏(display)。
性能开销
v-if
:当条件为true
时,Vue
会重新创建元素并渲染。当条件为false
时,元素不会被渲染。这也就是说只要切换条件,元素都需要被创新创建和销毁,如果切换频繁这需要的性能开销就比较大了。v-show
:当条件不管是true
或者false
元素都已经被渲染完成了,所以就不存在切换时的性能开销。
如何选择
v-if
:当条件为false
时,我们也希望减少相关的DOM
数量,那我们使用v-if
就是合适的。例如如下代码中,我希望展示列表页时,删除详情页的页面信息减少请求次数,就可以使用
v-if
来完成。1
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<template>
<div class="class-style">
<!-- 根据状态渲染不同组件 -->
<!-- 当状态为 'list' 时,显示列表页 -->
<list-page v-if="status === 'list'"></list-page>
<!-- 当状态为 'detail' 时,显示详情页 -->
<detail-page v-else-if="status === 'detail'"></detail-page>
</div>
</template>
<script>
import ListPage from './ListPage.vue'; // 导入列表页组件
import DetailPage from './DetailPage.vue'; // 导入详情页组件
export default {
components: {
ListPage,
DetailPage
},
data() {
return {
status: 'list', // 默认状态为 'list'
};
}
};
</script>v-show
:如果需要频繁切换时,而不产生较大的性能开销时,我们就可以使用v-show
。例如如下代码中, 展开/收起文章的详细内容时。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<template>
<div id="app">
<h3>{{ article.title }}</h3>
<button @click="toggleContent(article)">Toggle Content</button>
<div v-show="article.showContent">
{{ article.content }}
</div>
</div>
</template>
<script>
export default {
el: '#app',
data: {
article: { title: 'Article', content: 'Content of Article', showContent: false }
},
methods: {
toggleContent(article) {
article.showContent = !article.showContent;
}
}
};
</script>
3. 列表渲染
列表渲染(
v-for
)是非常非常非常常用的一个指令,在开发中 100% 会使用到的一个指令,类似于java
中的for
循环。
3.1. v-for
v-for
:基于一个数组进行列表的渲染。例如,我们的form
表单就一定会使用到。
- 语法
1 | <li v-for="{ message } in items"> |
假设我们有一个数组,需要将数组里面的元素全部遍历出来,使用 v-for
实现。
HTML
模板1
2
3
4
5
6
7<body>
<div id="app">
<ul v-for="item in items" :key="item.message">
<li>{{ item.message }}</li>
</ul>
</div>
</body>Vue
实例和数据1
2
3
4
5
6
7
8
9
10
11<script>
new Vue({
el: "#app",
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
</script>结果
4. 属性绑定
属性绑定:在前端页面中如果需要将数据绑定在
HTML
元素或者表单的属性上时,我们需要这些属性绑定的值可以随着数据的变化而进行更新。在属性绑定中,常用的指令有如下两种:
v-bind
v-model
4.1. v-bind
v-bind
:用于将数据绑定到HTML
元素 上,使属性值可以动态的随数据的变化而变化。如果绑定的值是
null
或者undefined
,那么该 attribute 将会从渲染的元素上移除。
- 语法
1 | <div v-bind:id="dynamicId"></div> |
- 其中
v-bind
可以省略不写,直接简化为:
1 | <div :id="dynamicId"></div> |
其中针对 v-bind
的典型用法应该时分页条,如下是 Element-ui
分页条 的用法。
1 | <template> |
4.2. v-model
v-model
:用于将数据绑定在 表单元素(文本输入框、复选框、单选按钮等等) 上创建双向绑定数据,可以实现用户的输入与数据之间的同步。
- 语法
1 | <input v-model="message" placeholder="edit me" /> |
假设我们将多个复选框绑定到同一个数组
HTML
模板
1 | <body> |
Vue
实例和数据
1 | <script> |
- 结果
5. 事件处理
事件处理:在前端开发中我们有时需要监听
DOM
事件,并在触发时执行相应的JavaScript
代码,控制数据的变化或执行特定的操作。事件处理的值可以是如下两种:
- 内联事件处理器
- 方法事件处理器
- 自定义事件处理器(后面在组建通信时讲解)
- 按钮修饰符
Vue
语法
1 | <button v-on:click="handler"> Click Me </button> |
- 简写:省略
v-on:
修改为@
1 | <button @click="handler"> Click Me </button> |
5.1. 内联事件处理器
内联事件处理器:指的是在
HTML
元素中指定事件监听函数,类似于JavaScript
的onclick
事件。
假设我们现在通过 内联事件处理器
实现点击按钮数字+1
HTML
模板
1 | <body> |
Vue
实例和数据
1 | <script> |
- 结果
5.2. 方法事件处理器
方法事件处理器:如果简单的案例可以通过
内联事件处理器
进行解决,但业务一旦复杂,那么内联事件处理器
的劣势(不够灵活)就出来了。这个时候我们将点击事件的处理逻辑提出来抽成一个方法,就形成了方法事件处理器
。
假设我们现在通过 方法事件处理器
实现点击按钮数字+1
。如下的案例虽然很简单,但是后续我们
HTML
模板
1 | <body> |
Vue
实例和数据
1 | <script> |
- 结果
6. 计算属性
计算属性:我们在开发中,无法避免两个属性发生计算的,一旦某个属性的值发生变化,那么他们计算出来的结果也一定会发生变化,这个时候就需要使用到属性计算了。
6.1. computed
computed:当其依赖的属性的值发生变化的时,计算属性会重新计算。
- 语法
1 | export default { |
假设我们需要判断当前数组的数量是否显示元素,不使用 计算属性 computed
HTML
模板
1 | <body> |
Vue
实例和数据
1 | <script> |
- 结果
假设我们需要判断当前数组的数量是否显示元素,使用 计算属性 computed
计算属性带来的优点
- 复用性高:如果在后期我们使用组件开发,那将会导致大量的冗余代码。如果使用
computed
把复杂的逻辑封装为一个属性,使模板中的代码更简洁、易读。 - 性能提高: 计算属性具有自动缓存机制,只有当其依赖的响应式数据发生变化时,才会重新计算。
使用 computed
修改之后的代码如下
HTML
模板
1 | <body> |
Vue
实例和数据
1 | <script> |
7. 监听器
监听器:监听观察某个事件(程序)发生变化时,事件发生者(事件源) 就会给注册该事件的监听者(监听器)发送消息,告诉监听者某些信息已经发生变化了。
7.1. watch
watch:在
Vue
中,监听器通常指的是watch
去监听属性来响应数据的变化。
- 浅层监听器语法
1 | export default { |
- 深层监听器语法
1 | export default { |
❔监听器和计算属性有什么区别呢
异步操作:如果说我们需要的数据发生变化需要调用外部
API
时,使用计算属性是不行的,因为计算属性采用的是同步,而监听器采用的异步。监控多个数据变化:如果说我们需要监听多个数据源发生变化,并且只要其中一个数据发生变化时就执行操作。那么监听器是更加合适的。
假设我们使用监听器实现登录功能,需求如下:
- 用户名长度必须大于5
- 密码长度必须大于8
- 登录按钮必须满足以上两个条件才可以登录
HTML
模板
1 | <body> |
Vue
实例和数据
1 |
|
- 结果
8. Class 与 Style 绑定
Class 与 Style 绑定:指的是将
HTML
元素的样式与CSS
类进行联动的过程。
8.1. Class
绑定
通过为 HTML 元素添加一个或多个类名,你可以将元素与预定义的
CSS
样式规则关联起来。
HTML
模板
1 | <div class="box red-border"></div> |
CSS
样式
1 | .box { |
8.2. Style
绑定
内联样式是直接在 HTML 元素中使用
style
属性来定义样式。
HTML
模板
1 | <div style="width: 100px; height: 100px; background-color: lightgray;"></div> |
内联样式虽然灵活,但通常不推荐在大规模项目中频繁使用,因为它容易导致代码混乱,难以维护。
8.3. Vue
绑定 class
属性绑定的一个常见需求场景是操纵元素的
CSS class
列表和内联样式,这个需求是非常常见的。例如我们需要通过按钮控制表单是需要编辑还是保存。
- 语法
1 | <div :class="{ active: isActive }"></div> |
假设我们通过按钮控制字体的样式
HTML
模板
1 | <body> |
Vue
实例和数据
1 | <script> |
css
样式
1 | <style> |
- 结果
如下代码还可以改写为如下样式
1 | <body> |
9. 任务清单-案例
需求如下
- 通过输入框输入任务点,添加到任务列表中;
- 在添加的任务点通过按钮实现任务是否完成以及删除任务点;
- 统计已经完成的任务数量
- 需要将任务列表添加进缓存,实现关闭浏览器也可以展示任务清单列表
效果图如下:
实现前端页面
HTML
前端页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14<body>
<div id="app">
<h3>Todo 任务清单</h3>
<input type="text" placeholder="回车添加任务清单" />
<ul>
<li>
<span> 任务点 </span>
<button> 是否完成 </button>
<button> 删除任务 </button>
</li>
</ul>
<p>已经完成的任务数量:0</p>
</div>
</body>通过输入框输入任务点,添加到任务列表中
HTML
前端页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14<body>
<div id="app">
<h3>Todo 任务清单</h3>
<input type="text" @keyup.enter="addTask" v-model="newTask" placeholder="回车添加任务清单" />
<ul v-for="(task , index) in taskList" :key="index">
<li>
<span> {{ task.task }} </span>
<button> 是否完成 </button>
<button> 删除任务 </button>
</li>
</ul>
<p>已经完成的任务数量:0</p>
</div>
</body>Vue
实例和数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<script>
new Vue({
el: "#app",
data() {
return {
newTask: '',
taskList: []
}
},
methods: {
// 添加任务点
addTask() {
if(this.newTask.trim() !== ''){
this.taskList.push({task: this.newTask});
this.newTask = ''
}
}
}
})
</script>- 结果
在添加的任务点通过按钮实现任务 是否完成 以及 删除任务
HTML
前端页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14<body>
<div id="app">
<h3>Todo 任务清单</h3>
<input type="text" @keyup.enter="addTask" v-model="newTask" placeholder="回车添加任务清单" />
<ul v-for="(task , index) in taskList" :key="index">
<li>
<span :class="{ active: task.isActive }"> {{ task.task }} </span>
<button @click="completedTask(task)">是否完成</button>
<button @click="removeTask(index)">删除任务</button>
</li>
</ul>
<p>已经完成的任务数量:0</p>
</div>
</body>CSS
样式
1
2
3
4
5
6
7<style>
.active{
color: green;
text-decoration: line-through;
}
</style>Vue
实例和数据
1
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<script>
new Vue({
el: "#app",
data() {
return {
newTask: '',
taskList: []
}
},
methods: {
// 添加任务点
addTask() {
if(this.newTask.trim() !== ''){
this.taskList.push({task: this.newTask, isActive: false});
this.newTask = ''
}
},
// 是否完成
completedTask(task) {
task.isActive = !task.isActive
},
// 删除任务
removeTask(index) {
this.taskList.splice(index, 1);
}
}
})
</script>结果
统计已经完成的任务数量
HTML
模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14<body>
<div id="app">
<h3>Todo 任务清单</h3>
<input type="text" @keyup.enter="addTask" v-model="newTask" placeholder="回车添加任务清单" />
<ul v-for="(task , index) in taskList" :key="index">
<li>
<span :class="{ active: task.isActive }"> {{ task.task }} </span>
<button @click="completedTask(task)">是否完成</button>
<button @click="removeTask(index)">删除任务</button>
</li>
</ul>
<p>已经完成的任务数量:{{ finishedTotal }}</p>
</div>
</body>Vue
实例和数据
1
2
3
4
5
6
7
8
9
10
11<script>
new Vue({
el: "#app",
// 属性计算
computed: {
finishedTotal() {
return this.taskList.filter(item => item.isActive).length;
}
}
})
</script>- 结果
需要将任务列表添加进缓存,实现关闭浏览器也可以展示任务清单列表
Vue
实例和数据
1
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<script>
new Vue({
el: "#app",
data() {
return {
newTask: '',
taskList: []
}
},
// 监听数组
watch: {
taskList: {
handler(newTaskList, oldTaskList) {
localStorage.setItem('taskList', JSON.stringify(newTaskList));
},
deep: true
}
},
// 在生命周期中会讲到 created
created() {
const storedTasks = JSON.parse(localStorage.getItem("taskList"));
if (storedTasks) {
this.taskList = storedTasks;
}
}
})
</script>- 结果