全新专栏带你快速掌握Vue2+Vue3

1.插值表达式{{}}
插值表达式是一种Vue的模板语法
我们可以用插值表达式渲染出Vue提供的数据

1.作用:利用表达式进行插值,渲染到页面中
表达式:是可以被求值的代码,JS引擎会将其计算出一个结果
以下的情况都是表达式:
javascript
money + 100
money - 100
money * 10
money / 10
price >= 100 ? '真贵':'还行'
obj.name
arr[0]
fn()
obj.fn()
2.语法
插值表达式语法:{{ 表达式 }}
html
<h3>{{title}}<h3>
<p>{{nickName.toUpperCase()}}</p>
<p>{{age >= 18 ? '成年':'未成年'}}</p>
<p>{{obj.name}}</p>
<p>{{fn()}}</p>
3.错误用法
html
1.在插值表达式中使用的数据 必须在data中进行了提供
<p>{{hobby}}</p> //如果在data中不存在 则会报错
2.支持的是表达式,而非语句,比如:if for ...
<p>{{if}}</p>
3.不能在标签属性中使用 {{ }} 插值 (插值表达式只能标签中间使用)
<p title="{{username}}">我是P标签</p>
2.基础指令
1.内容渲染指令(v-html)
什么是指令? 在 Vue中,带有 v- 前缀 的 特殊 标签属性

指令的作用: Vue会根据不同的**【指令】** ,针对标签实现不同的**【功能】**

2.条件渲染指令(v-show,v-if,v-else,v-else-if)
v-show与v-if
作用:v-show和v-if 用来控制元素的显示与隐藏
语法:
●v-show = "表达式" 表达式值为 true 显示, false 隐藏
●v-if= "表达式" 表达式值 true显示, false 隐藏
原理:
●v-show 原理: 切换 display:none 控制显示隐藏
●v-if 原理:基于条件判断,是否创建 或 移除元素节点
场景:
●v-show 用在 频繁切换显示隐藏的场景 (京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物! 的手机京东)

●v-if 用在要么显示,要么隐藏,不频繁切换的场景(京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物! 底部提示)

v-else,v-else-if
html
<!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>
</head>
<body>
<div id="app">
<p v-if="gender ==1">性别:♂ 男</p>
<p v-else>性别:♀ 女</p>
<hr />
<p v-if="score>90">成绩评定A</p>
<p v-else-if="score>80">成绩评定B</p>
<p v-else-if="score>70">成绩评定C</p>
<p v-else>成绩评定D</p>
</div>
<script src="./vue2.7.16.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
gender: 2,
score: 95,
},
});
</script>
</body>
</html>

3.事件绑定指令(v-on)
**作用:**注册事件 (注册流程:事件名+ 事件处理逻辑 ,事件源哪去了?)
语法:
- v-on:事件名="内联语句"
- v-on:事件名="methods中的函数名"
- v-on:事件名="methods中的函数名(参数)"
**举例:**button注册事件的三种写法
- <button v-on:事件名="内联语句">按钮</button>
- <button v-on:事件名="处理函数">按钮</button>
- <button v-on:事件名="处理函数(实参)">按钮</button>
注意:v-on:
简写为 @
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<button @click="count--">-</button>
<span>{{ count }}</span>
<button v-on:click="count++">+</button>
<hr />
<button @click="del">-</button>
<span>{{ num }}</span>
<button v-on:click="num++">+</button>
<hr />
<button @click="changenNum(-5)">-5</button>
<span>{{ num }}</span>
<button v-on:click="changenNum(10)">+10</button>
</div>
<script src="./vue2.7.16.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100,
num: 0,
},
methods: {
del() {
if (this.num > 0) {
this.num--;
}
},
changenNum(num) {
this.num += num;
},
},
});
</script>
</body>
</html>

4.属性绑定指令(v-bind)
作用: 给元素的属性动态绑定数据 ->例如:<img src=" " >

语法: v-bind:属性名 ="表达式 "
<img v-bind:src="imgUrl" alt="">

