我經(jīng)常和面試者聊的一個題目
作為一個Web前端從業(yè)者,資深B/S架構(gòu)的應(yīng)用開發(fā),通常我們負(fù)責(zé)的內(nèi)容都是側(cè)重的瀏覽器端比較多,即便目前Vue、React等各種框架庫流行的年代,核心實現(xiàn)也依然是JS API操作DOM;如果資歷更深一些的同學(xué),還會熟知jQuery,更是因為各瀏覽器API不統(tǒng)一作為其解決的問題痛點。
在長期擔(dān)任Web前端面試官的過程中,我歸納沉淀了一些有趣的面試題目,今天來聊其中一個與DOM操作相關(guān)的題,可以用于考察一個前端工程師的邏輯條理性、問題分析解決能力、純Web前端(瀏覽器端)JS技術(shù)基礎(chǔ)情況等。
面試原題描述
如圖,紅色矩形是網(wǎng)頁中的一個DOM元素(比如是個普通DIV)。
需求:當(dāng)用戶鼠標(biāo)在該DOM元素上移動時,判定光標(biāo)相對于灰色對角線所處位置狀態(tài)(左上、右下、剛好在線上)。
粗略解答思路
相信你一定已經(jīng)看懂是個啥需求,需要做些啥了吧?
所以不需要贅述了,直接上解法:?。?!
首先,我們需要確定判定方法,以及需要傳入的參數(shù)。
然后,再通過DOM行為監(jiān)聽、事件&DOM屬性讀取,得到參數(shù)具體數(shù)值,傳入上面實現(xiàn)的方法。
很簡單對不對?讓我想到了經(jīng)典的“怎么畫好一匹馬”。
別急,具體處理方式容我再慢慢道來。
一點面試的心得感受
被我面試時聊過這個問題的人,不上幾千肯定也過幾百了。
所以,技術(shù)問題之外,也會有一些心得感悟。
比如我經(jīng)常對新參加面試工作的同事說的一句話:“切記:面試不是拿你自己準(zhǔn)備好的、或者熟悉的問題,創(chuàng)造出一個不公平的溝通場景,然后再跟被面試者比誰更聰明;面試官的職責(zé)是通過針對特定話題的溝通,來檢驗其過往經(jīng)歷的真實性、判定這個人特定方向的能力邊界。”
如果一個被面試者,第一次遇到這個非純知識考查的怪異問題,還能做到冷靜思考、清晰表述思路,那么我們完全可以判定這個人的基本素質(zhì):臨場應(yīng)變、抽象變通都不錯。
如果接下來還能提供代碼實現(xiàn)過程的表述,那更是這個方向上,問題分析解決能力、編程經(jīng)驗豐富了。
能達到上述表現(xiàn)的,對心理抗壓、臨場應(yīng)變、相關(guān)技能儲備是個不小的挑戰(zhàn),往往是鳳毛麟角。
而在我面試他人的經(jīng)歷中,還有兩種非常有趣的極端情況會經(jīng)常遇到:
看完不假思索、或稍微思考一會,直接選擇放棄的。
缺乏思考或沒有清晰的思路,強拉硬扯一通,然后提供一些牽強附會的結(jié)論。
當(dāng)我作為面試官遇到上述極端情形時的感受往往是:
是不是沒太大必要繼續(xù)浪費時間了。
這個同學(xué)任用可一定得慎重。
當(dāng)然,感受歸感受,現(xiàn)實里面我并不會這么武斷的定下結(jié)論。此時需要再回顧一下前文加粗的那點感想。
如果一個人的臨場應(yīng)變能力不是非常優(yōu)秀,也不一定就是能力問題。
誰也難免會有緊張、腦筋卡殼的時候。我自己就經(jīng)常這樣啊 ----- 往往晚上睡覺時趟在床上,回想一天的過往,“嘿,我那個想法、那句話,簡直就是SB至極”。
所以遇到上述兩種極端情況,換到應(yīng)聘者角色又或者是這樣呢:
問我這些?簡直是羞辱,我不屑回答。
怎么辦,怎么辦,好緊張,可我不能不要面子?。骸鞍屠屠屠?..”
所以如果我作為面試官遇到不太能給出思路的同學(xué),會試圖引導(dǎo)一下,強調(diào)“面試不一定非得純問答題,也是個相互溝通、相互學(xué)習(xí)的過程,想到啥都可以說說看”。
而作為面試官通過進一步溝通,也可以更可靠、清晰的確認(rèn)一下對被面試者能力范圍的判定。
學(xué)霸式解題方法思路
如果面試中遇到數(shù)學(xué)基礎(chǔ)不錯的學(xué)霸,往往會直接甩出向量方案。
像下圖三種狀態(tài)代表性的點 P1、P2、P3,求其點坐標(biāo)到對角線的向量值,根據(jù)正、負(fù)、零自然也就映射到要判定的狀態(tài)了。
但是,像我這種連“向量:具有大小和方向的量”的基礎(chǔ)概念都忘光光的學(xué)渣,肯定不會啊。
所以引導(dǎo)他人解題時候,更是不敢聊向量這個話題了,我經(jīng)常用邏輯推理的方式。
邏輯推理式解題思路之一
畢竟是引導(dǎo)別人,我也要面子嘛:通常會先建議再想一想、確定一下參照坐標(biāo)系、畫一畫輔助線試試。
比如,我們假設(shè)任意光標(biāo)點為P1,DOM元素左下角為二維坐標(biāo)系原點P0呢?有沒有想到啥思路?
還沒有思路的話,將P1-P0連線呢?跟對角線比較是啥關(guān)系,能不能映射到題目需求狀態(tài)上?
對嘛,斜線P0-P1與底邊的夾角如果大于、等于、小于對角線與底邊或左邊的夾角,不就判定出來了。
不過要計算角的大小好像也會很麻煩(我三角函數(shù)都忘光光了,太難了、不會?。?...
其實,剛剛我們已經(jīng)不知不解決的假定了底邊是x軸、左邊是y軸(原點P0嚒 ?(′???`?)),也就形成了一個二維坐標(biāo)系。
在這個坐標(biāo)系里,P1到左邊的距離X、到底邊的距離Y,跟矩形寬度boxWidth、boxHeight的比例關(guān)系剛好也可以映射到題目需求的三個位置狀態(tài)上誒!!
即:
X/Y === boxWidth/boxHeight 那么點在對角線上。
X/Y < boxWidth/boxHeight 那么點在對角線左上。
X/Y > boxWidth/boxHeight 那么點在對角線右下。
到這里判定方法確定了,剩下就是怎么去獲取這些參數(shù)值了。
必要參數(shù)值獲取
現(xiàn)在我們需要獲取4個數(shù)值:X、Y、boxWidth、boxHeight。
我就知道,你一定會覺得很簡單,沒錯,這是算是基本JS API基礎(chǔ)了。
事件處理及對應(yīng)值獲取
回到題目“當(dāng)用戶鼠標(biāo)在該DOM元素上移動時”,不就是監(jiān)聽鼠標(biāo)事件、然后取相關(guān)對象的目標(biāo)屬性值么,這有啥難點?
我也一直這么認(rèn)為的,但經(jīng)過那么多次面試,發(fā)現(xiàn)竟然很多人都不知道(╮(╯▽╰)╭),能通過篩選的怎么也是有幾年前端工作經(jīng)驗的呢。
遇到過:“不知道”、 “onMouseover”、“onTouch”、“o(╯□╰)o”...
確定了事件監(jiān)聽方式,那么我們通過事件中的哪個對象啥屬性獲取X、Y呢?
曾經(jīng)收到過的答案們(只拿X值關(guān)聯(lián)屬性示例):不知道、div.x、event.x、evnet.left、event.offsetX、event.clientX、event.pageX、... ???
上面這些肯定有錯誤的或者存在問題的,聰明的你,一定想到了正確的方案了。
你拿到的值是相對哪個坐標(biāo)系的?如果得到的是 pageX值,是不是還得換算一下,又進一步依賴哪個屬性怎么獲???
DOM屬性讀取
X、Y坐標(biāo)值能取到了,那么boxWidth、boxHeight怎么取呢?
曾經(jīng)收到的答案們(只拿寬度值關(guān)聯(lián)屬性示例):不知道、div.width、div.style.width、div.contentWidth、div.getAttribute('xxx')、div.offsetWidth、div.outerWidth、div.innerWidth、div.getBoundingClientRect().width....
上面這些還是存在錯誤的,聰明的你,又一定想到了正確的方案了。~O(∩_∩)O~
延展討論
“既然聊到事件了,如果我頁面里有好多元素,還存在懶加載動態(tài)插入的,都想達成這個題目的需求,事件綁定有沒有一次綁定也都能生效的方案嘞?”、“是不是有個啥事件委托、事件代理?”
“事件可以自定義么?"
"如果我在JS代碼里悄悄的自動觸發(fā)一個元素的事件可以么,會不會有啥問題?”
“誒,上面你好像聊到了 div.style.width、div.offsetWidth,這倆貨有啥區(qū)別???”、“瀏覽器里是不是有個盒模型的說法?”
“如果鼠標(biāo)移動頻度很高,會不會有性能問題?”、“可以怎么優(yōu)化一下嗎?”。
“如果要在DOM元素里繪制這個斜對角線,該怎么畫?”
"你剛說用兩個DOM元素分別實現(xiàn)上下三角區(qū)域,再綁定onClick判斷?" “那這倆三角區(qū)域CSS咋寫出來?”
收個尾
今天先想到啥寫啥了,回頭再想到啥再補充。
可能有同學(xué)會非常納悶,“怎么會有這么個題目,前端工程師怎么可能用到?”。
首先這個問題,來自我11年前的一個真實項目經(jīng)歷中的產(chǎn)品需求:
如上圖:“當(dāng)某個WEB應(yīng)用啟用精簡排版模式時,將第二行中倆功能按鈕合并成第一行的那一個,按照點擊位置判定并執(zhí)行為獨立按鈕一樣的目標(biāo)行為?!?/p>
再后來,稍微了解了一點計算機圖形學(xué)三角剖分法、紋理貼片,我勒個乖乖,全是三角形,太嚇人了,果斷放棄。





