一、題目
用JS代碼求出頁面上一個元素的最終的background-color,不考慮IE瀏覽器,不考慮元素float情況。(題目copy自網上)
二、題目解析
1.考察底層JavaScript基礎
前端開發,日常最常接觸的就是頁面樣式的編寫。而擺脫jQuery等工具庫,用原生js獲取樣式,是每個前端程序猿進階階段必須掌握的技能。
2.考察面試者的思維縝密程度和開發經驗
如果認為單單求元素計算后的樣式,就有點too young了。頁面的樣式的復雜,永遠是最虐心的。就算前端有多牛逼,一聽到兼容IE6,論誰都會心塞😓。所以還要考慮特殊的情況:display,opacity,visibility
的取值。
三、理論基礎
1. 內聯樣式
內聯樣式可以通過元素的style屬性獲取,如果style屬性有background-color值,則可以直接獲取出來 (暫不考慮!important) 。
2. 外聯的層疊樣式
DOM2樣式規范在document.defaultView
中包含了一個getComputedStyle()
方法。該方法返回一個只讀的CSSStyleDeclaration對象,其中包含特定元素的所有計算樣式。
四、解題
4.1 將所有工具方法封裝在WDS(wall dom script)命名空間中
(function(WDS, undefined){
// 封裝代碼...
})(window.WDS || (window.WDS = {}));
代碼封裝在命名空間里,不會造成無意間的代碼污染。
4.2 工具方法camelize
// 字符串轉換為駝峰寫法
function camelize(str) {
return str.replace(/-(\w)/g, function (strMatch, p1){
return p1.toUpperCase();
});
}
該方法是為了方便后續getStyle()
方法的編寫,而獨立出來的。
作用是將連字符類的css屬性值,轉換成駝峰寫法。
例如:將background-color轉換為backgroundColor
4.3 獲取特定元素的計算樣式
// 獲取元素計算后的樣式
function getStyle(elem, property){
if(!elem || !property){
return false;
}
var value = elem.style[camelize(property)], // 先獲取是否有內聯樣式
css; // 獲取的所有計算樣式
// 無內聯樣式,則獲取層疊樣式表計算后的樣式
if(!value){
if(document.defaultView && document.defaultView.getComputedStyle){
css = document.defaultView.getComputedStyle(elem, null);
value = css ? css.getPropertyValue(property) : null;
}
}
return value;
}
做到這一步,第一個考察點基本就滿足了。也能獲知面試者是否具備足夠扎實的js基礎。
另外,像安全保護性的判斷if(!elem || !property)
和功能嗅探if(document.defaultView && document.defaultView.getComputedStyle)
,都能很好地體現開發者的代碼邏輯和開發經驗。
4.4 排除特殊情況
// 檢測獲取的背景色是否有效
function checkBgValue(elem){
var value = getStyle(elem, 'background-color'),
hasColor = value ? true : false; // 是否有顏色
// 排除特殊情況
if(value == "transparent" || value == "rgba(0, 0, 0, 0)"){
// 未設置background-color,或者設置為跟隨父節點
hasColor = false;
}else if(getStyle(elem, 'opacity') == "0"){
// dom節點透明度為全透明
hasColor = false;
}else if(getStyle(elem, 'visibility') == "hidden"){
// dom節點不可見
hasColor = false;
}else if(getStyle(elem, 'display') == "none"){
// dom節點不可見
hasColor = false;
}
return hasColor;
}
4.5 獲取div在頁面最終顯示的顏色
// 獲取div最終顯示的顏色
function getRealBg(elem){
if(checkBgValue(elem)){
return getStyle(elem, 'background-color');
}else if(elem != document.documentElement){
return getRealBg(elem.parentNode);
}
return '';
}
獲取樣式值采用遞歸方式處理。
如果能順利獲取到元素樣式,且不觸發4.4 排除特殊情況
中的一種,則直接返回結果。
觸發了特殊情況,則需要查找父節點以及更上層的節點的樣式,來獲取肉眼能看到,顯示在頁面上的background-color值。
在向上回溯的過程中,如果已經回溯到html
根節點,則可以停止回溯。所以加了判斷else if(elem != document.documentElement)
五、遺漏的大boss
5.1 大boss !important
如果亂用 !important
,對大型項目的維護和開發,絕對是一場噩夢。因為優先級規則的計算,!important
永遠處在食物鏈的最頂層。
當前題目不考慮這種情況,也是我的偷懶😆。確實很棘手,就不寫這個邏輯分支的代碼了。這里提醒一下~
5.2 大boss 父節點及根節點設置了不可見css屬性
只要設置該css語句:html {display:none;}
,頁面所有元素立刻消失不見。而任意特定元素的上級節點,只要設置了 opacity,display,visibility
,判斷邏輯瞬間變得復雜起來。所以,這個渾水我也不趟 O(∩_∩)O哈哈~
六、改進的點
其實特殊情況排除的判斷,我偷懶沒做到最好——rgb顏色值和特定顏色值(比如red)沒有進行統一的轉換,只是加了生硬的判斷if(value == "transparent" || value == "rgba(0, 0, 0, 0)")
。
有興趣的可以搜索下顏色值轉換的js方法,這里我就不寫了。
七、源碼和demo
源碼地址:https://github.com/wall-wxk/blogDemo/blob/master/2017/02/05/getStyle.html
demo:https://wall-wxk.github.io/blogDemo/2017/02/05/getStyle.html
補充
謝謝@煙雨霧嵐 的提醒的新思路:canvas截圖+Js獲取圖片某點顏色,這樣可以完美解決所有的問題。
閱讀原文:http://www.jianshu.com/p/e94b5779f998
文章列表