指令 v-for
- 作用:基于数据循环,多次渲染整个元素 --> 数组、对象、数字...
2. 遍历数组语法:
v-for="(item,index) in 数组"
item 每一项 , index 下标
省略 index:v-for = "item in 数组"
如:数组有4项,则循环四次
<div id="app">
<h1>水果铺</h1>
<ul>
<li v-for="(item,index) in list">
{{item}} - {{index}}
</li>
</ul>
<!-- 如果只需要显示item,那么可简写成下面这样 -->
<ul>
<li v-for="item in list">
{{item}}
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
const app=new Vue({
el:'#app',
data:{
list:['西瓜','草莓','哈密瓜','香蕉']
}
})
</script>
案例——小黑的书架
由于vue是响应式布局,所以只需想办法通过删除数组中的数据则可同步实现页面响应删除
删除列表对应项的两种思路
根据index下标删
根据id删(优先)
- 用
filter(根据条件,保留满足条件的对应项,得到一个新数组,且不会改变原数组)- 将得到的新数组再赋值给原数组
this.book_list=this.book_list.filter(item => item.id!==id)
<div id="book">
<h1>小黑的书架</h1>
<ul>
<li v-for="item in book_list" :key="item.id">
<span>{{item.name}}</span>
<span>{{item.author}}</span>
<button @click="del(item.id)" >删除</button>
<!-- 必须是item.id,而不是直接写id -->
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
const book=new Vue({
el:'#book',
data:{
book_list:[
{id:1,name:'《红楼梦》',author:'曹雪芹'},
{id:2,name:'《西游记》',author:'吴承恩'},
{id:3,name:'《水浒传》',author:'施耐庵'},
{id:4,name:'《三国演义》',author:'罗贯中'}
]
} ,
methods:{
del(id){
this.book_list=this.book_list.filter(item => item.id!==id)
}
}
})
</script>
指令 v-for的 key
- 语法:
key属性 = "唯一标识" - 作用:给列表项添加唯一标识。便于 Vue 进行列表项的正确排序复用
- 注意点:
key的值只能是字符串或数字key的值必须具有唯一性- 推荐使用
id作为key(唯一),不推荐使用index作为key(会变化,不对应)
不加 key 的话: v-for 的默认行为会尝试原地修改元素(就地复用)
如图:列表有4项,点击删除第一项,会因为默认行为只留下前3项,删除最后一项,并且把所有的文字内容都替换到前3个 li 身上。效果为:最后一个 li 被删除了,文字正确了,但第一项的背景颜色依旧存在
指令 v-model
- 作用:给表单元素使用,双向数据绑定 --> 可以快速获取或设置表单元素内容
- 数据变化 --> 视图自动更新
- 视图变化 --> 数据自动更新
- 语法:
v-model = '变量'
<div id="app">
账户:<input type="text" v-model="username"><br><br>
密码: <input type="password" v-model="password"><br><br>
<button @click="log">登录</button>
<button @click="reset">重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
const app=new Vue({
el:'#app',
data:{
username:'',
password:''
} ,
methods:{
log(){
console.log(this.username,this.password)
},
reset(){
this.username=''
this.password=''
}
}
})
</script>
案例——小黑记事本
渲染和删除
- 运用
v-for和key和{{ }}插值表达式 - 运用
v-on调用传参 和filter过滤
<!-- 主体区域 -->
<section id="app">
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input placeholder="请输入任务" class="new-todo" />
</header>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in list" :key="item.id">
<div class="view">
<span class="index">{{ index + 1 }}</span> <label>{{ item.name }}</label>
<!--因为 index 是从0开始的,所以 +1 -->
<button class="destroy" @click="del(item.id)"></button>
</div>
</li>
</ul>
</section>
</section>
<!-- 底部 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
todoName:'',
list:[
{id:1,name:'跑步锻炼20分钟'},
{id:2,name:'复习数组语法'}
]
},
methods:{
del(id){
this.list = this.list.filter(item => item.id !== id)
}
}
})
</script>
添加
- 通过
v-model绑定输入框 --> 实时获取表单元素内容 - 点击按钮进行新增,往数组最前面加
unshift
<!-- 主体区域 -->
<section id="app">
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input v-model="todoName" placeholder="请输入任务" class="new-todo" />
<button @click="add" class="add">添加任务</button>
</header>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in list" :key="item.id">
<div class="view">
<span class="index">{{ index + 1 }}</span> <label>{{ item.name }}</label>
<button class="destroy" @click="del(item.id)"></button>
</div>
</li>
</ul>
</section>
</section>
<!-- 底部 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
todoName:'',
list:[
{id:1,name:'跑步锻炼20分钟'},
{id:2,name:'复习数组语法'}
]
},
methods:{
del(id){
this.list = this.list.filter(item => item.id !== id)
},
add(){
if(this.todoName.trim()===''){ //trim指在处理表单输入时自动去除输入字符串两端的空白字符
alert('请输入任务名称')
return
}
this.list.unshift({
id: +new Date(), //时间戳,在这里临时当一下 id
name: this.todoName
})
this.todoName='' //添加完之后输入框内自动清空
}
}
})
</script>
底部统计和清空
<!-- 主体区域 -->
<section id="app">
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input v-model="todoName" placeholder="请输入任务" class="new-todo" />
<button @click="add" class="add">添加任务</button>
</header>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in list" :key="item.id">
<div class="view">
<span class="index">{{ index + 1 }}</span> <label>{{ item.name }}</label>
<button class="destroy" @click="del(item.id)"></button>
</div>
</li>
</ul>
</section>
<!-- 统计和清空 -->
<!-- 如果没有任务了,就用v-show把底部隐藏掉 -->
<footer class="footer" v-show="list.length>0" >
<!-- 统计 -->
<span class="todo-count">合 计:<strong> {{list.length}}</strong></span>
<!-- 清空 -->
<button @click="cut" class="clear-completed"> 清空任务 </button>
</footer>
</section>
<!-- 底部 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
todoName:'',
list:[
{id:1,name:'跑步锻炼20分钟'},
{id:2,name:'复习数组语法'}
]
},
methods:{
del(id){
this.list = this.list.filter(item => item.id !== id)
},
add(){
if(this.todoName.trim()===''){ //trim指在处理表单输入时自动去除输入字符串两端的空白字符
alert('请输入任务名称')
return
}
this.list.unshift({
id: +new Date(), //时间戳,在这里临时当一下 id
name: this.todoName
})
this.todoName='' //添加完之后输入框内自动清空
},
cut(){
this.list=[]
}
}
})
</script>
指令的修饰符
通过 "." 指明一些指令后缀,不同后缀封装了不同的处理操作 --> 简化代码
- 按键修饰符
@keyup.enter=""键盘回车监听![]()
keyup键盘弹起,加上enter就是回车弹起
- v-model 修饰符
v-model.trim去除首尾空格v-model.number尝试转数字
- 事件修饰符 冒泡是默认存在的(点击子盒子,父盒子也会触发)
@事件名.stop阻止冒泡@事件名.prevent阻止默认行为
v-bind 操作class
语法::class = "对象/数组"
<style>
.pink{
backgroundcolor:pink;
}
.big{
width:200px;
height:200px;
}
</style>
<div class = "box" :class = "{ pink: true, big: true }">哈哈哈</div>
<div class = "box" :class = "['pink','big']">哈哈哈</div>
案例——导航高亮
<div id="app">
<ul>
<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: {
activeIndex:0,
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
v-bind 操作style
语法: :style = "样式对象"
<style>
.box{
backgroundcolor:pink;
width:200px;
height:200px;
}
</style>
<div class = "box" : style = "{ width: '400px', height: '400px',backgroundColor: 'red' }">哈哈哈</div>
还可以
v-model 应用于其他表单元素
<div id="app">
<h3>小黑学习网</h3>
姓名:
<input type="text" v-model="username">
<br><br>
是否单身:
<input type="checkbox" v-model="isSingle">
<br><br>
<!--
前置理解:
1.name:给单选框加上 name 属性可以分组——同一组相互会排斥
2.value:给单选框加上 value 属性,用于提交给后台的数据
结合 Vue 使用 —— v-model
-->
性别:
<input v-model="gender" type="radio" name="gender" value="1">男
<input v-model="gender" type="radio" name="gender" value="2">女
<!--
前置理解:
1.option 需要设置 value 值提供给后台
2.select 的 value 值,关联了选中的 option 的 value 值
结合 Vue 使用 —— v-model
-->
所在城市:
<select v-modle="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: false,
gender: "1",
cityId: '102',
desc: ""
}
})
</script>
计算属性
概念:基于现有的数据,计算出来的新属性。依赖的数据变化,自动重新计算
<div id="app">
<h3>小黑的礼物清单</h3>
<table>
<tr>
<th>名字</th>
<th>数量</th>
</tr>
<tr v-for="(item,index) in list" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.num }}个</td>
</tr>
</table>
<!--目标:统计求和,求得礼物总数-->
<p>礼物总数:{{ totalCount }}个</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
//现有的数据
list: [
{ id: 1, name: '篮球', num: 1 },
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 },
]
},
computed: {
totalCount() {
//基于现有的数据,编写求值逻辑
//计算属性函数内部,可以直接通过 this 访问到 app 实例
//需求:对 this.list 数组里面的 num 进行求和 : reduce
let total = this.list.reduce((sum, item) => sum + item.num, 0)
return total
}
}
})
</script>
computed 计算属性 Vs 方法 methods
computed 计算属性
作用:封装了一段对于数据的处理,求得一个结果
语法:
- 写在
computed配置项中 - 作为属性,直接使用 ——
this.计算属性 {{ 计算属性 }}
缓存特性(提升性能):
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算并再次缓存。
方法 methods
作用:给实例提供一个方法,调用以处理业务逻辑
语法
- 写在
methods配置中 - 作为方法,需要调用 ——
this.方法名(){{ 方法名() }}@事件名 = "方法名"
计算属性的完整写法
计算属性默认的简写,只能读取访问,不能“修改”
如果要“修改” --> 需要写计算属性的完整写法
computed:{
计算属性名:{
get(){ //当计算属性被获取求值时,执行 get (有缓存,优先读缓存)
一段代码逻辑(计算逻辑)
return 结果
},
set(修改的值){ //当计算属性被修改赋值时,执行 set ,修改的值会传递给 set 方法的形参
一段代码逻辑(修改逻辑)
}
}
}
案例:改名
<div id="app">
姓:<input type="text" v-model="firstName"> +
名:<input type="text" v-model="lastName"> =
<span>{{ fullName }}</span>
<button>改名</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: '刘',
lastName: '贝',
},
methods: {
changeName() {
this.fullName = '刘备'
}
},
computed: {
fullName: {
get() {
return this.firstName + this.lastName
},
set(value) {
this.firstName = value.slice(0, 1)
this.lastName = value.slice(1)
}
}
}
})
</script>
案例——成绩
<div id="app" class="score-case">
<div class="table">
<table>
<thead>
<tr>
<th>编号</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody v-if="list.length>0">
<tr v-for = "(item,index) in list" :key = "item.id">
<td>{{ index+1 }}</td> <!--为了保证连续,编号用 index ,并且 +1 -->
<td>{{ item.subject }}</td>
<!--需求:不及格的成绩要标红,当成绩小于 60 时,加上 red 类-->
<td :class="{red:item.score < 60}">{{ item.score }}</td>
<td><a href="#" @click.prevent="del(item.id)">删除</a></td>
</tr>
</tbody>
<!--有数据时就渲染上面的结构,无数据时就渲染下面的结构-->
<tbody v-else>
<tr>
<td colspan="5">
<span class="none">暂无数据</span>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
<span>总分:{{ totalCount }}</span>
<span style="margin-left: 50px">平均分:{{ average }}</span>
</td>
</tr>
</tfoot>
</table>
</div>
<div class="form">
<div class="form-item">
<div class="label">科目:</div>
<div class="input">
<input type="text" placeholder="请输入科目" v-model.trim="subject" />
</div>
</div>
<div class="form-item">
<div class="label">分数:</div>
<div class="input">
<input type="text" placeholder="请输入分数" v-model.number="score" />
</div>
</div>
<div class="form-item">
<div class="label"></div>
<div class="input">
<button class="submit" @click="add">添加</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: [
{ id: 1, subject: '语文', score: 86 },
{ id: 7, subject: '数学', score: 95 },
{ id: 12, subject: '英语', score: 59 },
],
subject: '',
score: ''
},
methods: {
del(id) {
this.list = this.list.filter(item => item.id != id)
},
add() {
if (!this.subject) {
alert("请输入科目")
return
}
if (typeof this.score !== 'number') {
alert("请输入正确的成绩")
}
this.list.unshift({
id: +new Date(),
subject: this.subject,
score: this.score
})
this.subject = ''
this.score = ''
}
},
computed: {
totalCount() {
return this.list.reduce((sum, item) => sum + item.score, 0)
},
average() {
if (this.list.length === 0) {
return 0
}
return (this.totalCount / this.list.length).toFixed(2)
}
}
})
</script>