一个小需求
事变的原由,是昨天有一个新的需求被提出。
需求是要完成,让我们本身定制的弹出层,具有按下 ESC 也能退出的功用。我把使命交给了同组的小伙伴S去完成。(这个项目用到了vue手艺栈,以及饿了么的UI框架。)
我开完会返来,发明他还在处置惩罚谁人功用,但彷佛碰到了什么瓶颈。因而,我就问他,卡在了什么地方。
小伙伴S说,他百度了不少材料,还查了官方文档,而且尝试个中的要领,但就是没法触发按下 ESC 的回调要领,异常忧郁。我看了他的代码,他的写法是如许的:
<div class="custom-modal" @keydown.27="handlePressEscape">
...
</div>
...
handlePressEscape () {
console.log('press escape!');
},
...
他的主意不错,由于是自定义的弹出层,所以就想着把 keydown 事宜,绑定在最外层的 div 上,让全部弹出层都能监听到。
他给我看了他查的材料,险些都是在 input 上绑定 keydown 事宜的例子,而 vue 的官方文档里也是相似的例子,实践后却陷入了瓶颈。然则他疏忽了一个问题,keydown 事宜,并不是绑在恣意一个标签上,都邑起作用。
一种思绪
我没有直接把答案通知他,而是给他供应了一个思绪:在我们常常运用的 element-ui 的 el-dialog 组件里,有个属性叫做 close-on-press-escape
,它的诠释如下图:
从文档的诠释,能够看出 el-dialog 在默许情况下,已完成了我们须要处理的需求。所以,我让他看看 el-dialog 的源码,是怎样完成的。
他一听要看源码,就露出了恐惊之情。
源码是一切框架和API的基础,由于比较庞杂深奥,所以让人很抗拒。我本身也经历过这个阶段,所以异常邃晓他的心境,勉励他一同做一次尝试。
查找源码
起首,我们在 node_modules 里,找到了 element-ui的文件夹,它大抵长这个模样:
接着,我们找到了 packages 里的 dialog 文件夹,再从 index 进口,找到了组件 component.vue。但是,点进去找了半天,也只找到个 closeOnPressEscape 属性的定义,却没有完成的要领。
...
closeOnPressEscape: {
type: Boolean,
default: true
},
...
这么奇异么?只定义一个属性,就可以完成一个事宜的交互了?
觉得不太可能啊?!? 为了揭开迷雾,继承找。。。
细致阅读了 component.vue 文件,发明在 script 里,引入下面 3 个文件:
import Popup from 'element-ui/src/utils/popup';
import Migrating from 'element-ui/src/mixins/migrating';
import emitter from 'element-ui/src/mixins/emitter';
...
在第一个引入的 Popup 中,居然也发明了 closeOnPressEscape,觉得好像找对方向了。
但使人懊丧的是,Popup 中一样只要 closeOnPressEscape 的属性定义,却没有完成。不过,它却引入了另一个辅佐文件 PopupManager,再点进去找。
哇!终究找到了!它的完成,是如许的:
// handle `esc` key when the popup is shown
window.addEventListener('keydown', function(event) {
if (event.keyCode === 27) {
const topPopup = getTopPopup();
if (topPopup && topPopup.closeOnPressEscape) {
topPopup.handleClose
? topPopup.handleClose()
: (topPopup.handleAction
? topPopup.handleAction('cancel')
: topPopup.close());
}
}
});
本来,是在 window 上增加了事宜监听 keydown,当监测到是 ESC 的 keyCode 时,则实行相干操纵。
模拟源码
ok,如今已晓得了道理,那就根据我们的现实需求,模拟革新一下:
...
props: {
...
closeOnPressEscape: {
type: Boolean,
default: true
}
},
...
mounted () {
window.addEventListener('keydown', this.handlePressEscape);
},
destroyed () {
window.removeEventListener('keydown', this.handlePressEscape);
},
methods: {
...
handlePressEscape (event) {
if (this.closeOnPressEscape && event.keyCode === 27) {
this.handleClose();
}
}
}
在上述完成中,有2个须要注重的点:
- 代码方面,在 mounted 中,给 window 增加事宜监听以后,要记得在 destroyed 时,去除监听。
- 营业方面,这是一个我们定制的通用的弹出层组件,所以在 props 中定义了一个 closeOnPressEscape 属性,以方便在某些营业场景下,不须要按 ESC 就退出这个功用的时刻,直接设置它为 false 即可。
到此为止,全部事宜画上了美满的句号。
源码真有那末恐怖吗?
源码一词,乍一听就是神奇、嵬峨上、吊炸天的代名词,让许多的前端同砚心惊胆战。追念当初,我也曾一度对它有一股深深的恐惊。
源码真的这么恐怖吗?
从以上的事例中能够看出,实在并没有。例子中的element-ui源码并不庞杂,我和小伙伴S一同看源码时,他也也许都能看得邃晓。末了由于弄懂了背地的道理,举行简朴运用,比较轻松地就处理了问题。
关于源码的恐惊,让我们逐渐头脑固化,本身通知本身不要去碰源码,时候长了就遗忘了另有如许一条路可走。
口试中的运用
关于对源代码的考核,我也会常常运用在口试中。在口试中,假如候选人给我的觉得不错,我的习用手法是问下面这个问题:
适才你说到,用过一段时候 xxx 框架,xx API属性也用过,也很清晰它到达的结果。
那末如今,假如须要你完成一个相似的结果,抛开 xxx 框架以及 xx API属性,
你会怎样去完成,有无其他思绪?
这个问题,意在考量候选人的头脑体式格局和处理问题的才能,以及把他思索的历程论述清晰的表达才能。这三种才能,每每比运用过某些框架的履历,更让我看中。
这道题的回复思绪,实在就是能够经由过程发掘源码,去完成功用。别的也能够经由过程海量地查找材料,发明原生js的完成体式格局,但这条路没有直接发掘源码来得快。在碰到现实的营业问题的时刻,参考源码的道理和写法,每每能更快地处理问题。
这是我本身对这道问题,给出的答案。
一点点思索
昨天的案例,引发了我的一连串思索:
当代框架确实降低了前端入门的门坎,提高了开辟效力。
然则,在运用这些框架的历程当中,我们究竟学到了什么?
脱离了框架和它的API,我们脑海中还剩下些什么?
以至于,当下一个更新更棒的框架涌现的时刻,我们是否能够用已学到的学问,协助本身更迅速地上手?
知其然,并知其所以然,进修一切的学问都应当有这类探究精力。我们不仅仅是代码的搬运工。意会这些深层次的道理,比起仅仅熟练地控制一门框架,要有用很多。
PS:迎接关注我的民众号 “超哥前端小栈”,交换更多的主意与手艺。