標籤:
來杭一周,收穫很多,成長很多。
周六在搞一個外掛程式的時候碰到需要動態添加虛擬元素的需求,搜了一下解決方案,有人用正則寫出了讀取虛擬元素的函數;我覺得倒是可以通過注入css rule的方式,來讓預留有某些類的標籤動態產生虛擬元素。
然後在google上搜到這樣一篇文章,講了一下之前沒瞭解到的api函數:addrule等,翻譯一下,分享一下好了。
原博文網址:http://davidwalsh.name/add-rules-stylesheets
譯文如下:
因為我們在開發中javascript使用的越來越多,所以我們總是想盡辦法想讓它更快。我們使用事件代理來監聽事件,使用函數節流來限制單位時間內函數的調用次數,使用loader方法來載入最需要的資源。這些方法都可以讓我們的頁面載入、渲染、執行的速度有一定的加快。本文要說另一種方法:通過動態添加刪除CSS樣式代替原有的尋找節點並修改來應用某些樣式。
我們可以選擇向頁面內的某條stylesheet中添加樣式。可以給<link>標籤或者<style>標籤添加ID,通過引用節點的sheet屬性來擷取CSSStyleSheet對象。頁面中的stylesheets可以使用document.styleSheets來擷取:
var sheets = document.styleSheets; // returns an Array-like StyleSheetList//返回一個類數組對象/*Returns: StyleSheetList {0: CSSStyleSheet, 1: CSSStyleSheet, 2: CSSStyleSheet, 3: CSSStyleSheet, 4: CSSStyleSheet, 5: CSSStyleSheet, 6: CSSStyleSheet, 7: CSSStyleSheet, 8: CSSStyleSheet, 9: CSSStyleSheet, 10: CSSStyleSheet, 11: CSSStyleSheet, 12: CSSStyleSheet, 13: CSSStyleSheet, 14: CSSStyleSheet, 15: CSSStyleSheet, length: 16, item: function}*/// Grab the first sheet, regardless of media//先不管第一個樣式的具體應用media(註:可能是print等)var sheet = document.styleSheets[0];
在我們選取link或者style標籤時,我們應該考慮被選中的樣式表標籤是否是應用於screen,而不是print等。CSSStyleSheet對象給我們提供了這樣的屬性:
// Get info about the first stylesheetconsole.log(document.styleSheets[0]);/*Returns: CSSStyleSheet cssRules: CSSRuleList disabled: false href: "http://davidwalsh.name/somesheet.css" media: MediaList ownerNode: link ownerRule: null parentStyleSheet: null rules: CSSRuleList title: null type: "text/css"*/// Get the media type//擷取media類型console.log(document.styleSheets[0].media.mediaText)/*Returns: "all" or "print" or whichever media is used for this stylesheet*/
當然除了上面的,還有別的方法可以擷取stylesheet對象。
有些情況下,可能建立一個style節點來承裝新添加的style rule。方法很簡單:
var sheet = (function() { // Create the <style> tag var style = document.createElement("style"); // Add a media (and/or media query) here if you‘d like! // style.setAttribute("media", "screen") // style.setAttribute("media", "only screen and (max-width : 1024px)") // WebKit hack :( //webkit核心瀏覽器的hack: style.appendChild(document.createTextNode("")); // Add the <style> element to the page 插入頁面 document.head.appendChild(style); return style.sheet;})();
請留意上面第三條語句是為webkit瀏覽器添加的hack。
- 插入規則 insertRule(styles,[index])
Stylesheets對象提供了insertRule(譯者註:IE8及以下不相容,具體參考連結http://www.quirksmode.org/dom/w3c_css.html )方法。insertRule函數要求傳入css樣式風格的str作為參數。
具體調用方法:
sheet.insertRule("header { float: left; opacity: 0.8; }", 1);
(譯者註:傳入的樣式str的格式要求很多。就我目前發現的:1.{}兩個花括弧和前後最好都有一個空格 2.如果是webkit核心,函數在解析帶有-moz-首碼的樣式規則時會拋err)
這種方法看上去有點醜,但是確實有用。第二個參數Index,表示我們將在樣式內部的哪一條插入新樣式css rule,這就可以協助我們實現原有樣式的覆蓋。預設index取值是-1(譯者註:但是輸入-1在chrome 41下拋了err,提示參數不能小於0,這裡值得在研究一下),表示預設在樣式最後追加。如果想強制覆蓋,可以使用!important,來避免插入次序引起其他問題。
- 添加規則(非標準函數) addRule(selector,styles,index)
CSSStyleSheet對象有一個非標準函數addRule,和insertRule相比,它更像js api的調用風格,無需自己注意插入的樣式字串的格式。addRule方法接受三個參數,分別是選取器selector,樣式字串"color:red;font-size:12px",和插入次序index。
sheet.addRule("#myList li", "float: left; background: red !important;", 1);
方法有傳回值,為-1。但是沒有什麼具體含義。
這種方式可以快速高效的改變頁面上節點的已有樣式。
因為上面提到兩個函數都不是常見api函數,所以需要做瀏覽器安全色性處理。
function addCSSRule(sheet, selector, rules, index) { if("insertRule" in sheet) { sheet.insertRule(selector + "{" + rules + "}", index); } else if("addRule" in sheet) { sheet.addRule(selector, rules, index); }}// Use it!addCSSRule(document.styleSheets[0], "header", "float: left");
這種方法可以應用於所有進階的瀏覽器,如果還是有擔心的話,可以在調用時使用try-catch結構。
如果你需要插入media-queries的css樣式規則,你只能使用第一個insertRule方法。
sheet.insertRule("@media only screen and (max-width : 1140px) { header { display: none; } }");
IE不支援insertRule函數,所以另一種方法是建立style標籤節點,通過寫入的方式來注入樣式規則。
動態添加樣式規則是有效且容易的。在下一個應用裡嘗試一下吧,你會發現這個真的很好用~
譯文結束
[javascript][翻譯]使用javascript添加css rule