目录
处理用户交互实际上就是对用户操作事件的监听和处理。在vue中,使用v-on指令来进行事件的监听和处理,我们可以使用@来代替v-on指令。
网页的事件监听主要分为两类:键盘按键事件和鼠标操作事件。
事件的监听与处理
v-on指令用来为DOM事件绑定监听,其可以设置为一个简单的js语句,也可以设置为一个js函数。
事件监听实例
关于DOM事件的绑定,如下
<!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">
<title>Document</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="Application">
<div>点击次数:{{count}}</div>
<button @click="click">
点击
</button>
</div>
<script>
const App={
data() {
return {
count:0
}
},
methods: {
click(){
this.count++
}
},
}
Vue.createApp(App).mount("#Application")
</script>
</body>
</html>
@click是一种基础的用户交互处理方法,我们也可以直接将要执行的代码逻辑放在@click赋值的地方
<button @click="this.count++">点击</button>
这一行代码和上面的代码的运行效果是一样的,只是通常事件的处理方法都不是一行js代码能够解决的,所以更多的时候我们都会采用绑定方法函数的方式来处理事件。在上面的代码里,我们定义的click函数是没有参数的,实际上我们触发这个函数的时候,系统会将当前的event对象传递到函数里去,如果需要用到event对象,定义的函数是这样的
click(event){
console.log(event);
this.count++
}
event对象会存储当前事件的很多信息,例如事件类型,鼠标位置 ,键盘按键情况等
如果DOM元素绑定执行事件的函数需要传自定义的参数,我们可以通过函数的参数来进行控制,
click(step){
// console.log(event);
this.count+=step
}
<button @click="click(2)">
点击
</button>
就可以实现+2+2的操作了。如果在自定义传参的基础上,我们需要使用系统的event对象,我们可以使用$event来传递此参数,代码:
<button @click="click(2,$event)">
点击
</button>
click(step,event){
console.log(event);
this.count+=step
}
多事件处理
多事件处理是指对于同一个用户交互事件,需要调用多个方法来进行处理。一种比较简单的写法是编写一个聚合函数作为事件的处理函数,但是在vue中,绑定事件的时候支持逗号对多个函数进行调用绑定,上节的click函数实现了计数和打印,我们可以将这两个功能拆开来
methods: {
click(step){
this.count+=step
},
log(event){
console.log(event);
}
},
<button @click="click(2),log($event)">
点击
</button>
事件修饰符
DOM事件的传递原理是,当我们在页面上触发了一个单击事件的时候,事件会首先从父组件开始依次传递到子组件,这一过程叫做事件捕获,当事件传递到最上层的子组件的时候,还会逆向再进行一轮传递,从子组件依次向下传递,这一过程叫做事件冒泡。我们在vue中的@click方法绑定事件的时候,默认监听的是DOM事件的冒泡阶段,也就是从子组件传递到父组件的过程
捕获事件和冒泡事件的选择是根据业务的具体需求的
<div @click="click1" style="border:solid red;">
外层
<div @click="click2" style="border:solid red;">
中层
<div @click="click3" style="border:solid red;">
点击
</div>
</div>
</div>
click1(){
console.log("外层");
},
click2(){
console.log("中层");
},
click3(){
console.log("内层");
}
运行代码,输出如下
如果需要监听捕获阶段的时间,我们就需要使用事件修饰符,事件修饰符capture可以将监听事件的实际设置为捕获阶段
<div @click.capture="click1" style="border:solid red;">
外层
<div @click.capture="click2" style="border:solid red;">
中层
<div @click.capture="click3" style="border:solid red;">
点击
</div>
</div>
</div>
打印出来的
捕获事件触发的顺序和冒泡事件是相反的。
理解事件的传递对处理页面用户的交互是非常重要的,但是也有许多场景是不需要事件进行传递的,例如上面的例子,用户点击内层组件,我们只希望触发内存组件绑定的方法,点击外层组件,触发外层组件绑定的方法,这个时候就需要有用到stop
<button @click="this.count++">点击</button>
<div @click.stop="click1" style="border:solid red;">
外层
<div @click.stop="click2" style="border:solid red;">
中层
<div @click.stop="click3" style="border:solid red;">
点击
</div>
</div>
</div>
在单击时候,只有单击当前组件,才会调用当前组件所绑定的方法。
事件修饰符:
stop阻止事件传递
capture监听捕获场景的时间
once只触发一次事件
self当事件对象的target属性是当前组件才触发事件
prevent禁止默认的事件
passive不禁止默认事件
这些事件修饰符可以串联来使用。
Vue中的事件类型
事件本身也是有类型的分别的,例如@click绑定的就是元素的单击事件,如果需要通过用户鼠标操作行为来实现更加复杂的交互逻辑,则需要监听更加复杂的鼠标事件。v-on指令进行普通的HTML元素的时间绑定时,制裁所有的原生DOM事件,对自定义的vue组件进行事件绑定的时候,也可以支持自定义的事件
常用事件类型
常用的交互事件有
事件 说明
click 单击
dblclick 双击
click 单击
click 单击
click 单击
focus 获取焦点
blur 失去焦点
change 元素内容改变
select 元素内容被选中
mousedown 鼠标按键被按下
mouseup 鼠标按键抬起
mousemove 鼠标在组件内移动
mouseout 鼠标移出组件
mouseover 鼠标移入组件
Keydown 键盘按键被按下
Keyup 键盘按键抬起
对于事件类型,编写示例代码来理解其触发的实际:
<!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">
<title>Document</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="Application">
<div @click="click">单击事件</div>
<div @dblclick="dblclick">双击事件</div>
<input type="text" @focus="focus" @blur="blur" @change="change" @select="select"></div>
<div @mousedown="mousedown">鼠标按下</div>
<div @mouseup="mouseup">鼠标抬起</div>
<div @mousemove="mousemove">鼠标移动</div>
<div @mouseout="mouseout" @mouseover="mouseover">鼠标移入移出</div>
<input type="text" @keydown="keydown" @keyup="keyup">
</div>
<script>
const App={
methods: {
click(){
console.log("单击事件");
},
dblclick(){
console.log("双击事件");
},
focus(){
console.log("获取焦点");
},
blur(){
console.log("失去焦点");
},
change(){
console.log("内容改变");
},
select(){
console.log("文本选中");
},
mousedown(){
console.log("鼠标按键按下");
},
mouseup(){
console.log("鼠标按键抬起");
},
mousemove(){
console.log("鼠标移动");
},
mouseout(){
console.log("鼠标移出");
},
mouseover(){
console.log("鼠标移入");
},
keydown(){
console.log("键盘按键按下");
},
keyup(){
console.log("键盘按键抬起");
}
},
}
Vue.createApp(App).mount("#Application")
</script>
</body>
</html>
按键修饰符
当需要对键盘按键进行监听的时候,我们通常使用keyup参数,如果仅仅要对某个按键进行监听,可以通过event对象来判断,如果需要监听用户敲击回车键,可以这样实现
keyup(event){
console.log("键盘按键抬起");
if(event.key=='Enter'){
console.log(1);
}
},
在vue中,还有一种更加简单的方法可以实现对某个具体按键的监听,即使用按键修饰符,在绑定监听方法的时候,我们可以设置要监听的具体按键
<input type="text" @keydown="keydown" @keyup.enter="keyup">
修饰符的命名规则和event对象中属性的key值的命名规则略有不同,event对象采用的是大写字母驼峰法,如Enter,PageDown此类,在使用按键修饰符的时候需要将其转化为中划线驼峰法,如enter、page-down
vue还提供了一些特殊的系统按键修饰符,这些修饰符主要是配合其他键盘按键或者鼠标按键来使用的,主要有:
ctrl
alt
shift
meta
这些系统的修饰符的使用意义是当用户按下这些键的时候,对应的键盘或鼠标事件才能触发,在处理某些组件键指令的时候会经常用到,例如
<div @mousedown.ctrl="mousedown">鼠标按下</div>
上面代码就要去在按下ctrl的同时要按下鼠标按键才会触发绑定的事件函数
<input type="text" @keydown="keydown" @keyup.alt.enter="keyup">
上面代码是需要用户按下alt的同时在按下回车键
有一个需要注意的地方,系统修饰符满足条件就会触发,以鼠标按下事件为例,只要满足用户按下了ctrl的时候按下了鼠标按键,就会触发事件,即使用户同时按下了其他按键也不会手袋影响,如果想要精准的进行按键修饰,可以使用exact修饰符,只有精准的满足按键的条件才会触发事件
vue还有三个常用的鼠标按键修饰符。在进行网页应用的开发,通常左键用来选择,右键用来配置。left right middle
例子1.随鼠标移动的小球
此应用的逻辑:在页面上绘制出一片区域,在区域内绘制一个圆形球体,我们需要实现当鼠标在区域内移动的时候,球体也可以平滑的随鼠标移动
要实现页面元素随鼠标移动,我们只需要监听鼠标移动事件就可以了,做好元素坐标的更新。
<!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">
<title>Document</title>
<script src="https://unpkg.com/vue@next"></script>
<style>
body{
margin: 0;
padding: 0;
}
.container{
margin: 0;
padding: 0;
position: absolute;
width: 440px;
height: 440px;
background-color: blanchedalmond;
display: inline;
}
.ball{
position: absolute;
width: 60px;
height: 60px;
left: 100px;
top: 100px;
background-color: red;
border-radius: 30px;
z-index:100
}
</style>
</head>
<body>
<div id="Application">
<div class="container" @mousemove.stop="move">
<div class="ball" :style="{left:offsetX+'px',top:offsetY+'px'}"></div>
</div>
</div>
<script>
</script>
</body>
</html>
下面需要关注实现js逻辑,要控制小球的移动,需要实时修改小球的布局位置,因此需要在vue组件中定义两个属性:offsetX和offsetY,分别用来控制圆球的横纵坐标,之后根据鼠标所在的位置的坐标来不断更新坐标属性即可
<script>
const App={
data() {
return {
offsetX:0,
offsetY:0
}
},
methods: {
move(event){
if(event.clientX+30>440){
this.offsetX=440-60
}else if(event.clientX-30<0){
this.offsetX=0
}else{
this.offsetX=event.clientX-30
}
if(event.clientY+30>440){
this.offsetY=440-60
}else if(event.clientY-30<0){
this.offsetY=0
}else{
this.offsetY=event.clientY-30
}
}
},
}
Vue.createApp(App).mount("#Application")
</script>
运行代码,实现了定位
例子2:弹球游戏
弹球游戏规则:开始游戏的时候,页面中的弹球以随机的速度和方向运行,当弹球飞行到左侧边缘、右侧边缘或上册边缘的时候会进行回弹,在页面的下侧有一块挡板,我们可以通过键盘上的左右按键来控制挡板的移动,当球体落向页面底部的时候,如果用户用挡板接住,则弹球会继续反弹,如果没有接住,游戏就失败。
实现这个游戏的核心逻辑在于弹球的移动和回弹的算法。
<div id="Application">
<!-- 游戏区域 -->
<div class="container">
<!-- 底部挡板 -->
<div class="board" :style="{left:ballX+'px'}"></div>
<!-- 弹球 -->
<div class="ball" :style="{left:ballX+'px',top:ballY+'px'}"></div>
<!-- 游戏提示结束 -->
<h1 v-if="fall" style="text-align: center;">游戏失败</h1>
</div>
</div>
HTML代码如上,底部裆部可以通过键盘来控制,游戏失败的提示文案默认应该是隐藏的,当游戏失败后控制器展示
<style>
body{
margin: 0;
padding: 0;
}
.container{
position: relative;
margin: 0 auto;
width: 440px;
height: 440px;
background-color: blanchedalmond;
}
.ball{
position: absolute;
width: 30px;
height: 30px;
left: 0px;
background-color: orange;
border-radius: 30px;
}
.board{
position: absolute;
left: 0;
bottom: 0;
height: 10px;
width: 80px;
border-radius: 5px;
background-color: red;
}
</style>
运用到了子爵负向的原理,可以将子组件相对父组件进行绝对布局。
完整的逻辑代码
<script>
const App={
data() {
return {
boardX:0,
ballX:0,
ballY:0,
rateX:0.1,
rateY:0.1,
fail:false
}
},
mounted() {
this.enterKeyup();
this.rateX=(Math.random()+0.1)
this.rateY=(Math.random()+0.1)
this.timer=setInterval(()=>{
if(this.ballX+this.rateX>=440-30){
this.rateX*=-1
}
if(this.ballX+this.rateX<=0){
this.rateX *=-1
}
if(this.ballY+this.rateY<=0){
this.rateY *=-1
}
this.ballX+=this.rateX
this.ballY+=this.rateY
if(this.ballY>=440-30-10){
if(this.boardX<=this.ballX+30 && this.boardX+80>=this.ballX){
this.rateY *=-1
}else{
clearInterval(this.timer)
this.fail=true
}
}
},2)
},
methods: {
keydown(event){
if(event.key=="ArrowLeft"){
if(this.boardX>10){
this.boardX-=20
}
}else if(event.key=="ArrowRight"){
if(this.boardX<440 - 80){
this.boardX+=20
}
}
},
enterKeyup(){
document.addEventListener("keydown",this.keydown)
}
},
}
Vue.createApp(App).mount("#Application")
</script>