Vue2-基础2

Vue2基础2

事件处理

v-on

这里我们要接触一个全新的配置项methods和一个新的指令语法v-on,我们以需求为导向来学习这一节

需求一:点击按钮,控制台显示欢迎信息

HTML

1
2
3
4
5
6
<div id="app">
{{msg}}
<input type="text" v-model="name">
<!--按钮绑定点击事件,回调函数是welcome-->
<button v-on:click="welcome">欢迎</button>
</div>

JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new Vue({
el: '#app',
data(){
return {
name: 'kerwin',
msg: '坚持很难,但很酷'
}
},
methods:{
welcome(){
console.log(`Hello,${this.name}`)
}
}
})

这里有几个知识点

1、模板字符串

1
被``包裹的字符串被叫做模板字符串,它的特点是,在其中可以使用${}语法读取变量

2、methods中配置的函数,this指的应该是vm对象,这就对应着前面我说的一句话

所有被Vue管理的函数(不能是箭头函数),其内部的this都是vm对象,所以可以使用this.xxx直接获取属性的值

3、观察vm对象,发现在methods中配置的函数,都出现在了vm身上

4、简写形式,常用

1
<button @click="welcome">欢迎</button>

需求二:点击按钮,提示当前鼠标位置

这就需要使用事件参数,其实在welcome方法的参数列表中,Vue默认为咱们传递了一个参数,只不过刚刚我们没有使用而已,我们接收打印一下看看

1
2
3
welcome($event){
console.log($event)
}

既然有了这个对象($event),那我获取当前鼠标位置,只需要读取该对象的pageX属性和pageY属性即可

这里也可以不叫$event,叫它a啊b啊都可以,但是习惯起见,我就以$event来接收它了

需求3:我想将name传参进去,而不是使用this去读取

HTML

1
<button @click="welcome($event,name)">欢迎</button>

JavaScript

1
2
3
welcome($event,name){
console.log(`Hello,${name}`)
}

这里有个注意点,如果我在这里是这样写的<button v-on:click="welcome(name)">欢迎</button>

那么welcome函数只有一个入参,那就是name,点击事件对象就没了

事件修饰符

需求1:点击一个a标签,然后提示弹窗,但是不跳转页面

HTML

1
2
3
<div id="app">
<a href="https://baidu.com" @click.prevent="showInfo">点我跳转百度</a>
</div>

JavaScript

1
2
3
4
5
6
7
8
let vm = new Vue({
el: '#app',
methods:{
showInfo(){
alert('Hello')
}
}
});

这里面的prevent就是事件修饰符。

Vue为我们提供了6种事件修饰符,用的都不是很多,大家过个眼就行

事件修饰符 作用
prevent 阻止默认事件(常用)
stop 阻止事件冒泡(常用)
once 事件只触发一次(常用)
capture 使用事件的捕获模式
self 只有event.target是当前操作的元素时才触发事件
passive 事件的默认行为立即执行,无需等待事件回调执行完毕

这里讲一下passive的作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<style>
.list{
width: 200px;
height: 200px;
background-color: peru;
overflow: auto;
}
li{
height: 100px;
}
</style>
<div id="app">
<ul @wheel.passive="bigWork" class="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<!--
wheel事件
当鼠标滚轮滚动,则触发该事件,并且当滚动条到达边界后,滚动也会触发该事件
scroll事件
当滚动条滚动则触发该事件,滚动条到了边界后,再滚动就不会触发该事件了
-->
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#app',
methods:{
bigWork(){
for (let i = 0; i < 100000; i++) {
console.log('===')
}
console.log('活终于干完了')
}
}
})
</script>

现在滚动鼠标滚轮的时候,滚动条就会卡住不动,当我加上passive后,即变正常。这是为什么呢?

当触发滚轮事件后,先执行事件回调,然后再执行默认事件,如果任务量很大,则默认事件就会堆积,导致页面卡顿

但是当我换成scroll的时候,就算我不加passive修饰符,滚动条依旧正常。

passive在pc端用的很少,在移动端用的较多一点

键盘事件

键盘事件最常用的就两个事件keydownkeyup

