第七节: 一文带你全面学通v-on事件绑定指令

1. Vue事件的绑定方式理解


vue采用行内事件绑定的方式. 因此在学习vue事件绑定方式之前,先回顾一下JS的行内事件绑定

学习中对比vue的行内事件绑定和JS原生行内事件绑定的不同


我们先来看一个行内事件绑定的示例
示例代码如下:

<style>
    .box{
        color:red;
    }
    .wrap{
        color:skyblue;
    }
</style>
<div id="app">
    <h2 id="box" class="box">Hello World</h2>
    <button onclick="changeColor()">点击切换颜色</button>
</div>

<script>   
    let className = "box"
    function changeColor(){
        if(className =='box'){
            box.className = className = "wrap"

        }else{
            box.className = className =  "box"
        }
    }
</script>

我们先描述一下示例的行为, 标签button 上使用了onclic 属性, 属性值是一个字符串changeColor(). 当用户点击标签是, 会强行将字符串changeColor() 转为JavaScript 语句执行. 也就意味着changeColor() 会作为函数调用. 这就是行业事件绑定的原理, 因此changeColor() 后的() 不能省略


原生JavaScript 这种行内事件的绑定, 并不是我们所推荐的. 相信大家在学习JavaScript 时, 应该有人告诉过你们, 不要使用行内样式, 不用绑定行内样式, 推荐使用HTML, CSS , JavaScript 三层分离的开发方式.

原因就在于, 行内样式和行内事件, 会让HTML 结构,CSS 样式, JavaScript 脚本 耦合性太高. 不利于后续维护.


既然行内样式有这样的问题, 为什么Vue 还要采用行内事件的绑定方式呢?
主要原因就在于行内事件绑定的方式非常明确事件绑定的对象, 不用像原生JavaScript 花大量的时间在DOM 节点的获取上. 还需要考虑不同的DOM 获取方式, 所获取DOM 的差异


至于行内事件耦合性问题, 通过Vue 组件化开发就已经很好的降低了这个问题. 组件本身就是页面某一块的功能, 也方便我们后续的维护. 同时Vue 内部也做了大量的优化处理

vue采用这种方式绑定事件,
原因在于这种绑定方式比较直观的处理事件的绑定, 省去了大量获取DOM的操作.
不用担心Vue的问题, Vue在采用行内事件绑定,内部肯定做了大量的优化处理


2. Vue 事件的绑定与基本使用

Vue 中提供了一个内置的指令v-on , 用于绑定事件,我们可以用 v-on 指令添加一个事件监听器,通过事件监听器触发事件执行程序, 也就是数据处理函数


2.1 v-on指令的认识和使用

v-on指令说明:

  • . v-on指令和其他指令一样,通过v-on绑定事件后,事件属性值将不再是字符串,而是表达式
  • . 就可以在表达式中编写JavaScript 语句

示例:

<div id="app">
    <h2 class="box">点击次数: {{ count }}</h2>
    <!-- 既然click 的值是表达式,那么我们就可以动态的拿到vue ,data属性中的数据,然后操作-->
    <button v-on:click="count++">暴击</button>
</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            count: 0

        }
    })
</script>

示例分析:

示例中最核心的语句就是v-on:click="count++" , 对于该代码, 我们可以进行如下分析:

  1. 通过v-on指令绑定click单机事件, v-on 是绑定事件的指令, click 则是具体的事件名
  2. v-on指定绑定事件的属性值是表达式,表示中可以编写JavaScript语句, 同时在表达式中是可以直接获取vue中的数据

综上分析, Vue 给具有v-on:clickDOM 元素绑定了一个click 事件, 当事件被触发时执行, "count++" 属性值所代表的语句.

每次点击,都会获取数据count 执行++ 操作. 同时因为Vue data中的数据是响应式的, 所以在count 发生变化后, 页面渲染值也会发生变化


