欢迎大家订阅【Vue2+Vue3】入门到实践 专栏,开启你的 Vue 学习之旅!
文章目录
- 前言
- 一、指令修饰符
- 二、v-bind对于样式操作的增强
- 三、v-model应用于表单元素
前言
在 Vue.js 中,指令是带有 v- 前缀的特殊属性,不同属性对应不同的功能。通过学习不同的指令,我们能够灵活应对多种业务场景的需求。本章详细讲解了指令修饰符并对 v-bind 以及 v-model 指令进行了拓展。
一、指令修饰符
指令修饰符是用于修改指令行为的特殊后缀,通过 .
指明一些指令后缀,不同后缀封装了不同的处理操作,能够改变指令的默认行为。通过使用修饰符,开发者可以在不增加额外逻辑的情况下,提高Vue应用的功能和可读性。
常用的指令修饰符如下:
①.stop
阻止事件冒泡。使用此修饰符可以防止事件向上冒泡到父元素。
【示例】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.a {
width: 200px;
height: 200px;
background-color: pink;
margin-top: 20px;
}
.b {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div id="app">
<div @click="aFn" class="a">
<div @click="bFn" class="b">B</div> <!-- 使用 .stop 修饰符 -->
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
methods: {
aFn() {
alert('A被点击了');
},
bFn() {
alert('B被点击了');
}
}
});
</script>
</body>
</html>
运行结果:
点击B,会弹出弹窗“B”被点击了”,点击“确定”后会弹出弹窗“A被点击了”
【分析】
在DOM(文档对象模型)事件处理模型中,事件的传播有两个主要阶段:捕获阶段和冒泡阶段。对于在本例中,点击B元素时事件会冒泡到A元素。
事件传播的过程如下:
①捕获阶段:事件从文档的根元素开始,逐层向下传播到触发事件的目标元素(在本例中是B元素)。
②目标阶段:事件到达目标元素(B),此时可以执行目标元素上的事件处理。
③冒泡阶段:事件开始从目标元素向上传播,逐层返回到文档的根元素。在这个阶段,父元素的事件处理器将被触发(在本例中是A元素)。
为防止事件向上冒泡到父元素,可使用 .stop
修饰符,修改代码为:
<div @click="aFn" class="a">
<div @click.stop="bFn" class="b">B</div>
</div>
运行结果:
点击B,会弹出弹窗“B”被点击了”
点击A,会弹出弹窗“A被点击了”
②.prevent
阻止默认事件的发生。常用于表单提交等场景,以防止页面刷新。
【示例】
<a @clickhref="http://www.baidu.com">阻止默认行为</a>
运行结果:
点击页面链接会跳转至百度官网
如果要阻止默认事件的发生,可使用 .prevent
修饰符,修改代码为:
<h3>@事件名.prevent → 阻止默认行为</h3>
<a @click.prevent href="http://www.baidu.com">阻止默认行为</a>
运行结果:
点击页面链接不会发生跳转
③.trim
用于处理输入的字符串。当使用v-model绑定输入框时,去除输入字符串的前后空格。
【示例】
<body>
<div id="app">
姓名:<input v-model="username" type="text"><br>
年纪:<input v-model="age" type="text"><br>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
age: '',
}
})
</script>
</body>
运行结果:
如果要去除输入字符串的前后空格,可使用 .trim
修饰符,修改代码为:
<div id="app">
<h3>修饰符 .trim </h3>
姓名:<input v-model.trim="username" type="text"><br>
年纪:<input v-model="age" type="text"><br>
</div>
运行结果:
④.number
自动将输入字符串转换为数字。适合处理数字输入。
【示例】
<body>
<div id="app">
姓名:<input v-model="username" type="text"><br>
年纪:<input v-model="age" type="text"><br>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
age: '',
}
})
</script>
</body>
运行结果:
如果要将输入字符串转换为数字,可使用 .number
修饰符,修改代码为:
<h3>修饰符 .number</h3>
姓名:<input v-model.trim="username" type="text"><br>
年纪:<input v-model.number="age" type="text"><br>
</div>
运行结果:
二、v-bind对于样式操作的增强
为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名和 style 行内样式进行控制。
①操作class
语法1::class="{类名1 : 布尔值, 类名2 : 布尔值,……}"
对象 → 键就是类名,值是布尔值。如果值为 true,该类存在,否则不存在。
适用场景:一个类名来回切换
【示例】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 200px;
height: 200px;
border: 3px solid #000;
font-size: 30px;
margin-top: 10px;
}
.pink {
background-color: pink;
}
.big {
width: 300px;
height: 300px;
}
</style>
</head>
<body>
<div id="app">
<div class="box">Hello Vue</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app'
})
</script>
</body>
</html>
运行结果:
如果我们需要改变box的样式:
<div id="app">
<div class="box pink big">Hello Vue</div>
</div>
运行结果:
该写法不能根据应用状态动态添加或删除样式类。如果需要根据条件来改变样式,就需要通过添加额外的逻辑来实现,增加代码的复杂度。
可使用动态绑定(例如v-bind:class)根据组件的数据状态动态添加或删除类,修改代码如下:
<div id="app">
<div class="box" :class="{pink:true,big:true}">Hello Vue</div>
</div>
语法2::class="['类名1', '类名2', ……]"
数组 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表
适用场景:批量添加或删除类
【示例】
<div id="app">
<div class="box" :class="['pink','big]">Hello Vue</div>
</div>
【案例——京东秒杀 tab 导航高亮】
请根据所学知识实现以下效果:
核心思路:
- 基于数据动态渲染 tab → v-for
- 设置下标记录高亮的是哪一个 tab → activeIndex
- 基于下标动态控制 class 类名 → v-bind:class
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
ul {
display: flex;
border-bottom: 2px solid #e01222;
padding: 0 10px;
}
li {
width: 100px;
height: 50px;
line-height: 50px;
list-style: none;
text-align: center;
}
li a {
display: block;
text-decoration: none;
font-weight: bold;
color: #333333;
}
li a.active {
background-color: #e01222;
color: #fff;
}
</style>
</head>
<body>
<div id="app">
<ul>
<!-- @click="activeIndex=index": 处理点击事件,将当前项的索引赋值给activeIndex,以便高亮显示当前选中的项
===:为一种比较运算符,称“严格相等”运算符。它用于比较两个值是否相等,同时还会检查它们的类型是否相同。-->
<li v-for="(item,index) in list" :key="item.id" @click="activeIndex=index">
<a :class="{active:index===activeIndex}" href="#">{{item.name}}</a></li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
/* 用于存储选中项的索引,初始值为0 */
activeIndex:0,
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
</script>
</body>
</html>
运行结果:
点击“每日特价”后:
点击“品类秒杀”后:
②操作style
语法::style="{CSS属性名1 : 'CSS属性值', CSS属性名2 : 'CSS属性值', ……}"
适用场景:某个具体属性的动态设置
【示例】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 200px;
height: 200px;
background-color: rgb(187, 150, 156);
}
</style>
</head>
<body>
<div id="app">
<div class="box"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app'
})
</script>
</body>
</html>
运行结果:
使用 v-bind:style
动态地修改元素的样式,修改代码如下:
<div id="app">
<!-- 在 JavaScript 中,属性名不能包含连字符,应使用驼峰命名法(CamelCase)来表示
background-color要写成backgroundColor -->
<div class="box" :style="{width:'400px',height:'400px',backgroundColor:'red'}"></div>
</div>
运行结果:
【案例——进度条效果】
请根据所学知识实现以下效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.progress {
height: 25px;
width: 400px;
border-radius: 15px;
background-color: #272425;
border: 3px solid #272425;
box-sizing: border-box;
margin-bottom: 30px;
}
.inner {
width: 50%;
height: 20px;
border-radius: 10px;
text-align: right;
position: relative;
background-color: #409eff;
background-size: 20px 20px;
box-sizing: border-box;
transition: all 1s;
}
.inner span {
position: absolute;
right: -20px;
bottom: -25px;
}
</style>
</head>
<body>
<div id="app">
<!-- 外层盒子——进度条外框(黑色) -->
<div class="progress">
<!-- 内层盒子——进度(蓝色) -->
<div class="inner" :style="{width:percent+'%'}">
<span>{{percent}}%</span>
</div>
</div>
<!-- 每个按钮通过 Vue 的事件处理 (@click) 设置 percent 数据属性,从而改变进度条的显示百分比 -->
<button @click="percent=25">设置25%</button>
<button @click="percent=50">设置50%</button>
<button @click="percent=75">设置75%</button>
<button @click="percent=100">设置100%</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
percent:0
}
})
</script>
</body>
</html>
运行结果:
点击“设置25%”后:
点击“设置100%”后:
三、v-model应用于表单元素
常见的表单元素都可以用 v-model 绑定关联,以便快速获取或设置表单元素的值。v-model 应用于表单元素时会根据控件类型自动选取正确的方法来更新元素。
【示例】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
textarea {
display: block;
width: 240px;
height: 100px;
margin: 10px 0;
}
</style>
</head>
<body>
<div id="app">
<h3>消息注册</h3>
姓名:
<input type="text" v-model="username">
<br><br>
是否单身:
<input type="checkbox" v-model="isSingle">
<br><br>
<!--
前置理解:
1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥
如果不设置 name 属性,用户就可以同时选择多个选项,违背了单选框的设计初衷
2. value: 给单选框加上 value 属性,用于提交给后台的数据
-->
性别:
<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女
<br><br>
<!--
前置理解:
1. option 需要设置 value 值,提交给后台
2. select 的 value 值,关联了选中的 option 的 value 值
-->
所在城市:
<select v-model="cityId">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">成都</option>
<option value="104">南京</option>
</select>
<br><br>
自我描述:
<textarea v-model="desc"></textarea>
<button>立即注册</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username:'',
isSingle:'',
gender:'',
cityId:'',
desc:''
}
})
</script>
</body>
</html>
运行结果:
填写相关信息后: