hello,我是小索奇,精心制作的Vue系列教程持续更新哈,想要学习&巩固&避坑就一起学习吧~
事件处理
事件的基本用法
重点内容
- 使用
v-on:xxx
缩写@xxx
绑定事件,其中xxx
是事件名(回顾:v-bind缩写为冒号:) - 事件的回调需要配置在
methods
对象中,最终会在VM
上 methods
中配置的函数,不要用箭头函数,否则 this 就不是VM了,重点强调!methods
中配置的函数,都是被 Vue所管理的函数,this 的指向是VM(ViewModel-vue实例对象)或组件实例对象@click="demo"
和@click="demo($event)"
效果一致,前者是默认会传event,省略了而已,后者更加灵活,可以传更多参数- 当我们需要给函数传参时
@click='showInfo(666)'
怎么获取event
? - 关于
this
的详细理解
详细解析
先看这一组代码,哪里有问题
<body> <div id="root"> <h2>这是name:{{name}}</h2> <button v-on:click = "showInfo">点击提示信息</button> </div> <script type="text/JS"> Vue.config.productionTip = false function showInfo(){ alert('你好哈') } new Vue({ el:'#root', data:{ name:'即兴小索奇' } }) </script> </body>
不知道methods的伙伴可能看不出什么问题,但实际的问题是点击按钮没有任何反应
image-20230812205755903
这里定义了一个普通的JS 函数 showInfo()
,但没有将它添加到 Vue 实例的 methods
选项中,因此在模板中使用 v-on:click="showInfo"
时无法正确调用该函数我们需要将 showInfo
函数添加到 Vue 实例的 methods
选项中
因为 Vue 实例的 methods
选项专门用于存放可以在模板中调用的方法
当在methods
中加上showInfo
方法就会成功显示
image-20230812211754411
事件对象
当你在模板中使用事件处理函数时,Vue 会自动将事件对象作为第一个参数传递给该函数因此,你可以在事件处理函数中定义一个参数来接收这个事件对象常见的做法是将这个参数命名为 event
,以表示它是一个事件对象
例如,在你的代码中,如果你使用 v-on:click="showInfo"
来绑定事件,那么在 showInfo
函数中,你可以定义一个名为 event
的参数,这样就可以访问到事件对象,从而获取事件的信息(如点击的坐标、触发的元素等)
举个栗子
<body> <div id="root"> <button v-on:click="showInfo">点击提示信息</button> </div> <script type="text/JS"> new Vue({ el: '#root', data: { name: '即兴小索奇' }, methods: { showInfo(event) { console.log(event) console.log(event.target) alert('你好哈,点击坐标:' + event.clientX + ',' + event.clientY + ' ' + event.target.innerText); } } }); </script> </body>
image-20230812213221250
在这里这个事件就是button
event.target
就是这个事件目标(button)
image-20230812213746135
用console.log(event)
输出可以看到所有属性及方法
image-20230812213517353
当我们需要给函数传参时@click='showInfo(666)'
怎么获取event
?
当我们需要传参时,会发现event
不能输出了,即使设置多个参数也是undefined,这时候我们只要在参数后面加上$(event)
关键词即可
@click='showInfo(666,$event)
方法中对应两个参数就可以输出event了,这是官方设置的,记住就行- 对于event的顺序没有要求,可以把其它参数放在
event
后面也行
this函数的区分
如果把下面代码中的普通函数改为箭头函数,它的this会如何变化?
<body> <div id="root"> <button v-on:click="showInfo">点击提示信息</button> </div> <script type="text/JS"> new Vue({ el: '#root', data: { name: '即兴小索奇' }, methods: { showInfo:(event)=> { console.log(this) // 箭头函数时输出window console.log(this) // 普通函数时输出vue alert('你好哈,点击坐标:' + event.clientX + ',' + event.clientY + ' ' + event.target.innerText); } } }); </script> </body>
- 当showInfo为普通函数时,显示的是Vue对象
- 当showInfo为箭头函数时,显示的是Window对象
在普通函数中,this
的值是在函数被调用时确定的,它可以根据调用的方式(比如函数被作为对象的方法调用、作为构造函数调用等)而发生改变
而在箭头函数中,this
的值是由外围(定义箭头函数的上下文)的上下文确定的,它继承自最近的非箭头函数父级换句话说,箭头函数的 this
始终指向定义箭头函数的代码块所在的上下文,而不是调用箭头函数的方式
这种行为对于在回调函数中捕获外部上下文非常有用,但也可能导致在某些情况下出现意外的结果所以,大家在使用箭头函数时,需要特别注意 this
的行为哈
注意
- 在被Vue管理的函数中(在Vue实例对象里面)最好都写成普通函数,不要写箭头函数!
让我们首先来看看普通函数中的 this
:
函数作为独立函数调用: 当函数作为独立的函数调用时,this
会指向全局对象(在浏览器中通常是 window
对象,Node.js 中是 global
对象)
function normalFunction() { console.log(this); // 在浏览器中输出 window(全局对象) } normalFunction();
函数作为对象方法调用: 当函数作为对象的方法调用时,this
会指向调用该方法的对象
const obj = { name: 'John', greet: function() { console.log(this.name); } }; obj.greet(); // 输出 "John"
函数作为构造函数调用: 当函数用作构造函数创建新对象时,this
会指向正在创建的新对象
function Person(name) { this.name = name; } const person = new Person('Alice'); console.log(person.name); // 输出 "Alice"
而在箭头函数中,this
的行为有所不同:
箭头函数中的 this
: 箭头函数的 this
始终由外围(定义箭头函数的上下文)的上下文决定,它不会因为函数被调用的方式而改变
const arrowFunction = () => { console.log(this); // 这里的 this 是外围上下文中的 this }; arrowFunction(); // 输出的 this 取决于外围上下文
这种行为使得箭头函数在某些情况下非常有用,例如在回调函数中,你可以捕获外部函数的上下文,避免了在回调中使用 that
或 self
来保存上下文
总结来说,普通函数中的 this
在调用时会根据调用方式和上下文而变化,而箭头函数中的 this
始终继承自外围上下文,不会随着调用方式的改变而改变
拓展一下
在箭头函数中,this
的取值是由箭头函数所在代码块的上下文决定的换句话说,箭头函数的 this
继承自最近的非箭头函数父级的 this
值
这意味着,如果箭头函数直接位于全局作用域中,那么它的 this
就会继承自全局对象(例如,在浏览器环境中,就是 window
对象)
让我们来看一个示例:
const arrowFunction = () => { console.log(this); }; arrowFunction(); // 输出的 this 取决于全局上下文,通常是 window 或 global 对象(取决于环境)
在浏览器环境中运行上述代码,arrowFunction
的 this
将指向全局对象 window
然而,如果箭头函数嵌套在其他函数或对象方法中,它的 this
将继承自外围上下文:
function outerFunction() { const innerArrow = () => { console.log(this); }; innerArrow(); } outerFunction(); // 输出的 this 取决于 outerFunction 的上下文
在这个示例中,innerArrow
的 this
将继承自 outerFunction
的上下文
我们可以在不同的上下文中尝试运行这些示例代码,并查看输出的 this
值,以更好地理解箭头函数的 this
行为
这里的this也就是输出全局对象window
<script type="text/JS"> new Vue({ el: '#root', data: { name: '小索奇' }, methods: { showInfo: () => { console.log(this); // 输出全局对象 window,因为箭头函数没有外围上下文 } } }); </script>
索奇问答
这里可能又会有人问了
A:什么是外围上下文?
Q:在JS 中,每个函数都有一个自己的执行上下文(execution context),其中包含函数的作用域、参数、变量等信息函数的执行上下文在函数被调用时创建,随后被推入执行上下文栈(execution context stack)中,函数执行完毕后从栈中弹出
代码举例
假设有一个函数 outer
包含一个函数 inner
,在 inner
函数中,outer
就是 inner
函数的外围上下文
function outer() { // 我是外围 const outerVar = 'I am outer'; function inner() { console.log(outerVar); // 访问外围上下文中的变量 } inner(); } outer(); // 输出 "I am outer"
在这个例子中,inner
函数的外围上下文是包含它的 outer
函数的执行上下文因此,inner
函数可以访问 outer
函数中的变量 outerVar
另一个例子是使用事件处理函数时:
<!DOCTYPE html> <html> <head> <title>Outer Context</title> </head> <body> <button id="myButton">Click Me</button> <script> const button = document.getElementById('myButton'); button.addEventListener('click', function() { console.log(this); // 这里的 this 是事件目标,即按钮元素 console.log('Button clicked!'); }); </script> </body> </html>
当按钮被点击时,事件处理函数中的 this
指向事件目标,即按钮元素这是因为事件处理函数的外围上下文是事件目标的上下文
全局作用域中的外围上下文: 在全局作用域中,外围上下文就是全局上下文~
console.log(this === window); // 在浏览器环境中输出 true,因为 this 在全局作用域中指向全局对象 window
外围上下文就是包裹当前代码块的上一层环境,它决定了代码中的 this
、变量访问等行为
不同的this
- 这里再精简一下this,既然说了,一下子多拓展一点