没时间学 Vue (8) —— 事件处理(一):简单 DOM 事件的处理方式

迄今为止,我们比较深入了讲了 “绑定” 和 “渲染” 相关的内容。

而且,通过上一篇 “条件渲染”,我们还能实现某种程度动态的画面切换。

你可能也注意到了 —— 尤其是如果你有 GUI 应用程序的开发经验的话 —— 

我们在 “条件渲染” 这一篇里,并没有处理 “单选按钮” 的 “选中状态变更” 事件,

而是使用了基于 “绑定” 的数据驱动画面 (MVx)的方式,由 Vue 帮我们完成了事件处理和画面刷新的工作。

你也能感觉到这种做法的局限 —— 比如说没法处理 按钮 的点击事件 —— 所以,接下来让我们学习一下普通事件是怎么处理的。

Vue 官网上相关的内容在:https://cn.vuejs.org/v2/guide/events.html,不过我们还是掰碎了、挑最常用的来说。

 

1、HTML 原生的事件处理


由于 Vue 只是帮我们简化了 HTML 的相关处理,所以我们还是从 HTML 的原生事件处理入手;知道了本质,举一反三更加容易。

假设我们要做一个按钮,点击后提示 “Hello, World!”。为了顺带了解一下事件参数,我们在提示信息里把点击时鼠标的位置也显示出来。

使用原生的 HTML ,有以下 2 种实现方式。

1)在 <input> 元素上直接使用 onclick 属性设置回调函数: (注意 onclick 属性的值设置成了一个字符串)

    <input type="button" value="测试按钮" onclick="onButtonClicked(event)">
    <script>
      function onButtonClicked(e) {
        alert("Hello, world! (" + e.x + ", " + e.y + ")");
      }
    </script>

如果你对 JavaScript 的函数不太熟,可以顺带看一下 https://zh.javascript.info/function-basics

2)使用 JavaScript 动态设置 <input> 元素上的 onclick 属性: (注意 onclick 属性的值设置成了一个函数,同时需要给按钮加上 id 或者其他标识)

    <input id="testButton" type="button" value="测试按钮">
    <script>
      // 处理函数
      function onButtonClicked(e) {
        alert("Hello, world! (" + e.x + ", " + e.y + ")");
      }

      // 设置 testButton 按钮的 点击事件 处理函数。
      // HTML 加载时执行。
      document.getElementById("testButton").onclick = onButtonClicked;
    </script>

原生 HTML 中有各式各样的事件(不过对比 WIN32 的 MSG 类型定义也只是小巫见大巫了),

可以看  https://zh.javascript.info/introduction-browser-events  有个大概的印象,

遇到具体的事件再查询 https://zh.javascript.info/event-details 和 https://zh.javascript.info/forms-controls,(略去了页面声明周期、文档加载和观察者等不常用的部分)

比如说 onclick 事件的详细描述在 https://zh.javascript.info/mouse-events-basics

(当然,英文无障碍的话首选 MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Element

 

2、Vue 中的事件处理方法


我们再来看一下,用 Vue 怎么实现同样的效果。

    <div id="app">
      <input type="button" value="测试按钮" v-on:click="onButtonClicked($event)">
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        methods: {
          onButtonClicked: function(e) {
            alert("Hello, world! (" + e.x + ", " + e.y + ")");
          }
        }
      });
    </script>

 

仔细比对一下原生 HTML 的写法,可以发现 Vue 的写法有几个特征,可以快速复制:

1)使用 v-on:click 属性代替了原生的 onclick 属性 —— 但是仍然可以监控到 点击 事件。

2)用 $event 代替了原生的 event —— 用于传递事件的参数。

       

3)在 methods 中间增加了 v-on:click 中指定的函数

    

最基本的事件处理方式,就是这样的 —— 简单吧?

Vue 还允许把 v-on 简写成 @ ,于是还能再少敲 4 个字符。(还记得 : 是什么的简写不?千万不要记混了 ......)

 

3、Vue 事件处理中的参数传递


1)传递原生 DOM 事件的参数:

上面的例子中,我们使用 Vue 自定义的 $event 来传递原生 DOM 事件的参数。