前者是当按键按下后触发,后者是当按键回弹起来后触发

案例1:输入文字,当按下回车控制台打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
<input type="text" v-model="msg" v-on:keyup.enter="showInfo">
<!--
简写模式
<input type="text" v-model="msg" @keyup.enter="showInfo">
-->
</div>

<script type="text/javascript">
let vm = new Vue({
el: '#app',
data(){
return {
msg: ''
}
},
methods:{
showInfo(){
console.log(`输入框中的句子是${this.msg}`)
}
}
});
</script>

总结:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1.Vue中常用的按键别名:
回车 => enter
删除 => delete、backspace (包括“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right

2.系统修饰键(用法特殊):ctrl、alt、shift、meta(win)
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。

3.当按下Ctrl+y的时候,再触发事件
<input type="text" v-model="msg" @keyup.ctrl.y="showInfo">

计算属性与监视

案例:根据输入的姓和名展示姓名

插值语法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
<span>全名:{{firstName}}-{{secondName}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'',
secondName: ''
}
}
})
</script>

methods实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
<!--这里的方法必须加上小括号,不然读取的就是方法的源码-->
<span>全名:{{fullName()}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'',
secondName: ''
}
},
methods:{
fullName(){
return `${this.firstName}-${this.secondName}`
}
}
})
</script>

这里需要注意一个点:当data中的数据发生了改变,就会重新解析模板,所以所有在插值语法中的函数都会再执行一遍

计算属性实现

全写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
<span>全名:{{fullName}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'',
secondName: ''
}
},
computed:{
fullName: {
get(){
return `${this.firstName}-${this.secondName}`
},
set(value){
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
})

总结:

1
2
3
4
5
6
1、get何时被调用?
(1)页面加载好后,对此变量初次读取
(2)get中使用到的任何变量发生变化的时候
2、set何时被调用
(1)当fullName被修改时
3、计算属性会被放到vm上
简写

在只读不写的情况下才可以使用简写模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
<span>全名:{{fullName}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'',
secondName: ''
}
},
computed:{
fullName(){
return `${this.firstName}-${this.secondName}`
}
}
})
</script>

计算属性是一个名词,不是动词

这一点搞明白之后,就可以理解计算属性的作用其实就是拿着我现有的东西加工后再展示在页面上

既然插值语法和methods都可以实现该功能,为什么还要学一个计算属性呢?这不是经典白学吗?

NO!大NO特NO

计算属性的优势有两点

1、职责分明

2、与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。

证明:计算属性有缓存

1
2
3
4
5
6
computed:{
fullName(){
console.log('我被读取了')
return `${this.firstName}-${this.secondName}`
}
}

页面上多次使用fullName

修改姓

由此可以证明计算属性具有缓存

缓存什么时候刷新呢?当get中使用到的任何变量发生变化的时候

监视实现

监视是一个全新的配置项,作用是监视一个属性的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
<span>全名:{{fullName}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'李',
secondName: '四',
fullName: ''
}
},
watch:{
firstName:{
handler(newValue,oldValue){
this.fullName = newValue + '-' + this.secondName
}
},
secondName: {
handler(newValue,oldValue){
this.fullName = this.firstName + '-' + newValue
}
}
}
})
</script>

这样写就有一个问题,当firstNamesecondName有初始值的情况下,页面加载后,fullName是没有值的

这时候就需要使用一个配置项immediate,使得页面加载后立即执行一次监视的回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
watch:{
firstName:{
immediate: true,
handler(newValue,oldValue){
this.fullName = newValue + '-' + this.secondName
}
},
secondName: {
immediate: true,
handler(newValue,oldValue){
this.fullName = this.firstName + '-' + newValue
}
}
}

这时候小马觉得所有的数据直接写在data中不太好,他想使用一个对象来放这些数据,所以他把data改成了这样,然后他想监视person的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
data(){
return {
person: {
firstName:'李',
secondName: '四',
fullName: '',
school: {
name: '南京某大学',
age: 18
}
}
}
},