这种直接修改数据一般情况下用的比较少, 也不推荐使用. 原因在于通过`v-on`绑定的事件属性值虽然是表达式,但是只能处理单个表达式逻辑, 对于复杂的代码逻辑就会具有局限性. 同时也不方便对于事件对象的处理
再着, 示例工作中, 我们还会考虑代码的整体风格. 开发中保持代码风格, 便于代码的后续维护.

因此,通常会选择在表达式中绑定vue的方法,将方法作为事件函数处理

2.2 v-on绑定methods方法

在使用v-on 指令绑定事件时, 推荐使用Vue选项对象中定义的方法作为事件处理函数.


具体使用操作如下:

  1. 首先我们需要在选项对象methods选项中定义方法,
  2. 然后将方法名法绑定到v-on 指令的属性值中. Vue会自动将该方法作为事件处理函数调用

示例1: 修改上一个示例,限制点击次数

<!-- 限定点击次数 -->
<div id="app">
    <h2 class="box">点击次数: {{ count }}</h2>
    <button v-on:click="handleClick">点击</button>
</div>

<script>   
    const vm = new Vue({
        el: "#app",
        data: {
            count: 0
        },
        methods: {
            handleClick(){
                let count = this.count;
                // 限定显示最大点击次数
                this.count = Math.min(++count,5)
            }
        }
    })
</script>

示例分析:
在实例中v-on:click 绑定事件处理函数为handleClick 也就表示之后每次点击该button 按钮都会执行事件处理函数, 即handleClick 方法. 在方法中修改count 数据. 同时限定了数据的最大值


示例2: 翻转消息

<!-- HTML --->
<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="reverseMessage">逆转消息</button>
</div>

<!-- JS --->
<script>
    new Vue({
        el: "#app-5",
        data: {
            message: 'Hello Vue.js'
        },
        methods: {
            reverseMessage: function(){
               this.message = this.message.split('').reverse().join('')
            }
        }
    })
</script>

示例分析:示例中代码运行的主要逻辑就一下几点:

  1. 当按钮button被点击时,就会触发methods选项中的的方法,
  2. 在方法中修改data选项中数据, 当数据count被修改时触发响应系统, 进而触发视图的重新渲染,

最终结果就是页面显示内容发生了反转


这里有一个非常需要注意的点.:

methods选项中方法,不能和data选项中的数据重名,因为data 中的数据和methods中的方法都会在Vue初始化时成为Vue实例对象的属性或方法


2.3 事件绑定的简写方式

之前我们在分析v-bind 指令时, 说过该指令可以简写成:
同样v-on指令也有简写方式, 即@

语法格式如下:

<!-- 完整语法 -->
<button v-on:click="reverseMessage">逆转消息</button>

<!-- 缩写 -->
<button @click="reverseMessage">逆转消息</button>

3. 关于函数内的this指向问题

3.1 普通函数this

方法内this默认指向实例对象,因此就可以通过this代替实例对象处理很多操作

示例:

<div id="app">
    <!-- 绑定事件触发Vue方法 -->
    <button @click="reversed">按钮</button>
</div>

<script>
    let vm = new Vue({
        el: "#app",
        data: {
            msg: "Hello Vue"
        },
        methods: {
            reversed() {
                console.log(this) // 实例对象
            }
        }
    })
</script>

点击结果

methods方法中this指向.png


3.2 箭头函数中this

方法写可以写成箭头, 但需要注意的是JavaScript 箭头函数作用域中没有this, 按照JavaScript 作用域链规则, 箭头函数中使用的this 获取是箭头函数所在作用域中的this , 我们可以看一下, 箭头函数中this 指向谁

如果改为箭头函数为如下写法:,

{
    reversed:() =>  {
        console.log(this) // 实例对象
    }
}

那么我们就将实例中的方法换成箭头函数

<div id="app">
    <!-- 绑定事件触发Vue方法 -->
    <button @click="reversed">按钮</button>
</div>

