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