如果只使用原生 DOM 事件的参数的话,咱们可以进一步简化,只在 @click 属性中设置函数的名称 —— 连 $event 都不用写。

但是,一定要注意,只写函数名,连 () 都不要写。不然意思就变成了,事件处理函数中不使用任何参数 —— 点击按钮的时候,处理函数也会报错。

2)不使用参数:

以按钮点击事件为例,不同的按钮可能本身就代表着不同的业务逻辑,对应的处理函数也不一样;这时,可能连参数都不用,通过处理函数就能直接区分出来。

比如说,我们写这篇文章的编辑画面,右上角有 “保存草稿”  和  “发布文章”  这两个按钮。

它们的业务处理不一样,代码中可能就直接绑定了不同的处理函数。

3)使用自定义参数:

同样是按钮,也有业务逻辑基本一样的情况。

比如说,在表格中展示一组查询结果,并且在每一行中加入对应的操作按钮,点击后可以编辑这一行对应的记录。

此时,我们需要给把所有的 “编辑” 按钮的点击事件绑定到同一个函数,但是调用时把本行对应的数据传过去。

核心代码大概是这样的:

1)使用 v-for 来批量生成每一行;

2)每一行的 “编辑” 按钮的点击事件都绑定到同一个 edit 函数,而且在调用时指定本行(也就是 v-for 中 in 之前迭代的部分)的数据。

        <tr v-for="student in students">
          <td>{{student.id}}</td>
          <td>{{student.name}}</td>
          <td><input type="button" value="编辑" @click="edit(student.id)"></td>
        </tr>
        methods: {
          edit: function(id) {
            alert("编辑学生信息,id = " + id);
          }
        }

类似的还有 单选框、复选框、选择框 中的选中状态发生变化时的处理函数,也会采用类似的方式批量生成和设置处理函数。

(要是有点儿忘了,可以翻翻:没时间学 Vue (5) —— 绑定(四):面向单选、复选和选择框的 v-model。)

 

4、Vue 事件处理中处理绑定数据、调用其他函数


我们已经知道如何绑定(接收)事件了,可是事件的处理函数里要写些什么呢?不能总像上面的例子那样,什么也不做、光弹个提示框。

正常的事件处理里面,我们总是要处理一些画面上的数据、给后台发个请求然后把后台的返回结果展示出来的。

也就是说,事件处理函数里面经常要处理(获取 and/or 更新)绑定数据的,而且可能会调用其他的处理函数。

比如说,我们要做一个简单的调整某个数值的功能,画面大概是这样的: 

默认值是 10,按 - 号按钮就减一,按 + 号按钮就加一。

一种实现方式可能是这样的:(从简单描述的角度,先不合并这两个按钮的事件处理函数)

    <div id="app">
      <input type="button" value="-" v-on:click="minusOne()">
      {{value}}
      <input type="button" value="+" v-on:click="plusOne()">
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        data: {
          value: 10
        },
        methods: {
          minusOne: function() {
            this.value -= 1;
          },          
          plusOne: function() {
            this.value += 1;
          }
        }
      });
    </script>

其中,需要特别注意的是,我们在函数里操作绑定数据的时候,前面要加一个 this 的


如果不加的话,画面上的数值就不会变了 —— 也就是根本没有操作到绑定数据。

这点跟很多熟知的编程语言不太一样 —— 比如说 C++、Java 和 C# 里,访问成员变量的时候,加不加 this 都是没问题的。

之所以这么另类,主要是因为 JavaScript 固有的 this 会随着上下文变化的历史遗留问题。

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this

https://www.ruanyifeng.com/blog/2018/06/javascript-this.html

此外,Vue 对于 data 和 methods 的封装,也稍微让问题更复杂了一点儿。

简单来说,你可以这么理解 Vue 处理 data 和 methods 的方式 (把 data 和 methods 抽出来,合并到另一个新的对象中去了)

所以,从 methods 中访问 data 的时候,必须加上 this,不然就找不到了。

我们也可以进一步推测,methods 中的函数相互调用的时候(比如在 minusOne 中调用 plusOne 的话),也是需要加 this 的。