<script>
    let vm = new Vue({
        el: "#app",
        data: {
            msg: "Hello Vue"
        },
        methods: {
            reversed:()=> {
                console.log(this) // 实例对象
            }
        }
    })

</script>

点击结果:

methods方法使用箭头函数中this.png
我们会发现此时箭头函数中的this 指向的不在是Vue 实例对象, 而是Window 对象.
也可以理解为方法丢失了this 指向.
所以通常我们不会建议Vue 的方法使用箭头函数. 具体看下一节分析


4. methods 方法中不推荐使用箭头函数

上一小节中我们已经了解方法的不同写法会导致this的不同, 那么就来罗列一下不推荐使用箭头函数的原因

4.1 methods不推荐使用箭头函数

不推荐使用功能箭头函数说明:

1. vue是以数据作为驱动的,数据的变化将会触发vue响应系统,同时更改页面的渲染结果,
2. vue以数据为驱动,也就是说我们在未来的操作中将大量操作数据,
3. 数据被处理为Vue 实例vm上的属性,那么我们就需要大量的通过vm对象来调用数据, 本质上就是对象.属性的操作
4. 甚至methods的中的方法也会挂在在vm对象上的,
5. 因此箭头函数会影响我们对于数据和方法的获取,因为箭头函数thiswindow


也正式因为this 改变了这个原因,我们不推荐方法使用箭头函数,因为这样会丢失this 指向, 那么我们就不能利用this 来获取数据和其他的方法了.


看下面的例子

<div id="app">
    <button @click="handleClick">非箭头函数中this</button>
    <button @click="handleClickTwo">箭头函数中的this</button>
</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            msg: "hello"
        },
        methods: {
            handleClick(){
                console.log(this)  // vue实例化对象
            },
            handleClickTwo: () => {
                console.log(this) // window 对象
                
            },
        }
    })
</script>

这样我们就会发现如果我们使用普通函数, 那么要获取数据就很简单

handleClick(){
    console.log(this)  // vue实例化对象
    // 利用this 获取数据
    console.log(this.msg)  // 获取数据
},

不知道大家会不会有个疑问, 如果在一个方法中不使用Vue 的数据, 是不是就意味着可以使用箭头函数.
答案当然是确定的. 但是这样代码编写的风格就不统一了


总结:

methods 选项中方法函数中如果不需要操作Vue实例上的属性和方法, 可以使用箭头函数,

但是一般不推荐使用箭头函数, 原因

  1. 首先是因为我们可能需要在方法中获取Vue实例对象的其他数据或其他方法,
  2. 其次统一的编码风格, 总不至于有的用箭头函数,有的不用吧,

4.2 关于Vue方法里使用箭头函数误区

但是我们需要避免一个误区:

我们推荐不使用箭头函数是methods的方法, 不是说真个Vue项目里都不能使用箭头函数,

比如我们如果在方法里还有函数,在函数中需要使用vue实例化对象我们这个时候用箭头函数会比非箭头函数要方便很多

示例:

<div id="app">
    <button @click="handleClick">查看this</button>
</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            msg: "hello"
        },
        methods: {
            handleClick(){
                console.log(this)  // vue实例化对象

                // 延迟修改数据
                // 1.方法内使用普通函数,查看普通函数中this
                setTimeout(function(){
                    console.log(this)  // window 对象
                    
                    // 这个是有要修改数据,还的使用vm
                    vm.msg = "wrod"
                }, 1000)

                // 2.方法内使用箭头函数, 查看函数内this
                setTimeout(() => {
                    console.log(this) // vue实例对象
                    
                    // 这个是有修改数据,依然可以使用this
                    this.msg = "wuwei"
                
                }, 2000)
            },

        }
    })
</script>

是这里这种场景下,我们推荐使用箭头函数, 好处相信大家也通过示例看出来了

至于用不用箭头函数,完全看自己的需求, 而不是说不推荐使用箭头函数,就整个Vue项目中一个箭头函数都不用了,

