指令修饰符
通过 “.” 指明一些指令后缀,不同的后缀封装了不同的处理操作 -> 简化代码
按键修饰符
@keyup.enter:键盘回车监听
V-model 修饰符
v-model.trim:去除首尾空格
v-model.number:转数字
事件修饰符
@事件名.stop:组织冒泡
@事件名.prevent:阻止默认行为
V-bind 对于样式操作的增强
为了方便开发者进行样式控制,扩展了 v-bind 的语法,可以针对 class 类名和 style 行内样式进行控制
<body>
<div id="app">
<ul>
<li v-for="(item,index) in list">
<a :class="{active:index === activeIndex}" href="#" @click="activeIndex = index"></a>
</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
activeIndex: 0,
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
</script>
</body>
V-bind 对于样式控制的增强
<body>
<div id="app">
<div class="progress">
<div class="inner" :style="{ width: percent + '%'}">
<span>%</span>
</div>
</div>
<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="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
percent: 0
}
})
</script>
</body>
V-model 应用于其他表单元素
常见的表单元素都可以用 v-model 绑定关联 -> 快速获取或设置表单元素的值。会根据控件类型自动选取正确的方法来更新元素
<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 属性 可以分组 → 同一组互相会互斥
2. value: 给单选框加上 value 属性,用于提交给后台的数据
结合 Vue 使用 → v-model
-->
性别:
<input type="radio" name="gender" v-model="gender" value="1">男
<input type="radio" name="gender" v-model="gender" value="2">女
<br><br>
<!--
前置理解:
1. option 需要设置 value 值,提交给后台
2. select 的 value 值,关联了选中的 option 的 value 值
结合 Vue 使用 → v-model
-->
所在城市:
<select v-model="city">
<option value="001">北京</option>
<option value="002">上海</option>
<option value="003">成都</option>
<option value="004">南京</option>
</select>
<br><br>
自我描述:
<textarea v-model="describe"></textarea>
<button>立即注册</button>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: "",
isSingle: true,
gender: "1",
city: "003",
describe: "it入门到入土"
}
})
</script>
</body>
基础语法
基于现有的属性,计算出来的新属性,依赖数据变化,自动重新计算
<body>
<div id="app">
<h3>小黑的礼物清单🛒<span>?</span></h3>
<table>
<tr>
<th>名字</th>
<th>数量</th>
</tr>
<tr v-for="(item, index) in list" :key="item.id">
<td></td>
<td>个</td>
</tr>
</table>
<p>礼物总数: 个</p>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 现有的数据
list: [
{ id: 1, name: '篮球', num: 3 },
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 },
]
},
computed: {
totalCount () {
let total = this.list.reduce((sum, item) => sum + item.num, 0)
return total
}
}
})
</script>
</body>
计算属性 对比 方法
computed 存在一个缓存特性(提升性能):计算属性会对计算出来的结果进行一个缓存,再次使用直接读取缓存,依赖项变化了,则会重新计算并再次缓存
完整写法
计算属性默认的简写,只能读取访问,不能被修改,如果需要修改,则需要写出完整写法
<body>
<div id="app">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
<p>姓名:</p>
<button @click="updateName">修改姓名</button>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: "",
lastName: ""
},
computed: {
pullName: {
get(){
return this.firstName + this.lastName
},
set(value){
this.firstName = value.slice(0,1);
this.lastName = value.slice(1)
}
}
},
methods: {
updateName() {
this.pullName = "马浩楠"
}
}
})
</script>
</body>
案例
<body>
<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="this.list.length > 0">
<tr v-for="(item,index) in list">
<td></td>
<td></td>
<td :class="{ red: item.score < 60 }"></td>
<td><a href="#" @click="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>总分:</span>
<span style="margin-left: 50px">平均分:</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="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: [
{id: 1, subject: '语文', score: 20},
{id: 7, subject: '数学', score: 99},
{id: 12, subject: '英语', score: 70},
],
subject: '',
score: ''
},
methods: {
del(id) {
this.list = this.list.filter(item => item.id !== id)
},
add() {
this.list.push({id: this.list.length + 1, subject: this.subject, score: this.score})
}
},
computed: {
totalScore(){
return this.list.reduce((previous, item) => previous+item.score, 0)
},
averageScore(){
return this.list.length === 0 ? 0 : (this.totalScore / this.list.length).toFixed(2)
}
}
})
</script>
</body>
简单写法:对简单数据类型直接进行监视
完整写法:添加额外配置项监视复杂数据类型
案例
<body>
<div id="app">
<!-- 条件选择框 -->
<div class="query">
<span>翻译成的语言:</span>
<select v-model="obj.language">
<option value="italy">意大利</option>
<option value="english">英语</option>
<option value="german">德语</option>
</select>
</div>
<!-- 翻译框 -->
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words"></textarea>
<span><i>⌨️</i>文档翻译</span>
</div>
<div class="output-wrap">
<div class="transbox"></div>
</div>
</div>
</div>
<script src="./vue.js"></script>
<script src="./axios.js"></script>
<script>
// 接口地址:https://applet-base-api-t.itheima.net/api/translate
// 请求方式:get
// 请求参数:
// (1)words:需要被翻译的文本(必传)
// (2)lang: 需要被翻译成的语言(可选)默认值-意大利
// -----------------------------------------------
const app = new Vue({
el: '#app',
data: {
words: '',
obj: {
words: '单词',
language: "english"
},
transiate: "",
timerId: ""
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
// words(newValue){
// console.log(newValue)
// }
// 监听对象整体属性
obj: {
deep: true, // 深度监视(监视对象所有属性)
immediate: true, // 是否立刻执行一次 handler
handler(newValue) {
clearTimeout(this.timerId)
this.timerId = setTimeout(async () => {
const res = await axios({
url: "https://applet-base-api-t.itheima.net/api/translate",
params: newValue
})
this.transiate = res.data.data
}, 1000)
}
},
// 单独
/*'obj.words'(newValue){
clearTimeout(this.timerId)
this.timerId = setTimeout(async () => {
const res = await axios({
url: "https://applet-base-api-t.itheima.net/api/translate",
params: {
words: newValue,
lang: this.language
}
})
this.transiate = res.data.data
},1000)
}*/
}
})
</script>
</body>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt=""/></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div :class="{tr:true,active: item.isChecked}" v-for="(item,index) in fruitList" :key="item.id">
<div class="td"><input type="checkbox" v-model="item.isChecked"/></div>
<div class="td"><img :src="item.icon" alt=""/></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button class="decrease" :disabled="item.num === 1" @click="jian(item.id)"> -</button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase" @click="jia(item.id)"> +</button>
</div>
</div>
<div class="td">{{ item.num * item.price }}</div>
<div class="td" @click="del(item.id)">
<button>删除</button>
</div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="checkBox" @click="allChecked"/>
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">{{ totalPrice }}</span></span>
<!-- 结算按钮 -->
<button class="pay">结算( {{ totalCount }} )</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="./vue.js"></script>
<script>
const defaultList = [
{
id: 1,
icon: 'http://autumnfish.cn/static/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: 'http://autumnfish.cn/static/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: 'http://autumnfish.cn/static/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: 'http://autumnfish.cn/static/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: 'http://autumnfish.cn/static/樱桃.png',
isChecked: false,
num: 20,
price: 34,
},
]
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList: JSON.parse(localStorage.getItem("list")) || defaultList,
checkboxAll: false
},
methods: {
del(id) {
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
jia(id) {
this.fruitList.find(item => item.id === id).num++
},
jian(id) {
this.fruitList.find(item => item.id === id).num--
},
allChecked() {
this.fruitList = this.fruitList.map(item => {
item.isChecked = this.checkboxAll
return item
})
}
},
computed: {
totalPrice() {
return this.fruitList.filter(item => item.isChecked)
.reduce((previous, item) => previous + item.num * item.price, 0)
},
checkBox: {
get() {
return this.fruitList.every(item => item.isChecked)
},
set(value) {
this.fruitList.map(item => item.isChecked = value)
}
},
totalCount() {
return this.fruitList.reduce((previous, item) => item.isChecked ? previous + item.num : previous, 0)
}
},
watch: {
fruitList: {
deep: true,
handler(newValue) {
localStorage.setItem("list", JSON.stringify(newValue))
}
}
}
})
</script>
</body>