简写: v-bind: 可以简写成 => :bind
<img :src="imgUrl" alt="">
html
<!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>
</head>
<body>
<div id="app">
<button v-show="index > 0" @click="index--">上一页</button>
<div>
<img :src="list[index]" alt="" />
</div>
<button v-show="index < list.length - 1" @click="index++">下一页</button>
</div>
<script src="./vue2.7.16.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
index: 0,
list: [
'./imgs/11-00.gif',
'./imgs/11-01.gif',
'./imgs/11-02.gif',
'./imgs/11-03.gif',
'./imgs/11-04.png',
'./imgs/11-05.png',
],
},
});
</script>
</body>
</html>

5.列表渲染指令(v-for)
**作用:**基于数据循环,多次渲染整个元素


v-for可以基于哪些数据进行遍历呢?
数组 ,对象,数字,其中基于【数组】遍历是我们常用的方式
遍历数组的语法:

html
<!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>
</head>
<body>
<div id="app">
<h3>小黑水果店</h3>
<ul>
<li v-for="(item, index) in list">{{ item }} - {{ index }}</li>
</ul>
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
<script src="./vue2.7.16.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: ['西瓜', '苹果', '鸭梨', '榴莲'],
},
});
</script>
</body>
</html>

不加 key-原地修改元素 (就地复用)
v-for的默认行为会尝试原地修改元素(就地复用)


就是根据数据重新渲染li标签,此时要渲染三次性能不好

加key - 正确排序复用
**加key的作用:**给元素添加唯一标识
加了key之后就只会删除一开始的li



6.双向数据绑定(v-model)
**作用:**v-model是给 表单元素 双向数据绑定的,可以快速 获取 或 设置 表单元素内容
双向数据绑定是什么?
① 数据变化 → 视图自动更新
② 视图变化 → 数据自动更新

**语法:**v-model = '变量'

扩展: v-model还可以给select、checkbox、radio、textarea等表单元素使用
html
<!--
* @Date: 2025-01-02 17:38:11
* @LastEditors: zl 1077167261@qq.com
* @LastEditTime: 2025-01-02 17:51:40
* @FilePath: \vue\vue基本语法\5.v-model.html
-->
<!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>
</head>
<body>
<div id="app">
<!--
v-model 可以让数据和视图,形成双向数据绑定
(1) 数据变化,视图自动更新
(2) 视图变化,数据自动更新
可以快速[获取]或[设置]表单元素的内容
-->
文本:<input type="text" v-model="msg" />
<p>{{ msg }}</p>
<hr />
<input type="radio" value="true" name="option" /> 是
<input type="radio" value="false" name="option" /> 否
<hr />
<input type="checkbox" v-model="ischecked" />
<p>当前选择: {{ ischecked }}</p>
<hr />
<label for="fruit">选择水果:</label>
<select v-model="selectedFruit" id="fruit">
<option disabled value="">请选择</option>
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
<option value="orange">橙子</option>
</select>
<p>你选择了: {{ selectedFruit }}</p>
<hr />
账户:<input type="text" v-model="username" /> <br /><br />
密码:<input type="password" v-model="password" /> <br /><br />
<button @click="login">登录</button>
<button @click="reset">重置</button>
</div>
<script src="./vue2.7.16.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: '',
msg: 'hello',
ischecked: true,
selectedFruit: '',
},
methods: {
login() {
console.log(this.username, this.password);
},
reset() {
this.username = '';
this.password = '';
},
},
});
</script>
</body>
</html>