要关注一下是哪里不推荐使用箭头函数. 在那些场景下, 箭头函数能给我们带来更好的便利

因此:

Vue中是不是用箭头函数,完全看你自身的情况,千万不要听人说Vue不推荐使用箭头函数,就整个Vue项目中一个箭头函数都不用, 用不用,看this


5. 关于方法的事件对象

在调用方法的时候有两种使用方式,一种是不加括号,一种加括号

例如:

<!--不加括号 -->
<button @click="reversed">点击</button>

<!--加括号 -->
<button @click="reversed()">点击</button>
<button @click="reversed(12345)">点击</button>

那么很明显使用加括号的方式是为了传递参数给事件函数,

那么我们就来看看不同的事件绑定方式对于事件对象的影响


5.1 不加括号

不加括号的情况下,默认第一个形参就是事件对象

<div id="app">
    <!-- 不加括号绑定事件 -->
    <button @click="reversed">点击</button>
</div>

<script>
    let vm = new Vue({
        el: "#app",
        data: {
            msg: "Hello Vue"
        },
        methods: {
            reversed:(ev)=> {
                console.log(ev) // 事件对象
            }
        }
    })

</script>

页面点击结果:

事件函数绑定不加括号.png
不加括号的劣势相信大家也看出来了, 就是没办法给事件函数添加自定义的数据.


5.2 加括号

如果加括号无论你传不传实参,形参默认就是要接受你传递的实参
示例:

<div id="app">
    <!-- 加括号未传参 -->
    <button @click="reversed()">点击</button>

    <!-- 加括号传参 -->
    <button @click="reversed(123)">点击2</button>
</div>

<script>
    let vm = new Vue({
        el: "#app",
        data: {
            msg: "Hello Vue"
        },
        methods: {
            reversed:(ev)=> {
                console.log(ev) // 事件对象
            }
        }
    })

</script>

点击后的结果

事件加括号绑定.png

通过示例可以看出, 事件绑定加括号, 但是没有传递任何实参的情况下, 事件函数接受的第一个形参就是undefined , 因为没有接受到任何事件 , 加括号的目的就是为了手动传递实参

那么问题来了, 如果我需要传参时如何获取事件对象呢


5.3 绑定事件手动传递事件对象

如果加括号就需要手动的传递事件对象

示例

<div id="app">
    <!-- 手动传递事件对象,此时$event就是事件对象 -->
    <button @click="reversed($event,123)">点击</button>

</div>

<script>
    const vm = new Vue({
        el:"#app",
        data:{
            msg:"Hello Vue"
        },
        methods: {
            reversed(ev,num){
                console.log(ev) // 事件对象
                console.log(num) // 123
            }
        }
    })

</script>

点击结果

手动传递事件对象.png
如果我们选择使用() 的方式绑定事件函数, 我们就可以通过$event 获取事件对象. 通过参数传递的方式将事件对象传递给事件函数


5.4 默认事件对象的变量

同时还发现: 无论加不加括号,传不传参数,在函数里都会一个变量event, 该值默认就是事件对象, 所以不要定义同名变量将其覆盖就可以了

示例:

<div id="app">
    <!-- 手动传递事件对象,此时$event就是事件对象 -->
    <button @click="reversed($event,123)">点击</button>

</div>

<script>
    const vm = new Vue({
        el:"#app",
        data:{
            msg:"Hello Vue"
        },
        methods: {
            reversed(ev,num){
                console.log(event);

            }
        }
    })

</script>

点击显示结果

默认的事件对象.png


总结:

  1. 方法写在methods选项中
  2. 事件函数不需要传参时可以不加括号, 需要传参加括号
  3. 事件函数无括号,默认第一个参数是事件对象
  4. 事件函数有括号,需要手动传递事件对象
  5. 无论事件函数有无括号,event变量都是事件对象,前提不能有同名变量覆盖
  6. 事件函数一定要注意其this 指向问题
  • 30
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值