键盘事件:
涉及到要获取的数据
event.keyCode 获取按键编码
event.key 按键名
@keyup 按键抬起
@keydown 按键松开
@keyup.enter 是Vue中常用的按键别名
回车 enter
删除 delete (捕获“删除”和“退格”)
空格 space
退出 esc
换行 tab(tab键的神奇作用:将这个焦点从这个元素身上切走,由此不适合使用keyup,而使用keydown使用)
上下左右:up,down,left,right
Vue未提供别名的按键,可以使用按键原始的值去绑定,但注意,要转为kebab-case(短横线命名)
系统修饰键:ctrl,alt,shift,meta(就是win键)
配合keyup使用,按下修饰键的同时,再按下其他键,随后释放其他键,事件才会触发
例如ctrl+其他按键,释放其他按键
配合keydown使用,正常触发事件
也可以使用keyCode去指定具体的按键(不推荐,不同的键盘编码可能不统一)
Vue.config.keyCodes.自定义键名=键码,可以去定制按键别名
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<div id="root">
<h1>你好,{{name}}</h1>
<input type="text" placeholder="按下按键得到按键和按键编码" @keyup="showInfo">
<input type="text" placeholder="按下capslock得到输入" @keyup.caps-lock="showInfo2">
<input type="text" placeholder="这里测试ctrl等系统修饰键,得到除系统修饰键以外的其他按键" @keyup.ctrl="showInfo3">
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
Vue.config.keyCodes.huiche=13//定义了一个别名,虽然仍然不被推荐
new Vue({
el: "#root",
data: {
name: "柠"
},
methods:{
showInfo(event){
// if(event.keyCode!=13) return
console.log(event.key+" "+event.keyCode)
// 显示按键和按键编码
},
showInfo2(event){
console.log(event.target.value)
},
showInfo3(event){
console.log(event.key)
}
}
})
</script>
</body>
</html>事件总结:
@click.stop.prevent 这是先阻止冒泡再阻止跳转
注意:事件修饰符可以进行链式操作,这样子既可以阻止冒泡也可以阻止跳转
@click.prevent.stop 这是先阻止跳转再阻止冒泡
系统修饰键可以在后再点一个指定按键,这样指定了之后,只能通过"系统修饰键+指定按键"才能触发事件
这里就指定了ctrl+y才能触发
<input type="text" placeholder="这里测试ctrl等系统修饰键" @keyup.ctrl.y="showInfo3">计算属性:
所谓计算属性就是拿着已经写完的属性去加工,计算,生成一个全新的属性
就比如说,属性中有name1,name2,通过结合得到fullName,这里的fullName就是计算属性
计算属性由专门的配置项computed进行存放
computed:{
fullName:{
get(){
}
}
}get的作用:只要有人读取fullName,那么get就会被调用,且返回值作为fullName的值
get什么时候调用?
初次使用fullName时,
所依赖的数据发生变化时,在这里name1和name2就是被依赖的数据
并且计算属性具有缓存,下次取用时则会依据缓存进行:
如果get在所依赖的数据发生变化时没有进行调用,
那么会导致,当data数据发生改变时,但是get没有发生调用,此时因为缓存,得到的还是数据发生变化前的原始数据
张三-------->李三,但是没有调用get,所以得到的不是李三,而是张三
与methods对比,其中methods就没有缓存,fullName调用多少次就执行多少次
data和methods中,写什么就是什么,而在computed中写的fullName对象,在vm中也非对象,而是自动去调用fullName当中的get得到它的返回值,得到返回值之后直接返回给vm,于是拿到的是它的返回值,不要再去调用该对象的get方法了,fullName.get()是错误的,直接写fullName
set调用:
vm.fullName进行了修改,与之对应的set方法发生调用,但是set只是做出了相应输出,并没有将对应的值进行修改
computed:{
fullName:{
get(){
console.log('get被调用了')
return this.name1+'-'+this.name2
},
//set什么时候调用?当fullName被修改时
set(value){
console.log('set被调用了')
console.log(value)
}
}
}修改一番:
computed:{
fullName:{
get(){
console.log('get被调用了')
return this.name1+'-'+this.name2
},
//set什么时候调用?当fullName被修改时
set(value){
console.log('set被调用了')
console.log(value)
const arr =value.split('-')
this.name1=arr[0]
this.name2=arr[1]
console.log('已做出修改')
}
}
}整段流程:
vm-fullName修改--->set方法执行--->引起了name1和name2修改,然后导致data中的数据发生更新-->最后导致页面中有用到data的地方就立刻更新,全名也发生变化
计算属性总结:
定义:要用的属性不存在,而是通过已有属性计算得来
原理:底层借助了Object.defineproperty方法提供的getter和setter
get函数什么时候执行
初次读取时会执行一次
当以来的数据发生改变时会被再次调用
优势:methods实现相比,内部会有缓存机制进行复用,效率更高
备注:
计算属性最终会出现在vm上,直接读取使用即可
如果计算属性要被修改,则必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
以下为综合源码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<div id="root">
<h1>你好,{{name}}</h1>
姓:<input type="text" placeholder="请输入姓" v-model="name1"><br />
名:<input type="text" placeholder="请输入名" v-model="name2"><br />
测试:<input type="text" v-model="name3"><br />
<span>全名:{{fullName}}</span>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el: "#root",
data: {
name: "柠",
name1: "张",
name2: "三",
name3:'测试'
},
computed:{
fullName:{
get(){
console.log('get被调用了')
return this.name1+'-'+this.name2
},
//set什么时候调用?当fullName被修改时
set(value){
console.log('set被调用了')
console.log(value)
const arr =value.split('-')
this.name1=arr[0]
this.name2=arr[1]
console.log('已做出修改')
}
}
}
})
</script>
</body>
</html>计算属性:简写
简写的前提:set一定被省略
fullName不再写成一个对象,而是一个函数,函数就当getter使用
fullName:function(){
console.log('get被调用了')
return this.name1+'-'+this.name2
}监视属性
关键字:watch
需要传入的是一个配置对象,要监视谁,就往里面放,然后将其设置为一个配置对象
handler的调用时机:当外层的配置对象发生改变时就产生一次调用
watch:{
isHot:{
handler(){
}
}
}handler函数可以传入两个参数,一个是newValue,一个是oldValue,newValue表示的是得到的新值,oldValue表示更改前的旧值
*补充知识点:immediate,初始化时就让handler执行一次
除开在创建时使用watch,还可以在创建实例之后,使用$watch()进行创建,需要传入两个参数,一个是要监视的属性,一个是配置对象,配置对象内写的内容就是把watch里面那个配置对象的内容拿出来即可
vm.$watch('isHot',{
immediate:true,
handler(newValue,oldValue){
console.log('...')
}
})监视属性最终源码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<div id="root">
<h1>你好,{{name}}</h1>
<h1>今天天气很{{info}}</h1>
<button @click="changeWeather">切换天气</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el: "#root",
data: {
name: "柠",
isHot:true
},
methods:{
changeWeather(event){
console.log("天气变化了")
this.isHot = !this.isHot
}
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽'
}
},
// watch:{
// info:{
// handler(){
// console.log('已监视到目标对象发生变化')
// }
// }
// }
})
vm.$watch('isHot',{
handler(){
console.log('已监视到目标对象发生变化')
}
})
</script>
</body>
</html>监视属性watch总结:
当被监视的属性变化时,回调函数自动调用,进行相关操作
监视的属性必须存在,才能进行监视(因为不会报错,排错极为困难)
监视的两种写法:
new Vue时传入watch配置
通过vm.$watch监视
监视属性扩展点:深度监视
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<div id="root">
<h1>你好,{{name}}</h1>
<h1>今天天气很{{info}}</h1>
<button @click="changeWeather">切换天气</button>
<hr/>
<h3>a的值是{{numbers.a}}</h3>
<button @click="myadd">点我让a+1</button>
<hr />
<h3>b的值是{{numbers.b}}</h3>
<button @click="myadd">点我让b+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el: "#root",
data: {
name: "柠",
isHot: true,
numbers:{
a:1,
b:2
}
},
methods: {
changeWeather(event) {
console.log("天气变化了")
this.isHot = !this.isHot
},
myadd(){
this.numbers.a++
},
},
computed: {
info() {
return this.isHot ? '炎热' : '凉爽'
}
},
watch:{
//这种加引号的是正规写法,不过因为简化而可以选择丢去引号
'isHot':{
handler(){
console.log('已监视到目标对象发生变化')
}
},
//这种情况下删除外面的引号会导致报错,此时就不能删除
//监视多级结构中某个属性的变化
'numbers.a':{
handler(){
console.log('a已发生改变')
}
},
'numbers':{
//该配置项用于监视多级结构中所有属性的变化
deep:true,
handler(){
console.log('number发生改变')
}
}
//Vue默认可以检测到多层级数据的改变的
//但是为程序员提供的watch是不可检测的,需要添加上deep
}
})
</script>
</body>
</html>关键字:deep
总结:
Vue中的watch默认不监视对象内部值的改变(一层)
配置deep:true可以检测对象内部值改变(多层)
备注:
Vue自身可以检测对象内部值的改变,但Vue提供的watch默认不可以
使用watch时,根据数据的具体结构,决定是否采用深度监视
监视属性和计算属性的对比:
监视属性的简写:前提是只有一个handler,那么就直接写成一个函数,不要写成配置对象的形式
<!--简化版-->
isHot(newValue,oldValue){}
<!--完整版-->
isHot{
handler(newValue,oldValue){}
}watch,需要自行准备fullName
在watch里面可以很轻松的开启一个异步任务,在watch中,并不依赖返回值
而计算属性不行,因为计算属性完全依赖的就是返回值,而我们暂时办不到让fullName等一等才得到返回值
计算属性里面不能开启异步任务来维护数据
定时器函数并不是由Vue控制,由于这里使用的是箭头函数,于是就没有自己的this,没有自己的this就向外寻找,可以发现是找到了firstName,而且firstName还是普通函数,firstName的this是vm
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<div id="root">
<h1>你好,{{name}}</h1>
姓:<input type="text" placeholder="请输入姓" v-model="name1"><br />
名:<input type="text" placeholder="请输入名" v-model="name2"><br />
<span>全名:{{fullName}}</span>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el: "#root",
data: {
name: "柠",
name1: "张",
name2: "三",
// fullName: "张-三"
},
// 使用监视属性
watch:{
'name1':{
handler(newValue,oldValue){
setTimeout(()=>{
this.fullName = newValue + '-' + this.name2
},1000)
//watch里面可以放异步任务
}
},
'name2':{
handler(newValue,oldValue){
this.fullName=this.name1+'-'+newValue
}
}
}
// 计算属性不能执行异步任务
// computed:{
// fullName(){
// // setTimeout(() => {
// // fullname = this.name1 + '-' + this.name2
// // }, 1000)
// return this.name1 + '-' + this.name2
// }
// }
})
</script>
</body>
</html>计算属性不能执行异步任务,计算属性主要看的是返回值,但是异步函数把返回值吞了,连渲染在页面上都无法进行
总结:
computed和watch之间的区别:
1,computed能完成的,watch都能完成
2,watch能完成的,computed不一定能完成,例如watch可以进行异步操作
重要原则:
所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或者组件实例对象(只要用了和vm有关的东西,统统写成普通函数,这点是没有错的,防止this找到外面去)
所有不被Vue所管理的函数,如定时器的回调函数,最好写成箭头函数,这样this的指向才是vm或者组件实例对象