css
html,
body {
margin: 0;
padding: 0;
}
body {index.css
background: #fff;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
#app {
background: #fff;
margin: 180px 0 40px 0;
padding: 15px;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#app .header input {
border: 2px solid rgba(175, 47, 47, 0.8);
border-radius: 10px;
}
#app .add {
position: absolute;
right: 15px;
top: 15px;
height: 68px;
width: 140px;
text-align: center;
background-color: rgba(175, 47, 47, 0.8);
color: #fff;
cursor: pointer;
font-size: 18px;
border-radius: 0 10px 10px 0;
}
#app input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#app input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#app input::input-placeholder {
font-style: italic;
font-weight: 300;
color: gray;
}
#app h1 {
position: absolute;
top: -120px;
width: 100%;
left: 50%;
transform: translateX(-50%);
font-size: 60px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.8);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 16px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
position: relative;
z-index: 2;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
overflow: hidden;
}
.todo-list li {
position: relative;
font-size: 24px;
height: 60px;
box-sizing: border-box;
border-bottom: 1px solid #e6e6e6;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list .view .index {
position: absolute;
color: gray;
left: 10px;
top: 20px;
font-size: 22px;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
.todo-list li .toggle {
opacity: 0;
}
.todo-list li .toggle + label {
/*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
background-repeat: no-repeat;
background-position: center left;
}
.todo-list li .toggle:checked + label {
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}
.todo-list li label {
word-break: break-all;
padding: 15px 15px 15px 60px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
.todo-list li .destroy:hover {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: '×';
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 50px auto 0;
color: #bfbfbf;
font-size: 15px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio: 0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}
html
<!--
* @Date: 2025-01-02 17:54:51
* @LastEditors: zl 1077167261@qq.com
* @LastEditTime: 2025-01-02 18:12:25
* @FilePath: \vue\vue基本语法\6.小黑记事本.html
-->
<!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" />
<link rel="stylesheet" href="./css/index.css" />
<title>记事本</title>
</head>
<body>
<!-- 主体区域 -->
<section id="app">
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input placeholder="请输入任务" class="new-todo" v-model="value" />
<button class="add" @click="add">添加任务</button>
</header>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in lists" :key="item.id">
<div class="view">
<span class="index">{{index+1}}.</span>
<label>{{item.name}}</label>
<button class="destroy" @click="del(index)"></button>
</div>
</li>
</ul>
</section>
<!-- 统计和清空 -->
<footer class="footer">
<!-- 统计 -->
<span class="todo-count"
>合 计:<strong> {{lists.length}} </strong></span
>
<!-- 清空 -->
<button class="clear-completed" @click = delAll()>清空任务</button>
</footer>
</section>
<!-- 底部 -->
<script src="./vue2.7.16.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
id: 3,
value: '',
lists: [
{ id: 1, name: '吃饭饭' },
{ id: 2, name: '睡觉觉' },
{ id: 3, name: '打豆豆' },
],
},
methods: {
del(idx) {
this.lists.splice(idx, 1);
},
add() {
if (this.value.trim()) {
this.lists.unshift({
id: this.id++,
name: this.value,
});
this.value = '';
} else {
alert('请输入任务');
}
},
delAll() {
this.lists = [];
}
},
});
</script>
</body>
</html>

3.指令补充
1.指令修饰符
什么是指令修饰符?
指令修饰符就是通过"."增加一些指令的后缀 ,让这个指令有不同的作用
常用:
① 按键修饰符 @keyup.enter → 键盘回车监听
② v-model修饰符
- v-model.trim → 去除首尾空格
- v-model.number → 转数字
③ 事件修饰符
- @事件名.stop → 阻止冒泡
- @事件名.prevent → 阻止默认行为
- @事件名.stop.prevent --->可以连用 即阻止事件冒泡也阻止默认行为
html
<!--
* @Date: 2025-01-03 09:45:28
* @LastEditors: zl 1077167261@qq.com
* @LastEditTime: 2025-01-03 09:45:33
* @FilePath: \vue\2.watch与computed\1.指令修饰符.html
-->
<!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>
.father {
width: 200px;
height: 200px;
background-color: pink;
margin-top: 20px;
}
.son {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div id="app">
<h3>v-model修饰符 .trim .number</h3>
姓名:<input v-model.trim="username" type="text" /><br />
年纪:<input v-model.number="age" type="text" /><br />
<h3>@事件名.stop → 阻止冒泡</h3>
<div @click="fatherFn" class="father">
<div @click.stop="sonFn" class="son">儿子</div>
</div>
<h3>@事件名.prevent → 阻止默认行为</h3>
<a @click.prevent href="http://www.baidu.com">阻止默认行为</a>
</div>
<script src="./vue.2.7.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
age: '',
},
methods: {
fatherFn() {
alert('老父亲被点击了');
},
sonFn(e) {
// e.stopPropagation()
alert('儿子被点击了');
},
},
});
</script>
</body>
</html>

2.v-model在表单元素中的使用
常见的表单元素都可以用 v-model 绑定关联 → 快速 获取 或 设置 表单元素的值
它会根据 控件类型 自动选取 正确的方法 来更新元素

值得注意的是在单选框与下拉菜单中v-model的使用有一些不一样
html
<!--
* @Date: 2025-01-03 10:10:31
* @LastEditors: zl 1077167261@qq.com
* @LastEditTime: 2025-01-03 10:30:41
* @FilePath: \vue\2.watch与computed\2.v-model操作表单.html
-->
<style>
textarea {
display: block;
width: 240px;
height: 100px;
margin: 10px 0;
}
</style>
<div id="app">
<h3>小黑学习网</h3>
姓名:
<input type="text" v-model="user.username" />
<br /><br />
是否单身:
<input type="checkbox" v-model="user.isSingle" />
<br /><br />
<!--
前置理解:
1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥
2. value: 给单选框加上 value 属性,用于提交给后台的数据
结合 Vue 使用 → v-model
-->
性别:
<input type="radio" name="sex" value="1" v-model="user.sex" />男
<input type="radio" name="sex" value="2" v-model="user.sex" />女 <br /><br />
<!--
前置理解:
1. option 需要设置 value 值,提交给后台
2. select 的 value 值,关联了选中的 option 的 value 值
结合 Vue 使用 → v-model
-->
所在城市:
<select v-model="user.city">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">成都</option>
<option value="104">南京</option>
</select>
<br /><br />
自我描述:
<textarea v-model="user.desc"></textarea>
<button @click="show">立即注册</button>
<hr />
{{ user }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
user: {
username: 'zs',
isSingle: true,
sex: '1',
city: '101',
desc: '你好我叫zs',
},
},
methods: {
show() {
console.log(this.user);
},
},
});
</script>

3.v-bind对样式的操作
为了方便开发者进行样式控制,
Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式 进行控制
① 操作class 类名 语法 :class = "对象/数组"
② 操作style行内样式 语法 :style = "样式对象"
1.操作class类名
操作class 类名 语法 :class = "对象/数组"
- 对象形式

如:

**适用场景:**一个类名,来回切换

- 数组形式

如:

**适用场景:**批量添加或删除类
html
<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>
<div id="app">
<ul>
<li v-for="(item,idx) in list" :key="item.id">
<a @click="getActive(idx)" href="#" :class="{active:item.isActive}"
>{{item.name}}</a
>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: [
{ id: 1, name: '京东秒杀', isActive: true },
{ id: 2, name: '每日特价', isActive: false },
{ id: 3, name: '品类秒杀', isActive: false },
],
},
methods: {
getActive(idx) {
this.list.forEach((item, index) => {
if (idx === index) {
item.isActive = true;
} else {
item.isActive = false;
}
});
},
},
});
</script>

2.操作style样式
语法 :style = "样式对象"

如:

**适用场景:**某个具体属性的动态设置

css
<style>
#app {
margin: 100px auto;
text-align: center;
}
.progress {
margin: 100px auto;
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>
<div id="app">
<div class="progress">
<div class="inner" :style="{width:percent +'%'}">
<span>{{percent}}%</span>
</div>
</div>
<button @click="setPercent(25)">设置25%</button>
<button @click="setPercent(50)">设置50%</button>
<button @click="setPercent(75)">设置75%</button>
<button @click="setPercent(100)">设置100%</button>
<br />
<br />
<button @click="add">开始</button>
<button @click="percent=0">重置</button>
<button @click="clear">停止</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
percent: 50,
timer: null,
},
methods: {
setPercent(num) {
this.percent = num;
},
add() {
//清除定时器
this.clear();
this.timer = setInterval(() => {
this.percent += 1;
if (this.percent >= 100) {
this.clear();
}
}, 300);
},
clear() {
clearInterval(this.timer);
this.timer = null;
},
},
});
</script>