你可能会好奇地问,要是我要在函数中访问 el 的话,是不是也是加 this 就行了呢?

恭喜你又问了一个超越 80% 同行的问题,Vue 并没有把 el 简单地添加到新的对象里,所以加了 this 也访问不到。

非要打破砂锅问到底的话,答案在这里: https://cn.vuejs.org/v2/api/#el 。

 

5、常见 DOM 事件


除了上面提到的 点击 事件,常见的 DOM 事件还有:

1)鼠标拖拽事件:

    https://zh.javascript.info/mouse-drag-and-drop

2)键盘事件:(KeyDown、KeyUp )

    https://zh.javascript.info/keyboard-events

接下来是各种混乱的 输入类 组件,根据类型不同,触发的事件也不同。

3)关于各类文本框(<input type="text"> 和 <textarea>)的事件:

  • 获得焦点、失去焦点事件:

      https://zh.javascript.info/focus-blur

  • input 事件: 文本内容发生变化时触发

      https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/input_event

  • change 事件: 失去焦点后、如果文本内容发生变化才会触发

      https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event

4)关于单选框(<input type="radio">)的事件:

  • change 事件: 选中本单选框时才会触发,选中其他单选框导致本单选框勾掉的时候不会触发

      https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event

5)关于复选框(<input type="checkbox">)的事件:

  • change 事件: 勾选和勾掉的时候都会触发(不管是用鼠标还是键盘)

      https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event

6)关于选择框(<select>)的事件:

  • change 事件:选择的项目发生变化时才会触发

      https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event

有兴趣、有时间的话,可以为每一类输入组件写一组事件监听的测试程序;亲自动手跑一下,更能加深理解。

比如说,测试复选框事件的参考代码如下:

    <div id="app">
      <input type="text" value="测试文本" @keydown="onKeyDown" @keyup="onKeyUp" @input="onInput"
      @change="onChange" @select="onSelect" @blur="onBlur" @focus="onFocus"/>
      
      <div>事件记录: <input type="button" value="清空" @click="clearEvents">
        <div v-for="e in events">{{e}}</div>
      </div>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        data: {
          events: []
        },
        methods: {
          clearEvents: function () {
            this.events = [];
          },
          addEvent: function(text) {
            this.events.unshift(text);
          },
          onKeyDown: function (e) {
            this.addEvent(`[onKeyDown] key = ${e.key}`);
          },
          onKeyUp: function (e) {
            this.addEvent(`[onKeyUp] key = ${e.key}`);
          },
          onInput: function (e) {
            this.addEvent(`[onInput] data = ${e.data}`);
          },
          onChange: function (e) {
            this.addEvent(`[onChange]`);
          },
          onSelect: function (e) {
            this.addEvent(`[onSelect]`);
          },
          onBlur: function (e) {
            this.addEvent(`[onBlur]`);
          },
          onFocus: function (e) {
            this.addEvent(`[onFocus]`);
          }
        }
      });
    </script>

对应的画面输出如下:

 

6、DOM 事件处理的进阶用法


虽然上面写了很长一段,其实只覆盖了很小的一部分。

其他内容需要对 DOM 有较为深入的理解。

比如说:

1)要做一个只能输入数字的文本框,那就需要处理 keydown 事件,并且 “吃掉” 非数字的输入;

2)要弹出自定义的右键菜单,那需要处理 contextmenu 事件,同时屏蔽浏览器的默认事件处理。

新手处理这类事件的机会不多,有时间的话可以看一些资料,提前储备一些知识:

   https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Events

   https://zh.javascript.info/events

 

7、思考题


今天的内容比较多,既要绑定事件,又要写相应的处理函数。

1)模拟一个简单的 分页 功能。

最多 10 页,开始时在第 1 页。

如果已经是第 1 页,点击【前一页】按钮时,提示 “已经到第一页了” ;

如果已经是最后 1 页了,点击【后一页】按钮时,提示 “已经到最后一页了”。

 

2)模拟一个简单的 计算练习 功能。

数字随机生成。需要使用 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/random 😄

点击【重新生成】按钮时,重新生成数字,并且更新计算结果。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值