摘要:源碼真的這么可怕嗎從以上的事例中可以看出,其實并沒有。對于源碼的恐懼,讓我們漸漸思維固化,自己告訴自己不要去碰源碼,時間長了就遺忘了還有這樣一條路可走。
一個小需求
事情的起因,是昨天有一個新的需求被提出。
需求是要實現,讓我們自己定制的彈出層,具備按下 ESC 也能退出的功能。我把任務交給了同組的小伙伴S去實現。(這個項目用到了vue技術棧,以及餓了么的UI框架。)
我開完會回來,發現他還在處理那個功能,但好像遇到了什么瓶頸。于是,我就問他,卡在了什么地方。
小伙伴S說,他百度了不少資料,還查了官方文檔,并且嘗試其中的辦法,但就是無法觸發按下 ESC 的回調方法,很是郁悶。我看了他的代碼,他的寫法是這樣的:
...
... 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:歡迎關注我的公眾號 “超哥前端小棧”,交流更多的想法與技術。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100881.html
摘要:讓你收獲滿滿碼個蛋從年月日推送第篇文章一年過去了已累積推文近篇文章,本文為年度精選,共計篇,按照類別整理便于讀者主題閱讀。本篇文章是今年的最后一篇技術文章,為了讓大家在家也能好好學習,特此花了幾個小時整理了這些文章。 showImg(https://segmentfault.com/img/remote/1460000013241596); 讓你收獲滿滿! 碼個蛋從2017年02月20...
摘要:歡迎來我的個人站點性能優化其他優化瀏覽器關鍵渲染路徑開啟性能優化之旅高性能滾動及頁面渲染優化理論寫法對壓縮率的影響唯快不破應用的個優化步驟進階鵝廠大神用直出實現網頁瞬開緩存網頁性能管理詳解寫給后端程序員的緩存原理介紹年底補課緩存機制優化動 歡迎來我的個人站點 性能優化 其他 優化瀏覽器關鍵渲染路徑 - 開啟性能優化之旅 高性能滾動 scroll 及頁面渲染優化 理論 | HTML寫法...
閱讀 1990·2023-04-25 16:19
閱讀 3102·2021-11-24 09:39
閱讀 834·2021-11-16 11:44
閱讀 1694·2019-08-29 12:52
閱讀 1143·2019-08-26 13:33
閱讀 1079·2019-08-26 10:26
閱讀 2206·2019-08-23 16:42
閱讀 2571·2019-08-23 14:37