Vue的基础指令
# Vue的基础指令
# 1. 指令的概念
指令(Directives)是 Vue 为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。Vue 中的指令按照不同的用途可以分为如下 6 大类:
- 内容渲染指令
- 属性绑定指令
- 事件绑定指令
- 双向绑定指令
- 条件渲染指令
- 列表渲染指令
指令是 Vue 开发中最基础、最常用、最简单的知识点,通过使用指令,开发者可以更加方便地操作 DOM 元素,实现动态数据绑定和交互。
# 2. 内容渲染指令
内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下 3 个:
v-text
:用于更新元素的文本内容,会覆盖元素内默认的值。- 插值表达式
:用于将变量绑定到元素的文本内容中,不会覆盖元素内默认的值。
v-html
:用于将包含 HTML 标签的字符串渲染为页面的 HTML 元素。
# 2-1. v-text 指令
v-text
指令用于更新元素的文本内容,会覆盖元素内默认的值。
示例:
<!DOCTYPE html>
<html>
<head>
<title>v-text 示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<!-- 使用 v-text 指令来渲染文本内容 -->
<p v-text="message">原始内容</p> <!-- 这里的 v-text 会替换原始内容 -->
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
data: {
message: '这是使用 v-text 指令渲染的内容' // 绑定的数据
}
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在上述示例中,v-text
指令会将 message
数据的值渲染到 <p>
元素中,并覆盖该元素的原始内容。
# 2-2. 插值表达式
Vue 提供的 语法,专门用来解决
v-text
会覆盖默认文本内容的问题。这种 语法的专业名称是插值表达式(Mustache)。
示例:
<!DOCTYPE html>
<html>
<head>
<title>插值表达式示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<!-- 使用插值表达式来渲染文本内容 -->
<p>{{ message }} 原始内容</p> <!-- 这里的 {{ }} 不会替换原始内容 -->
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
data: {
message: '这是使用插值表达式渲染的内容' // 绑定的数据
}
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在上述示例中,插值表达式 会将
message
数据的值渲染到 <p>
元素中,并保留该元素的原始内容。
# 2-3. v-html 指令
v-text
指令和插值表达式只能渲染纯文本内容。如果要把包含 HTML 标签的字符串渲染为页面的 HTML 元素,则需要用到 v-html
这个指令。
示例:
<!DOCTYPE html>
<html>
<head>
<title>v-html 示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<!-- 使用 v-html 指令来渲染包含 HTML 标签的内容 -->
<p v-html="htmlContent"></p> <!-- 这里的 v-html 会将 HTML 字符串渲染为真正的 HTML 元素 -->
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
data: {
htmlContent: '<strong>这是加粗的内容</strong>' // 绑定的数据,包含 HTML 标签
}
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在上述示例中,v-html
指令会将包含 HTML 标签的字符串 htmlContent
渲染为真正的 HTML 元素。
# 3. 属性绑定指令 (v-bind)
Vue 提供了 v-bind
指令,用于动态绑定 HTML 元素的属性。通过 v-bind
,可以将数据中的值绑定到元素的属性上,实现动态更新。
# 3-1 基本用法
使用 v-bind
指令,可以为元素的属性动态绑定属性值。
示例:
<!DOCTYPE html>
<html>
<head>
<title>属性绑定指令示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<!-- 使用 v-bind 指令动态绑定属性 -->
<img v-bind:src="imageSrc" v-bind:alt="imageAlt">
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
data: {
imageSrc: 'https://example.com/image.jpg', // 动态绑定的图片路径
imageAlt: '示例图片' // 动态绑定的图片描述
}
});
</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
在上述示例中,v-bind:src
将 imageSrc
数据的值绑定到 <img>
元素的 src
属性上,而 v-bind:alt
将 imageAlt
数据的值绑定到 <img>
元素的 alt
属性上。
# 3-2 属性绑定指令的简写形式
由于 v-bind
指令在开发中使用频率非常高,Vue 官方为其提供了简写形式,即可以使用冒号 :
代替 v-bind:
。
示例:
<!DOCTYPE html>
<html>
<head>
<title>属性绑定指令简写形式示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<!-- 使用 v-bind 指令的简写形式 -->
<img :src="imageSrc" :alt="imageAlt">
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
data: {
imageSrc: 'https://example.com/image.jpg', // 动态绑定的图片路径
imageAlt: '示例图片' // 动态绑定的图片描述
}
});
</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
在上述示例中,使用了 :
代替 v-bind:
,简化了代码。
# 3-3 使用 JavaScript 表达式
在 Vue 提供的模板渲染语法中,除了支持绑定简单的数据值外,还支持使用 JavaScript 表达式进行运算,从而动态生成属性值。吗
示例:
<!DOCTYPE html>
<html>
<head>
<title>使用 JavaScript 表达式示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<!-- 使用 v-bind 指令绑定 JavaScript 表达式 -->
<p :title="'当前时间是:' + currentTime">鼠标悬停查看当前时间</p>
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
data: {
currentTime: new Date().toLocaleString() // 动态生成的当前时间字符串
}
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在上述示例中,使用了 JavaScript 表达式 '当前时间是:' + currentTime
来动态生成 title
属性的值,实现了更加灵活的属性绑定。
# 3-4 动态拼接属性值
在使用 v-bind
属性绑定期间,如果绑定的内容需要进行动态拼接,则字符串的外面应该包裹单引号。例如:
<!-- 动态拼接属性值 -->
<template>
<div>
<img :src="'/images/' + imageName + '.jpg'" alt="动态图片">
</div>
</template>
<script>
export default {
data() {
return {
imageName: 'example'
};
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在这个示例中,通过 v-bind
绑定动态拼接的 src
属性值,使其根据 imageName
动态生成图片路径。
注意事项
v-bind
属性绑定的内容里面如果没有加单引号,那么这些参数都会去data里面去找,没有就会报错。
# 3-5 动态绑定css样式
在 Vue 2 中,动态绑定 CSS 样式的写法通常有两种方式:通过动态绑定 class
和动态绑定 style
。
# 1. 动态绑定 class
当你需要根据条件动态地应用一个或多个 CSS 类时,可以使用 :class
动态绑定。以下是一个示例:
<template>
<div :class="{'active': isActive, 'hidden': !isActive}">
这是一个带有动态 class 的 div
</div>
</template>
<script>
export default {
data() {
return {
isActive: true // 控制是否应用 class
};
}
};
</script>
<style>
.active {
color: red;
}
.hidden {
display: none;
}
</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
在这个示例中,:class
根据 isActive
的值来动态应用 active
和 hidden
类。当 isActive
为 true
时,div
将有 active
类并显示红色;当 isActive
为 false
时,div
将应用 hidden
类并被隐藏。
# 2. 三目运算符动态绑定 class
在 Vue 中你也可以使用三目运算符来动态绑定 class
,效果是相同的。用三目运算符会让语法更加简洁,尤其是在你只需要根据条件应用单个类时非常方便。
<template>
<div :class="isActive ? 'active' : 'hidden'">
这是一个带有动态 class 的 div
</div>
</template>
<script>
export default {
data() {
return {
isActive: true // 控制是否应用 class
};
}
};
</script>
<style>
.active {
color: red;
}
.hidden {
display: none;
}
</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
- 如果
isActive
为true
,div
将使用active
类。 - 如果
isActive
为false
,div
将使用hidden
类。
这种方式更为简洁,尤其是在只有两个条件时使用三目运算符是非常合适的。如果有更多的条件或更复杂的逻辑,你可能还是希望用对象语法来绑定 class
,这样会更具可读性。
# 3. 动态绑定 style
如果你想根据某个条件来动态设置内联样式,可以使用 :style
绑定一个对象。下面是一个示例:
<template>
<div :style="divStyle">
这是一个带有动态样式的 div
</div>
</template>
<script>
export default {
data() {
return {
isRed: true // 控制颜色
};
},
computed: {
divStyle() {
return {
color: this.isRed ? 'red' : 'blue',
fontSize: '20px'
};
}
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
在这个示例中,:style
绑定了一个对象,div
的颜色将根据 isRed
的值在红色和蓝色之间切换。
# 4. 事件绑定指令 (v-on)
Vue 提供了 v-on
事件绑定指令,用于为 DOM 元素绑定事件监听器。使用 v-on
指令,可以轻松地为元素添加各种事件监听,如 click
、input
、keyup
等。
# 4-1 基本用法
在 Vue 中,可以使用 v-on
指令绑定事件监听器。语法格式如下:
<!-- 基本语法:v-on:eventName="handlerFunction" -->
<div id="app">
<button v-on:click="handleClick">点击我</button>
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
methods: {
// 声明事件处理函数
handleClick() {
alert('按钮被点击了!');
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在上述示例中,通过 v-on:click
为按钮绑定了 click
事件,当按钮被点击时,会执行 handleClick
方法。
提示
原生 DOM 对象有 onclick
、oninput
、onkeyup
等原生事件,替换为 Vue 的事件绑定形式后,分别为:v-on:click
、v-on:input
、v-on:keyup
。
# 4-2 事件绑定的简写形式
由于 v-on
指令在开发中使用频率非常高,Vue 官方为其提供了简写形式,使用 @
代替 v-on:
。
<!-- 使用 @ 代替 v-on: -->
<div id="app">
<button @click="handleClick">点击我</button>
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
methods: {
// 声明事件处理函数
handleClick() {
alert('按钮被点击了!');
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上述代码中,使用了 @click
代替 v-on:click
,简化了代码。
# 4-3 事件参数对象
在原生的 DOM 事件中,可以在事件处理函数的形参处接收事件参数对象 event
。同样地,在 v-on
指令所绑定的事件处理函数中,也可以接收到事件参数对象 event
。
<div id="app">
<button @click="handleClick">点击我</button>
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
methods: {
// 声明事件处理函数,接收事件对象作为参数
handleClick(event) {
console.log(event); // 打印事件对象
alert('按钮被点击了!');
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在上述示例中,handleClick
方法接收了事件参数对象 event
,可以通过 event
对象获取事件的详细信息。
# 4-4 绑定事件并传参
在使用 v-on
指令绑定事件时,可以通过括号 ()
为事件处理函数传递参数。
<div id="app">
<button @click="handleClick('参数1')">点击我</button>
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
methods: {
// 声明事件处理函数,接收传递的参数
handleClick(param) {
alert('传递的参数是:' + param);
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在上述示例中,handleClick
方法接收了传递的参数 param
,并在警告框中显示该参数。
# 4.5 $event
在事件处理函数中,可以接收事件参数对象 event,它默认作为事件处理函数的第一个参数,与原生 JavaScript 一样。通过 Vue 的 v-on 指令(或其简写 @),我们可以轻松地绑定事件处理函数。
在事件处理函数中如果传递参数,那么默认的事件对象会被覆盖,导致事件对象无法正确使用。
<div id="app">
<!-- 错误示例:传递多个参数,覆盖了事件对象 -->
<button @click="handleClick('参数1')">点击我</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleClick(param) {
console.log('参数:', param); // 这里的 param 是 '参数1',不是事件对象
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在上面的错误示例中,由于 event
被 '参数1'
覆盖。
为了解决这个问题,Vue 提供了特殊变量 $event
,表示原生的事件参数对象 event。通过使用 $event
,可以确保事件对象正确传递到事件处理函数中。
<div id="app">
<!-- 正确示例:使用 $event 保留事件对象 -->
<button @click="handleClick('参数1', $event)">点击我</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleClick(param, event) {
console.log('参数:', param); // 正确输出 '参数1'
console.log('事件对象:', event); // 正确的事件对象
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在这个正确的示例中,通过 $event
变量确保了事件对象能够正确传递到 handleClick
函数中,同时可以传递其他参数。
总结
虽然 Vue 可能在某些情况下自动处理事件对象,但为了代码的可靠性和可读性,建议总是使用 $event
来显式传递事件对象,特别是在传递多个参数时。这可以避免事件对象被覆盖的问题,确保事件对象能够正确传递到事件处理函数中。
# 4-6 事件修饰符
在事件处理函数中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。因此,Vue 提供了事件修饰符,用于更方便地控制事件的触发。常用的事件修饰符如下:
.stop
:调用event.stopPropagation()
阻止事件冒泡。.prevent
:调用event.preventDefault()
阻止默认行为。.capture
:以捕获模式添加事件监听器。.self
:仅当事件发生在该元素本身时触发事件。.once
:事件只触发一次。
<div id="app">
<button @click.stop="handleClick">点击我</button>
<form @submit.prevent="handleSubmit">
<input type="text" v-model="inputValue">
<button type="submit">提交</button>
</form>
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
data: {
inputValue: '' // 输入框的值
},
methods: {
// 声明事件处理函数,处理按钮点击事件
handleClick() {
alert('按钮被点击了,但事件不会冒泡!');
},
// 声明事件处理函数,处理表单提交事件
handleSubmit() {
alert('表单已提交,但页面不会刷新!');
}
}
});
</script>
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
在上述示例中,使用了 .stop
和 .prevent
修饰符,分别阻止了事件冒泡和表单的默认提交行为。
# 4-7 按键修饰符
在监听键盘事件时,我们经常需要判断具体的按键。此时,可以为键盘相关的事件添加按键修饰符,如 .enter
、.tab
、.delete
等。
<div id="app">
<input type="text" @keyup.enter="handleEnter" placeholder="按 Enter 键触发">
<input type="text" @keyup.delete="handleDelete" placeholder="按 Delete 键触发">
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
methods: {
// 声明事件处理函数,处理 Enter 键按下事件
handleEnter() {
alert('Enter 键被按下');
},
// 声明事件处理函数,处理 Delete 键按下事件
handleDelete() {
alert('Delete 键被按下');
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在上述示例中,使用了 .enter
和 .delete
修饰符,分别监听了 Enter 键和 Delete 键的按键事件,并在按键被触发时执行对应的事件处理函数。
# 4-8 常用按键修饰符
Vue 提供了一些常用的按键修饰符,用于处理键盘事件:
.enter
:监听 Enter 键。.tab
:监听 Tab 键。.delete
:监听 Delete 键(捕获 "Delete" 和 "Backspace" 键)。.esc
:监听 Escape 键。.space
:监听空格键。.up
:监听向上箭头键。.down
:监听向下箭头键。.left
:监听向左箭头键。.right
:监听向右箭头键。
<div id="app">
<input type="text" @keyup.enter="handleEnter" placeholder="按 Enter 键触发">
<input type="text" @keyup.esc="handleEscape" placeholder="按 Escape 键触发">
<input type="text" @keyup.space="handleSpace" placeholder="按空格键触发">
</div>
<script>
new Vue({
el: '#app', // Vue 实例挂载的元素
methods: {
// 处理 Enter 键按下事件
handleEnter() {
alert('Enter 键被按下');
},
// 处理 Escape 键按下事件
handleEscape() {
alert('Escape 键被按下');
},
// 处理空格键按下事件
handleSpace() {
alert('空格键被按下');
}
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在上述示例中,使用了 .enter
、.esc
和 .space
修饰符,分别监听了 Enter 键、Escape 键和空格键的按键事件,并在按键被触发时执行对应的事件处理函数。
# 4-9 .native修饰符
在Vue项目中,如果第三方组件没有提供某些点击事件的监听功能,但你需要在某些交互时触发事件,你可以使用.native
修饰符来监听原生的DOM事件。这个方法适用于大多数情况。
<template>
<div>
<!-- 假设第三方组件名为ThirdPartyComponent -->
<ThirdPartyComponent @click.native="handleClick" />
</div>
</template>
<script>
export default {
methods: {
handleClick() {
console.log('Third party component clicked');
// 在这里处理点击事件
}
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.native
修饰符告诉Vue监听的是原生DOM的click
事件,而不是组件自身的自定义事件。
# 5. 双向绑定指令 (v-model)
Vue 提供了 v-model
双向数据绑定指令,用来辅助开发者在不操作 DOM 的前提下,快速获取和更新表单的数据。
# 5-1 基本用法
v-model
指令可以在 <input>
、<textarea>
和 <select>
元素上使用,实现表单输入值和应用数据之间的双向绑定。
<div id="app">
<input v-model="message" placeholder="请输入内容">
<p>输入的内容是:{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: ''
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
在这个例子中,v-model
绑定了 message
变量到 <input>
元素。当用户在输入框中输入内容时,message
的值会自动更新,并且 p
元素中的文本也会随之更新。
# 5-2 收集表单数据
在 Vue 中,使用 v-model
指令可以轻松地实现表单数据的双向绑定。不同类型的输入元素(如文本框、单选框和复选框)的行为和数据收集方式有所不同。
# 1. 文本输入框
对于 <input type="text"/>
,v-model
收集的是 value
值,用户输入的内容就是 value
值。
<template>
<input type="text" v-model="textValue" />
<!-- v-model 绑定到 textValue,收集用户输入的 value 值 -->
</template>
<script>
export default {
data() {
return {
textValue: '' // 用于收集文本输入框的值
};
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2. 单选框(radio)
对于 <input type="radio"/>
,v-model
收集的也是 value
值,并且需要为标签配置 value
值,哪个 value
被收集,哪个 value
所在的单选框就会被选中。
<template>
<div>
<input type="radio" v-model="selectedOption" value="option1" /> 选项1
<input type="radio" v-model="selectedOption" value="option2" /> 选项2
<!-- v-model 绑定到 selectedOption,收集选中的 radio 的 value 值 -->
</div>
</template>
<script>
export default {
data() {
return {
selectedOption: '' // 用于收集单选框的值,哪个 value 被收集,哪个 value 所在的单选框就会被选中。
};
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 3. 复选框(checkbox)
对于 <input type="checkbox"/>
,收集方式有两种情况,取决于是否配置 value
属性以及 v-model
的初始值类型。
1. 没有配置 value
属性
- 如果没有配置
input
的value
属性,v-model
收集的是checked
状态(勾选或未勾选,是布尔值)。 - 对于多个独立的复选框,每个复选框需要一个独立的
data
属性值来存储其checked
状态:
<template>
<input type="checkbox" v-model="isChecked" /> 勾选状态
<!-- v-model 绑定到 isChecked,收集 checked 状态(布尔值) -->
</template>
<script>
export default {
data() {
return {
isChecked: false // 用于收集复选框的勾选状态
};
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
2. 配置 value
属性
(1) v-model
的初始值是非数组,收集的是 checked
状态(勾选或未勾选,是布尔值)。
当 v-model
的初始值不是数组时(例如一个布尔值),复选框会根据其 checked
状态(是否勾选)来更新 v-model
绑定的变量。即使配置了 value
属性,v-model
仍然会收集 checked
状态,并不会收集value的值。
<template>
<input type="checkbox" v-model="isAgreed" value="agree" /> 同意条款
<!-- v-model 绑定到 isAgreed,收集 checked 状态(布尔值) -->
</template>
<script>
export default {
data() {
return {
isAgreed: false // 用于收集复选框的勾选状态
};
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
(2) v-model
的初始值是数组,收集的是 value
组成的数组。
对于 v-model
的初始值是数组的复选框,数组中收集了哪些 value
,相应的复选框就会被选中。如果数组中包含某个复选框的 value
值,那么该复选框就会显示为选中状态。
<template>
<div>
<input type="checkbox" v-model="checkedValues" value="value1" /> 选项1
<input type="checkbox" v-model="checkedValues" value="value2" /> 选项2
<!-- v-model 绑定到 checkedValues,收集选中的复选框的 value 值,组成数组 -->
</div>
</template>
<script>
export default {
data() {
return {
checkedValues: [] // 用于收集复选框的值组成的数组
};
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 4. 复选框的最佳实践
对于复选框的使用,确实建议采用第三种写法,即配置 value
属性并使用数组来管理多个复选框的状态。这种方式更加简洁和高效,尤其是在复选框数量较多的情况下。此外,如果采用第一种写法,没有配置 value
属性,并且需要独立管理每个复选框的 checked
状态,这种方式与单选框的使用方式类似,但没有单选框的互斥性。
# 5-3 v-model 表单示例
下面是一个使用纯 HTML 和 Vue.js 的示例,通过 v-model
实现表单输入值和应用数据之间的双向绑定,并在表单提交时将数据传递给后端,同时在页面上渲染一个表格来显示提交的数据。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue v-model 示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<link rel="stylesheet" href="./css/carousel.css"> <!-- 引入CSS文件 -->
</head>
<body>
<div id="app">
<h1>Vue v-model 表单示例</h1>
<form @submit.prevent="submitForm">
<!-- 输入框 (input) 示例 -->
<div>
<label for="inputMessage">输入内容:</label>
<input id="inputMessage" v-model="formData.message" placeholder="请输入内容">
</div>
<!-- 多行文本框 (textarea) 示例 -->
<div>
<label for="textareaMessage">多行文本:</label>
<textarea id="textareaMessage" v-model="formData.textareaMessage" placeholder="请输入多行文本"></textarea>
</div>
<!-- 选择框 (select) 示例 -->
<div>
<label for="selectOption">选择一个选项:</label>
<select id="selectOption" v-model="formData.selectedOption">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</div>
<button type="submit">提交</button>
</form>
<h2>提交的数据</h2>
<table> <!-- 表格 -->
<thead>
<tr>
<th>输入内容</th>
<th>多行文本</th>
<th>选择的选项</th>
</tr>
</thead>
<tbody>
<tr v-for="(data, index) in submittedData" :key="index">
<td>{{ data.message }}</td>
<td>{{ data.textareaMessage }}</td>
<td>{{ data.selectedOption }}</td>
</tr>
</tbody>
</table>
</div>
</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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
form div {
margin: 20px 0;
}
label {
display: block;
margin-bottom: 5px;
}
input, textarea, select {
width: 300px;
padding: 5px;
font-size: 16px;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #3a8d75;
}
table {
margin: 20px auto;
border-collapse: collapse;
width: 80%;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: center;
}
th {
background-color: #f4f4f4;
}
</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
<script>
new Vue({
el: '#app',
data() {
return {
formData: {
message: '', // 存储输入框内容
textareaMessage: '', // 存储多行文本框内容
selectedOption: '' // 存储选择框选项
},
submittedData: [] // 存储提交的数据
}
},
methods: {
submitForm() {
// 打印表单数据,确认数据被正确捕获
console.log(this.formData);
// 添加表单数据到 submittedData 数组
this.submittedData.push({ ...this.formData });
// 发送表单数据到后端
axios.post('https://example.com/api/submit', this.formData)
.then(response => {
// 处理响应数据
console.log('提交成功:', response.data);
})
.catch(error => {
// 处理错误
console.error('提交失败:', error);
});
// 清空表单数据
this.formData.message = '';
this.formData.textareaMessage = '';
this.formData.selectedOption = '';
}
}
});
</script>
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
// Make sure to add code blocks to your code group
表单元素:
- 使用
v-model
指令绑定输入框、文本框和选择框的值到formData
对象中相应的属性。 formData
对象包含message
、textareaMessage
和selectedOption
属性,用于存储表单输入的数据。
表单提交:
- 使用
@submit.prevent="submitForm"
监听表单提交事件,并调用submitForm
方法。 - 在
submitForm
方法中,首先打印表单数据以确认数据捕获正确,然后将表单数据添加到submittedData
数组中,用于在表格中显示。 - 使用 Axios 将数据发送到后端,成功或失败后打印响应。
表格渲染:
- 使用
v-for
指令迭代submittedData
数组,并生成表格行。 - 表格显示已提交的数据,包括输入内容、多行文本和选择的选项。
# 5-4 v-model 指令的修饰符
为了方便对用户输入的内容进行处理,Vue 为 v-model
指令提供了 3 个修饰符:
# .lazy
修饰符
默认情况下,v-model
会同步更新数据,当输入框的值变化时立即更新绑定的变量。.lazy
修饰符可以将更新触发条件改为在输入框失去焦点或按下回车键时进行。
<div id="app">
<input v-model.lazy="message" placeholder="请输入内容">
<p>输入的内容是:{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: ''
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
在这个例子中,只有当输入框失去焦点或按下回车键时,message
的值才会更新。
# .number
修饰符
.number
修饰符可以将用户输入的字符串值自动转换为数值类型。
<div id="app">
<input v-model.number="age" placeholder="请输入年龄">
<p>输入的年龄是:{{ age }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
age: ''
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
在这个例子中,用户输入的内容会被自动转换为数值并存储在 age
变量中。
# .trim
修饰符
.trim
修饰符可以自动移除用户输入的首尾空格。
<div id="app">
<input v-model.trim="name" placeholder="请输入姓名">
<p>输入的姓名是:{{ name }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
name: ''
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
在这个例子中,用户输入的内容会被自动去掉首尾空格并存储在 name
变量中。
# 6. 条件渲染指令
条件渲染指令用于按需控制 DOM 元素的显示与隐藏,在 Vue 中有两种主要的条件渲染指令:
v-if
:用于根据表达式的真假值,动态地创建或移除 DOM 元素。v-show
:用于根据表达式的真假值,通过切换元素的display
样式来控制元素的显示与隐藏。
# 6-1 v-if 指令
v-if
指令用于根据表达式的真假值,动态地创建或移除 DOM 元素。
<!-- v-if 用法示例 -->
<div id="app">
<p v-if="isVisible">这段文本会根据 isVisible 的值显示或隐藏。</p>
</div>
<script>
new Vue({
el: '#app',
data: {
isVisible: true // 控制文本显示或隐藏
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
在上面的例子中,当 isVisible
为 true
时,<p>
元素会被渲染到 DOM 中;当 isVisible
为 false
时,<p>
元素会从 DOM 中移除。
# 6-2 v-show 指令
v-show
指令用于根据表达式的真假值,通过切换元素的 display
样式来控制元素的显示与隐藏。
<!-- v-show 用法示例 -->
<div id="app">
<p v-show="isVisible">这段文本会根据 isVisible 的值显示或隐藏。</p>
</div>
<script>
new Vue({
el: '#app',
data: {
isVisible: true // 控制文本显示或隐藏
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
在上面的例子中,无论 isVisible
的值如何,<p>
元素始终存在于 DOM 中,只是通过 display: none
样式来控制显示或隐藏。
# 6-3 v-if 和 v-show 的区别
实现原理不同
v-if
:动态地创建或移除 DOM 元素,从而控制元素在页面上的显示与隐藏。v-show
:通过动态添加或移除style="display: none;"
样式来控制元素的显示与隐藏。
性能消耗不同
v-if
:有更高的切换开销,适合在运行时条件很少改变的情况下使用。v-show
:有更高的初始渲染开销,适合需要非常频繁地切换显示状态的情况下使用。
# 6-4 v-else 指令
v-if
可以单独使用,也可以与 v-else
指令配合使用,v-else
指令用于在 v-if
判断为 false
时,显示相应的元素。
<!-- v-if 和 v-else 配合使用 -->
<div id="app">
<p v-if="isVisible">显示状态为真。</p>
<p v-else>显示状态为假。</p>
</div>
<script>
new Vue({
el: '#app',
data: {
isVisible: false // 控制文本显示或隐藏
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
在上面的例子中,当 isVisible
为 true
时,显示状态为真;当 isVisible
为 false
时,显示状态为假。
注意
v-else
指令必须紧跟在 v-if
指令或 v-else-if
指令之后,否则不会被识别。
# 6-5 v-else-if 指令
v-else-if
指令,顾名思义,充当 v-if
的“else-if 块”,可以连续使用来判断多个条件。
<!-- v-if 和 v-else-if 和 v-else 配合使用 -->
<div id="app">
<p v-if="status === 'success'">操作成功。</p>
<p v-else-if="status === 'pending'">操作进行中。</p>
<p v-else>操作失败。</p>
</div>
<script>
new Vue({
el: '#app',
data: {
status: 'pending' // 控制文本显示内容
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在上面的例子中,status
的值可以为 'success'
、'pending'
或其他值,页面会根据不同的 status
显示相应的信息。
注意
v-else-if
指令必须紧跟在 v-if
指令或其他 v-else-if
指令之后,否则不会被识别。
# 7. 列表渲染指令 (v-for)
Vue 提供了 v-for
列表渲染指令,用来帮助开发者基于一个数组来循环渲染一个列表结构。v-for
指令需要使用 item in items
形式的特殊语法,其中:
items
是待循环的数组item
是被循环的每一项
提示
v-for
指令加在哪个标签上,哪个标签就会被循环生成,包括该标签内部的内容。也就是说,包含 v-for
的标签及其子元素都会被循环生成。
# 7-1 v-for 的基本用法
# 1. 遍历数组
语法:v-for="item in items"
<!-- 遍历数组 -->
<ul>
<!-- v-for 指令加在 <li> 标签上,循环生成 <li> 元素 -->
<li v-for="(item, index) in items" :key="index">
<!-- item 是数组的每一项,index 是当前项的索引 -->
{{ item }}
</li>
</ul>
2
3
4
5
6
7
8
要遍历的数组结构:
data() {
return {
items: ['苹果', '香蕉', '橙子'] // 待遍历的数组
}
}
2
3
4
5
# 2. 遍历对象
语法:v-for="(value, key) in object"
<!-- 遍历对象 -->
<ul>
<!-- v-for 指令加在 <li> 标签上,循环生成 <li> 元素 -->
<li v-for="(value, key) in object" :key="key">
<!-- key 是对象的属性名,value 是对象的属性值 -->
{{ key }}: {{ value }}
</li>
</ul>
2
3
4
5
6
7
8
要遍历的对象结构:
data() {
return {
object: { name: 'Alice', age: 25, city: 'New York' } // 待遍历的对象
}
}
2
3
4
5
# 3. 遍历数组中的对象
语法:v-for="item in items"
<!-- 遍历数组中的对象 -->
<table>
<thead>
<tr>
<th>属性1</th>
<th>属性2</th>
<th>属性3</th>
</tr>
</thead>
<tbody>
<!-- v-for 指令加在 <tr> 标签上,循环生成 <tr> 元素及其子元素 -->
<tr v-for="item in items" :key="item.id">
<!-- item 是数组的每一个对象 -->
<td>{{ item.property1 }}</td>
<td>{{ item.property2 }}</td>
<td>{{ item.property3 }}</td>
</tr>
</tbody>
</table>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
要遍历的数组中的对象结构:
data() {
return {
items: [
{ id: 1, property1: '值1-1', property2: '值1-2', property3: '值1-3' },
{ id: 2, property1: '值2-1', property2: '值2-2', property3: '值2-3' },
{ id: 3, property1: '值3-1', property2: '值3-2', property3: '值3-3' }
] // 待遍历的数组中的对象
}
}
2
3
4
5
6
7
8
9
# 4. 简单示例
以下是一个使用 v-for
渲染列表的示例:
<div id="app">
<ul>
<!-- 使用 v-for 指令循环渲染列表 -->
<li v-for="item in items">{{ item }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
items: ['苹果', '香蕉', '橙子'] // 待渲染的数组
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在上面的例子中,v-for
指令用于遍历 items
数组,并将每一项 item
渲染为列表项 <li>
。
# 7-2 v-for 中的索引
v-for
指令还支持一个可选的第二个参数,即当前项的索引。语法格式为 (item, index) in items
,示例如下:
<div id="app">
<ul>
<!-- 使用 v-for 指令循环渲染列表,并包含索引 -->
<li v-for="(item, index) in items">{{ index }} - {{ item }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
items: ['苹果', '香蕉', '橙子'] // 待渲染的数组
}
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在上面的例子中,v-for
指令不仅遍历 items
数组,还提供了每一项的索引 index
。
注意
v-for
指令中的 item
项和 index
索引都是形参,可以根据需要进行重命名,例如 (user, i) in userlist
。
# 7-3 使用 key 维护列表的状态
当列表的数据发生变化时,默认情况下,Vue 会尽可能地复用已存在的 DOM 元素,从而提升渲染性能。但这种默认的性能优化策略,可能导致有状态的列表无法被正确更新。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染性能,需要为每项提供一个唯一的 key
属性。
以下是一个使用 key
属性的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue v-for 渲染四列表格示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<h1>水果列表</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>颜色</th>
<th>价格</th>
</tr>
</thead>
<tbody>
<!-- 使用 v-for 指令循环渲染表格的行,并为每一行提供唯一的 key 属性 -->
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.color }}</td>
<td>{{ item.price }}</td>
</tr>
</tbody>
</table>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
items: [
{ id: 1, name: '苹果', color: '红色', price: '$1.00' },
{ id: 2, name: '香蕉', color: '黄色', price: '$0.50' },
{ id: 3, name: '橙子', color: '橙色', price: '$0.80' },
{ id: 4, name: '葡萄', color: '紫色', price: '$2.00' }
] // 待渲染的数组
}
}
});
</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
45
46
47
48
49
<style>
table {
width: 50%;
margin: 0 auto;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
th {
background-color: #f4f4f4;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Make sure to add code blocks to your code group
在上面的例子中,每一项都提供了一个唯一的 key
属性,以确保 Vue 能够正确地跟踪每个节点的身份。
# 7-4 key 的注意事项
在使用 v-for
指令时,指定 key
属性时需要注意以下几点:
key
的值只能是字符串或数字类型。key
的值必须具有唯一性(即:key
的值不能重复)。- 建议将数据项
id
属性的值作为key
的值,因为id
属性的值具有唯一性。 - 使用
index
的值当作key
的值没有任何意义,因为index
的值不具有唯一性。 - 建议使用
v-for
指令时一定要指定key
的值,既提升性能,又防止列表状态紊乱。
为什么不能用索引index作为key?
使用 index
作为 key
会导致在数组项重新排序或更新时,Vue 无法正确地复用已有节点,从而降低性能并可能导致状态丢失。
# 7-5 表格添加删除示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue.js 表格示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<h2>数据表格</h2>
<!-- 输入框组,用于添加新数据 -->
<div class="form-group">
<label for="name">姓名:</label>
<input type="text" id="name" v-model="newName" placeholder="输入姓名">
</div>
<div class="form-group">
<label for="age">年龄:</label>
<input type="number" id="age" v-model="newAge" placeholder="输入年龄">
</div>
<button @click="addData">添加数据</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 使用 v-for 指令遍历 list 数组,并生成表格行 -->
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<!-- 删除按钮,点击时调用 removeData 方法 -->
<td><button @click="removeData(item.id)">删除</button></td>
</tr>
</tbody>
</table>
</div>
<script>
new Vue({
el: '#app',
data: {
newName: '', // 用于存储新添加数据的姓名
newAge: '', // 用于存储新添加数据的年龄
list: [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
], // 存储数据列表
nextId: 3 // 下一个数据项的 ID
},
methods: {
// 添加数据的方法
addData() {
// 检查姓名和年龄是否为空
if (this.newName && this.newAge) {
// 将新数据项添加到 list 数组中
this.list.push({ id: this.nextId++, name: this.newName, age: parseInt(this.newAge) });
// 清空输入框
this.newName = '';
this.newAge = '';
}
},
// 删除数据的方法
removeData(id) {
// 使用 filter 方法过滤掉要删除的项
this.list = this.list.filter(item => item.id !== id);
}
}
});
</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
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
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th,
td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
th {
background-color: #f4f4f4;
}
button {
padding: 8px 16px;
margin: 5px;
border: none;
background-color: #42b983;
color: white;
cursor: pointer;
}
button:hover {
background-color: #3a8d75;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input {
width: calc(100% - 16px);
padding: 8px;
margin-bottom: 10px;
}
</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
// Make sure to add code blocks to your code group
# 1. 效果演示
# 2. 代码分析
1. 数据绑定:
- 使用
v-model
绑定输入框的值到newName
和newAge
,用于输入新数据。
2. 添加数据:
addData
方法检查输入框是否有值,然后将新数据添加到list
数组中,并清空输入框。新增数据时自动生成唯一的 ID。
addData() {
// 检查姓名和年龄是否为空
if (this.newName && this.newAge) {
// 将新数据项添加到 list 数组中
this.list.push({
id: this.nextId++, // 自动生成唯一的 ID
name: this.newName, // 输入的姓名
age: parseInt(this.newAge) // 输入的年龄,转换为整数
});
// 清空输入框
this.newName = '';
this.newAge = '';
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
在这个方法中,push
方法用于将一个新对象(包含 id
、name
和 age
属性)添加到 list
数组的末尾,并返回数组的新长度。这种方式非常适合用于动态添加数据到数组中。
3. 删除数据:
删除方案一:removeData
方法使用 filter
方法根据 ID
删除对应的数据项。
// 删除方案一 (不局限于索引,适合用于有唯一标识符(如 ID)的数据项删除操作)
removeData(id) {
// 使用 filter 方法过滤掉要删除的项
this.list = this.list.filter(item => item.id !== id);
}
2
3
4
5
6
7
- 使用
filter
方法:filter
方法不修改原数组,而是返回一个新的数组,包含所有通过筛选函数的元素。 - 参数:
filter
的参数是一个函数,在这里是(item => item.id !== id)
,表示保留所有id
不等于给定id
的元素。
删除方案二:removeData
方法使用 splice
方法根据 index
删除对应的数据项。
// 删除方案二 (只能根据索引删除,必须知道要删除元素的具体位置)
removeData(index) {
this.list.splice(index, 1);
}
2
3
4
- 使用
splice
方法:splice
方法直接修改原数组,在指定的位置删除指定数量的元素。 - 参数:
splice
的参数是元素的索引和删除的数量。在这里,index
是元素的索引,1
表示删除一个元素。
4. 表格渲染:
- 使用
v-for
指令遍历list
数组,并生成表格行。 - 使用
:key
属性为每个数据项提供唯一的标识。
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<!-- 删除按钮,点击时调用 removeData 方法 -->
<td><button @click="removeData(item.id)">删除</button></td>
</tr>
2
3
4
5
6
7