目录
- <<回到导览
- vue基础知识
- 1.1.创建一个vue实例
- 1.2.vue基础指令
- 1.2.1.v-bind
- 1.2.2.v-model
- 1.2.3.常用事件
- 1.2.4.指令修饰符
- 1.3.计算属性
- 1.3.1.计算属性的完整写法
- 1.3.2.【案例】成绩
- 1.4.watch
- 1.4.1.watch属性
- 1.4.2.翻译业务实现
- 1.4.3.watch属性的完整写法
- 1.4.4.【案例】水果购物车
- 1.5.生命周期
- 1.5.1.【应用】初始化渲染
- 1.5.2.【应用】获取焦点
<<回到导览
vue基础知识
mvvm模型
响应式数据,一旦数据变化,视图效果跟着变化
1.1.创建一个vue实例
-
代码:
<!-- 1.准备容器 --> <div id="app">{{msg}}{{age-1}}</div> <!-- 2.引入开发版本的包 --> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script> <script> // 3.创建实例 const app = new Vue({ // 4.添加配置项 el: '#app',// el => 挂载 data: { msg: 'hello', age: 18 } })
-
插值表达式
用
{{}}
包裹变量名,将表达式插值,如上面{{msg}}和{{age-1}},浏览器会分别渲染值hello和 17 -
响应式特性
响应式:数据变化,视图自动更新,当我们修改数据后,vue会监听到数据修改,从而改变视图
data里的数据会添加到实例身上,以上面实例为例子,我们可以通过app访问属性msg和age
)
1.2.vue基础指令
-
一些基础指令:
<!-- 1.v-html => innerHtml --> <div v-html="msg2"></div> <!-- 2.v-show => 通过display来显示和隐藏 => 一般用于交互频繁 --> <div v-show="flag3">333</div> <!-- 3.v-if => 条件渲染 => 用于交互不频繁 --> <div v-if="flag3">444</div> <!-- 4.v-if、 v-else-if v-else => 条件渲染 --> <!-- 5.v-on 注册事件 每点击一下,count -1 --> v-on:click="count--" => @click="count--"
-
methods属性(用于存放事件方法)
<!-- 点击按钮,调用methods方法,弹出提示框 --> <button @click="methods">methods</button> <!-- js --> methods: { methods() { alert('methods') } }
-
7.v-for(基于数组循环,多次渲染整个元素,
v-for="(item,index) in arr
)<!-- 编号arr中的项,并且列举 --> <li v-for="(item, index) in list">{{index+1}}.{{item}}</li>
v-for中的key:给元素添加唯一标识,用于列表项的正确排序(key值必须具有唯一性,不推荐以index作为key值)
1.2.1.v-bind
-
可省略成
:
,用于实现熟悉的响应式<!-- imgUrl为配置项中data中的数据 --> <img v-bind:src="imgUrl"> <!-- 等价为 --> <img :src="imgUrl" alt="">
v-bind可以操作class
-
传对象
应用场景:一个类名,来回切换(tab栏)
<!-- size、pink、green都为类名 --> <div class="box" :class="{size:true,pink:false,green:true}">123</div>
-
-
传数组
应用场景:批量添加或者删除类
<div class="box" :class="['pink','size']">223</div>
-
style行内样式
应用场景:非常方便地控制某个样式属性的变化(进度条),数值拼接单位
<div class="box" :style="{'background-color':'green'}"></div>
1.2.2.v-model
v-modal 可以让数据和视图双向绑定,快速获取或者设置表单元素内容
<!-- input框值变化,data中对应的数据也会变化 -->
<input type="text" v-model="username"><br>
对于不同的表单元素, v-modal 的绑定也有所不同
表单元素 | 绑定 | 备注 |
---|---|---|
输入框 | value | text |
文本域 | value | textarea |
复选框 | checked | checkbox |
单选框 | checked | radio,name将单选框关联 |
下拉菜单 | selected元素中,option选项的value值 | selected、option |
1.2.3.常用事件
事件 | 触发 |
---|---|
@click | 单击触发 |
v-model | 常用于绑定input事件 |
@submit | 表单提交触发 |
@mouseover | 鼠标悬停触发 |
@mouseout | 鼠标移开触发 |
-
焦点事件
事件 触发 @focus
元素获得焦点 @blur
元素失去焦点 -
表单事件
事件 触发 @reset
点击重置按钮时 @submit
点击提交按钮 -
键盘事件
事件 触发 @keydown
按下任意按键。 @keypress
除 Shift、Fn、CapsLock 外的任意键被按住。 @keyup
按键弹起
1.2.4.指令修饰符
- 按键修饰符
- @keyup.enter:键盘回车监听
- v-model修饰符
- v-model.trim:去首尾空格
- v-model.number:转数字
- 事件修饰符
- 事件名.stop:阻止冒泡
- 事件名.prevent:阻止默认行为
- 其他
- once:事件只触发一次
1.3.计算属性
计算属性会对计算结果缓存,依赖项变了,会自动重新计算,并再次缓存,缓存可以被直接读取
(性能高)
1.methods属性
<p>礼物总数:{{ total() }} 个</p>
<p>礼物总数:{{ total() }} 个</p>
<p>礼物总数:{{ total() }} 个</p>
<!-- js中 -->
data: {
list: [
{ id: 1, name: '篮球', num: 1 },
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 },
]
},
methods: {
total() {
console.log("执行了一次。");
return this.list.reduce((sum, item) => sum + item.num, 0)
}
}
- 控制台会
打印三次
"执行了一次。"
- computed属性
<!-- 计算属性依旧是属性,不用加() -->
<p>礼物总数:{{ total }} 个</p>
<p>礼物总数:{{ total }} 个</p>
<p>礼物总数:{{ total }} 个</p>
<!-- js中 -->
computed: {
封装一段对于数据的处理,求得一个结果
total() {
console.log("执行了一次。");
return this.list.reduce((sum, item) => sum + item.num, 0)
}
}
- 控制台会
打印一次
"执行了一次。"
1.3.1.计算属性的完整写法
计算属性默认只能访问,不能修改,如果要修改,需要计算属性的完整写法
computed:{
fullName(){
return this.firstName + this.lastName
}
}
以上写法等价于
computed:{
fullName:{
get(){
return this.firstName + this.lastName
}
}
}
- 上面写法只能通过监听firstName和lastName,来动态改变fullName的值
- 现在假设fullName会变化,我们fullName变化时,有对firstName和lastName进行拆分的需求,就需要计算属性的完整写法
computed:{
fullName:{
// 监听firstName和lastName,动态改变fullName的值
get(){
return this.firstName + this.lastName
},
// 监听fullName,动态改变firstName和lastName的值
set(value){
this.firstName = value.slice(0,1))
this.lastName = value.slice(1)
}
}
}
从上面可以看出,set方法的形参value为fullName的值
当然除了改变firstName和lastName的值,还可以做出其他的一些操作,这里就不一一例举了
1.3.2.【案例】成绩
- 成品图
<!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="./styles/index.css" />
<title>Document</title>
</head>
<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="list.length>0">
<tr v-for="(item,index) in list" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.subject}}</td>
<td :class="{red:item.score<60}">{{item.score}}</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>总分:{{total}}</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="subject" />
</div>
</div>
<div class="form-item">
<div class="label">分数:</div>
<div class="input">
<input type="text" placeholder="请输入分数" v-model="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/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: [
{ id: 1, subject: '语文', score: 20 },
{ id: 2, subject: '数学', score: 99 },
{ id: 3, subject: '英语', score: 70 },
],
subject: '',
score: ''
},
methods: {
del(id) {
this.list = this.list.filter(item => item.id !== id)
},
add() {
if (!this.subject || !this.score) {
alert('没有输入科目或者分数!!!')
} else {
// 往数组前面加
this.list.unshift({
// 以时间戳作为id,来设置key
id: +new Date(),
subject: this.subject,
score: this.score
})
this.subject = ''
this.score = ''
}
}
},
computed: {
total() {
return this.list.reduce((sum, item) => sum + item.score, 0)
},
average() {
if (this.list.length == 0) {
return 0
} else {
return this.total / (this.list.length)
}
}
}
})
</script>
</body>
</html>
重要知识点
-
删除逻辑
del(id) { this.list = this.list.filter(item => item.id !== id) },
- 通过点击触发del方法,传入id
- 通过filter,从list过滤出和被点击项的id不同的id项,重新赋值给list(即从list删除点击项)
-
求和逻辑
total() { return this.list.reduce((sum, item) => sum + item.score, 0) },
- reduce累加器的运用
-
加入数组
- 往数组前面加:unshift()方法
- 往数组后面加:push()方法
1.4.watch
1.4.1.watch属性
作用:监视数据变化,执行 业务逻辑 或 异步操作
watch:{
// 该方法会在数据变化时调用执行
// newValue新值, oldValue老值(一般不用)
words(newValue, oldValue) {
console.log('变化了', newValue,, oldValue)
}
}
以上代码监听了data里的数据words,如果我们要监听data里obj对象属性words,则应该写为 'obj.words'
'obj.words'(newValue) {
console.log('变化了', newValue)
}
1.4.2.翻译业务实现
watch: {
'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
}
})
this.result = res.data.data
}, 300)
},
}
知识点
- 防抖处理
1.4.3.watch属性的完整写法
-
额外配置项
配置项 效果 deep:true
深度监视,对象的子元素变化也会触发 immediate:true
初始化立即执行一次
上面的翻译业务实现还可以升级为,通过改变翻译语言也会触发watch监听
- 对象obj有属性words和属性language
- 对象进行深度监视,对象的任何一个属性(words和language)发生变化,都会触发重新翻译
watch: {
obj: {
deep: true, // 深度监视
immediate: true, // 立即执行
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.result = res.data.data
}, 300)
}
},
}
1.4.4.【案例】水果购物车
- 成品图:
- js代码
const dedaultArr = [
{
id: 1,
icon: 'img/火龙果.png',
isChecked: true,
num: 1,
price: 6,
},
{
id: 2,
icon: 'img/荔枝.png',
isChecked: false,
num: 1,
price: 20,
},
{
id: 3,
icon: 'img/榴莲.png',
isChecked: false,
num: 1,
price: 40,
},
{
id: 4,
icon: 'img/鸭梨.png',
isChecked: true,
num: 1,
price: 3,
},
{
id: 5,
icon: 'img/樱桃.png',
isChecked: false,
num: 1,
price: 32,
},
]
const app = new Vue({
el: '#app',
data: {
// 水果列表
bannerSrc: 'img/fruit.jpg',
fruitList: JSON.parse(localStorage.getItem('list')) || dedaultArr
},
methods: {
del(id) {
return this.fruitList = this.fruitList.filter(item => item.id != id)
}
},
computed: {
// 计算选中个数
totalCount() {
return this.fruitList.reduce((sum, item) => {
if (item.isChecked) {
return sum + item.num
} else {
return sum
}
}, 0)
},
// 计算总价
totalPrice() {
return this.fruitList.reduce((sum, item) => {
if (item.isChecked) {
return sum + item.num * item.price
} else {
return sum
}
}, 0)
},
all: {
get() {
// return的值决定全选框是否勾选
// 必须所有框都选中,全选按钮才选中(every)
return this.fruitList.every(item => item.isChecked)
},
set(value) {
// 全选按钮的value影响其他框
this.fruitList.forEach(item => item.isChecked = value);
}
}
},
watch: {
fruitList: {
deep: true,
handler(newValue) {
localStorage.setItem('list', JSON.stringify(newValue))
}
}
}
})
- 部分html代码展示
<div class="tbody">
<div class="tr active" v-for="(item,index) in fruitList">
<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" @click="item.num--"> - </button>
<span class="my-input__inner">{{item.num}}</span>
<button class="increase" @click="item.num++"> + </button>
</div>
</div>
<div class="td">{{item.num*item.price}}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="all" />
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥
<span class="price">{{totalPrice}}</span>
</span>
<!-- 结算按钮 -->
<button class="pay">结算( {{totalCount}} )</button>
</div>
</div>
知识点:
- 全选框逻辑
- fruitList里添加属性isChecked来标记item项是否勾选
- 再通过
v-model="item.isChecked
”将isChecked和每个子checkbox绑定,即checkbox和勾选状态关联 - 如果子checkbox发生变化,调用get()
- 再通过every检查fruitList里的item.isChecked是否全为true,即检查是否全勾选
- 如果全勾选,返回true,通过
v-model="all"
反作用于全选的checkbox,使其勾选 - 如果全选的checkbox发生变化,调用set(),并通过形参value传入all的值
- 通过forEach,将所有子checkbox的isChecked设置为和all一样的值
1.5.生命周期
在不同的生命周期,会自动运行一些函数,被称为生命周期钩子,让开发者可以在特定阶段运行代码
-
生命周期四个阶段
1.创建阶段:创建响应式数据
2.挂载阶段:渲染模板
3.更新阶段:修改数据,更新视图
4.销毁阶段:销毁Vue实例
-
生命周期钩子
1.5.1.【应用】初始化渲染
在created生命周期,发送获取数据的请求
const app = new Vue({
el: '#app',
data: {
list: []
},
async created() {
// 1. 发送请求获取数据
const res = await axios.get('http://hmajax.itheima.net/api/news')
// 2.将获取的数据写入数据列表
this.list = res.data.data
}
})
</script>
1.5.2.【应用】获取焦点
在mounted生命周期,获取焦点(操作dom)
const app = new Vue({
el: '#app',
data: {
words: ''
},
mounted() {
document.querySelector('#inp').focus()
}
})