于是乎页面就成了这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<div id="app">
姓:<input type="text" v-model="person.firstName">
</br>
名:<input type="text" v-model="person.secondName">
</br>
学校名:<input type="text" v-model="person.school.name">
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
person: {
firstName:'李',
secondName: '四',
fullName: '',
school: {
name: '南京某大学',
age: 18
}
}
}
},
watch:{
person:{
handler(newValue,oldValue){
console.log('我被修改了');
console.log(newValue);
}
}
}
})
</script>

小马开心的修改了学校名,发现控制台啥也没有,又修改了姓和名,发现控制台都没有输出,

其实这不是小马的错,这时候就需要另一个配置项了deep,开启对对象的深度监视

1
2
3
4
5
6
7
8
9
watch:{
person:{
deep: true,
handler(newValue,oldValue){
console.log('我被修改了');
console.log(newValue);
}
}
}

小马发现这样写完之后,就又可以监视这个person对象了

简写模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
<span>全名:{{fullName}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'',
secondName: '',
fullName: ''
}
},
watch: {
firstName(newValue,oldValue){
this.fullName = newValue + '-' + this.secondName
},
secondName(newValue,oldValue){
this.fullName = this.firstName + '-' + newValue
}
}
})
</script>
另一种写法
1
2
3
4
5
6
7
8
9
10
11
12
 vm.$watch('firstName',{
immediate:true,
deep:true,
handler(newValue,oldValue){
console.log('firstName被修改了',newValue,oldValue)
}
})

//简写形式,所有被vm所管理的函数,都不要写成箭头函数
vm.$watch('secondName',function (newValue,oldValue){
console.log('secondName被修改了',newValue,oldValue,this)
})

区别

计算属性和监视的区别

就按照这个案例看的话,好像计算属性比监视好多了,但是如果我再加一个需求:姓名输入防抖动

防抖动:就是一段时间内不展示结果,等到用户输入完毕后,再将结果放到页面中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
全名:<span>{{fullName}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'李',
secondName: '四',
fullName: '',
timer: '',
}
},
watch:{
firstName:{
immediate: true,
handler(newValue,oldValue){
clearTimeout(this.timer);
this.timer = setTimeout(()=>{
this.fullName = newValue + '-' + this.secondName;
},2000);
}
},
secondName:{
immediate: true,
handler(newValue,oldValue){
clearTimeout(this.timer);
this.timer = setTimeout(()=>{
this.fullName = this.firstName + '-' + newValue;
},2000);
}
}
}
})
</script>

这里大家可能会有个疑惑

这里如果不写成箭头函数的话,函数里面的this就是window

但是写成箭头函数的话,在2s过后,vs引擎执行此回调的时候,就会在函数中找this,没有找到

然后向外找,就找到了handler函数,这里面的this就是vm,那么就可以找到data中的属性了


这时候就有人说了,那我也可以用计算属性啊

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div id="app">
姓:<input type="text" v-model="firstName">
</br>
名:<input type="text" v-model="secondName">
</br>
全名:<span>{{fullName}}</span>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data(){
return {
firstName:'李',
secondName: '四'
}
},
computed: {
fullName(){
setTimeout(()=>{
return this.firstName + '-' + this.secondName;
},2000);
}
}
})
</script>

当你写下这个代码的时候,你得反思一下基本功了

这个函数的返回值会返回到哪里去?

所以,当需要使用异步计算的时候,就需要使用属性监视

小总结

1
2
3
4
5
6
7
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以对数据进行异步的操作。
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数的形式,这样this的指向才是vm或组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数)
最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。

绑定style与class

这里就不写案例了

1
2
3
4
5
6
7
8
9
1. class样式
写法:class="xxx" xxx可以是字符串、对象、数组。
:class="" 字符串写法适用于:类名不确定,要动态获取。
:class="{classA:xxx,classB:xxx}" 对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用,xxx是布尔值
:class="['classA']"数组写法适用于:要绑定多个样式,个数不确定,名字也不确定
2. style样式
:style="{fontSize: xxx}"其中xxx是动态值。
:style="[a,b]"其中a、b是样式对象。
:style="obj"其中obj是样式对象或者数组
给作者买杯咖啡吧~~~