迄今为止,我们比较深入了讲了 “绑定” 和 “渲染” 相关的内容。
而且,通过上一篇 “条件渲染”,我们还能实现某种程度动态的画面切换。
你可能也注意到了 —— 尤其是如果你有 GUI 应用程序的开发经验的话 ——
我们在 “条件渲染” 这一篇里,并没有处理 “单选按钮” 的 “选中状态变更” 事件,
而是使用了基于 “绑定” 的数据驱动画面 (MVx)的方式,由 Vue 帮我们完成了事件处理和画面刷新的工作。
你也能感觉到这种做法的局限 —— 比如说没法处理 按钮 的点击事件 —— 所以,接下来让我们学习一下普通事件是怎么处理的。
Vue 官网上相关的内容在:https://cn.vuejs.org/v2/guide/events.html,不过我们还是掰碎了、挑最常用的来说。
由于 Vue 只是帮我们简化了 HTML 的相关处理,所以我们还是从 HTML 的原生事件处理入手;知道了本质,举一反三更加容易。
假设我们要做一个按钮,点击后提示 “Hello, World!”。为了顺带了解一下事件参数,我们在提示信息里把点击时鼠标的位置也显示出来。
使用原生的 HTML ,有以下 2 种实现方式。
1)在 元素上直接使用 onclick 属性设置回调函数: (注意 onclick 属性的值设置成了一个字符串)
如果你对 JavaScript 的函数不太熟,可以顺带看一下 https://zh.javascript.info/function-basics。
2)使用 JavaScript 动态设置 元素上的 onclick 属性: (注意 onclick 属性的值设置成了一个函数,同时需要给按钮加上 id 或者其他标识)
原生 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)
我们再来看一下,用 Vue 怎么实现同样的效果。
仔细比对一下原生 HTML 的写法,可以发现 Vue 的写法有几个特征,可以快速复制:
1)使用 v-on:click 属性代替了原生的 onclick 属性 —— 但是仍然可以监控到 点击 事件。
2)用 $event 代替了原生的 event —— 用于传递事件的参数。
3)在 methods 中间增加了 v-on:click 中指定的函数。
最基本的事件处理方式,就是这样的 —— 简单吧?
Vue 还允许把 v-on 简写成 @ ,于是还能再少敲 4 个字符。(还记得 : 是什么的简写不?千万不要记混了 ......)
1)传递原生 DOM 事件的参数:
上面的例子中,我们使用 Vue 自定义的 $event 来传递原生 DOM 事件的参数。
如果只使用原生 DOM 事件的参数的话,咱们可以进一步简化,只在 @click 属性中设置函数的名称 —— 连 $event 都不用写。
但是,一定要注意,只写函数名,连 () 都不要写。不然意思就变成了,事件处理函数中不使用任何参数 —— 点击按钮的时候,处理函数也会报错。
2)不使用参数:
以按钮点击事件为例,不同的按钮可能本身就代表着不同的业务逻辑,对应的处理函数也不一样;这时,可能连参数都不用,通过处理函数就能直接区分出来。
比如说,我们写这篇文章的编辑画面,右上角有 “保存草稿” 和 “发布文章” 这两个按钮。
它们的业务处理不一样,代码中可能就直接绑定了不同的处理函数。
3)使用自定义参数:
同样是按钮,也有业务逻辑基本一样的情况。
比如说,在表格中展示一组查询结果,并且在每一行中加入对应的操作按钮,点击后可以编辑这一行对应的记录。
此时,我们需要给把所有的 “编辑” 按钮的点击事件绑定到同一个函数,但是调用时把本行对应的数据传过去。
核心代码大概是这样的:
1)使用 v-for 来批量生成每一行;
2)每一行的 “编辑” 按钮的点击事件都绑定到同一个 edit 函数,而且在调用时指定本行(也就是 v-for 中 in 之前迭代的部分)的数据。
{{student.id}}
{{student.name}}
methods: {
edit: function(id) {
alert("编辑学生信息,id = " + id);
}
}
类似的还有 单选框、复选框、选择框 中的选中状态发生变化时的处理函数,也会采用类似的方式批量生成和设置处理函数。
(要是有点儿忘了,可以翻翻:没时间学 Vue (5) —— 绑定(四):面向单选、复选和选择框的 v-model。)
我们已经知道如何绑定(接收)事件了,可是事件的处理函数里要写些什么呢?不能总像上面的例子那样,什么也不做、光弹个提示框。
正常的事件处理里面,我们总是要处理一些画面上的数据、给后台发个请求然后把后台的返回结果展示出来的。
也就是说,事件处理函数里面经常要处理(获取 and/or 更新)绑定数据的,而且可能会调用其他的处理函数。
比如说,我们要做一个简单的调整某个数值的功能,画面大概是这样的:
默认值是 10,按 - 号按钮就减一,按 + 号按钮就加一。
一种实现方式可能是这样的:(从简单描述的角度,先不合并这两个按钮的事件处理函数)
{{value}}
其中,需要特别注意的是,我们在函数里操作绑定数据的时候,前面要加一个 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 。
除了上面提到的 点击 事件,常见的 DOM 事件还有:
1)鼠标拖拽事件:
https://zh.javascript.info/mouse-drag-and-drop
2)键盘事件:(KeyDown、KeyUp )
https://zh.javascript.info/keyboard-events
接下来是各种混乱的 输入类 组件,根据类型不同,触发的事件也不同。
3)关于各类文本框( 和
https://zh.javascript.info/focus-blur
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/input_event
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event
4)关于单选框()的事件:
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event
5)关于复选框()的事件:
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event
6)关于选择框(
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/change_event
有兴趣、有时间的话,可以为每一类输入组件写一组事件监听的测试程序;亲自动手跑一下,更能加深理解。
比如说,测试复选框事件的参考代码如下:
事件记录:
{{e}}
对应的画面输出如下:
虽然上面写了很长一段,其实只覆盖了很小的一部分。
其他内容需要对 DOM 有较为深入的理解。
比如说:
1)要做一个只能输入数字的文本框,那就需要处理 keydown 事件,并且 “吃掉” 非数字的输入;
2)要弹出自定义的右键菜单,那需要处理 contextmenu 事件,同时屏蔽浏览器的默认事件处理。
新手处理这类事件的机会不多,有时间的话可以看一些资料,提前储备一些知识:
https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Events
https://zh.javascript.info/events
今天的内容比较多,既要绑定事件,又要写相应的处理函数。
1)模拟一个简单的 分页 功能。
最多 10 页,开始时在第 1 页。
如果已经是第 1 页,点击【前一页】按钮时,提示 “已经到第一页了” ;
如果已经是最后 1 页了,点击【后一页】按钮时,提示 “已经到最后一页了”。
2)模拟一个简单的 计算练习 功能。
数字随机生成。需要使用 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/random
点击【重新生成】按钮时,重新生成数字,并且更新计算结果。