《編寫可維護的JavaScript》讀書筆記第5章:UI層的鬆耦合

將 JavaScript 從 CSS 中抽離

不要使用 IE 8 及更早版本支持的一個特性:CSS 表達式。

/* 不好的寫法 */
.box {
     expression(document.body.offsetWidth + "px");
}

將 CSS 從 JavaScript 抽離

// 不好的寫法
element.style.color = "red";

將 CSS 從 JavaScript 中抽離,需要把所有的樣式信息都放在 CSS 裏。這樣 JavaScript 只需要操作 CSS 的 className。

// 好的寫法- 原生代碼
element.className += " reveal";
// 好的寫法- HTML5
element.classList.add("reveal");
// 好的寫法 - YUI
Y.one(element).addClass("reveal");
// 好的寫法 - jQuery
$(element).addClass("reveal");
// 好的寫法 - dojo
dojo.addClass(element, "reveal");

將 JavaScript 從 HTML 中抽離

<!-- 不好的寫法 -->
<button  id="action-btn">Click Me</button>

絕大多數(並非所有的) JavaScript 代碼都應當包含在外部文件中,並在頁面中通過 <script> 標籤來引用。在 HTML 中,也不應當直接給 on 屬性掛載事件處理程序。對於支持 2 級 DOM 模型的瀏覽器來說,可以這樣寫:

function doSomething() {
    // 代碼
} 
var btn = document.getElementById("action-btn");
btn.addEventListener("click", doSomething, false);

爲了兼容不支持 addEventListener() 函數的IE8 及其更早版本,需要一個函數封裝差異:

function addListener(target, type, handler) {
   if (target.addEventListener) {
       target.addEventListener(type, handler, false);
   } else if (target.attachEvent) {
       target.attachEvent("on" + type, handler);
   } else {
      target["on" + type] = handler;
   }    
} 
function doSomething() {
    // 代碼
}
var btn = document.getElementById("action-btn");
addListener(btn, "click", doSomething);

使用 JavaScript 類庫:

// YUI
Y.one("#action-btn").on("click", doSomething);
// jQuery
$("#action-btn").on("click", doSomething);
// dojo
var btn = dojo.byId("action-btn");
dojo.connect(btn, "click", doSomething);

最好將所有的 JavaScript 代碼都放到外部文件中,這樣做的原因是出於緊急調試的考慮。當 JavaScript 報錯,你的下意識的行爲應當是去 JavaScript 文件中查找原因。如果在 HTML 中包含 JavaScript 代碼,則會阻斷你的工作流。

將 HTML 從 JavaScript 中抽離

// 不好的寫法
var div = document.getElementById("my-div");
div.innerHTML = "Error

Invalid e-mail address.

";

方法 1:從服務器加載

function loadDialog(name, oncomplete) {
    varxhr = new XMLHttpRequest();
    xhr.open("get", "/js/dialog/" + name, true);
    
    xhr.onreadystatechange = function() {
        if (xhr.readystate == 4 && xhr.status == 200) {
            var div = document.getElementById("dlg-holder");
            div.innerHTML = xhr.responseText;
            oncomplete);
        } else {
            // 處理錯誤
        }
    };
    xhr.send(null);
}

使用 JavaScript 類庫:

// YUI
function loadDialog(name, oncomplete) {
    Y.one("#dlg-holder").load("/js/dialog/" + name, oncomplete);
}
// jQuery
function loadDialog(name, oncomplete) {
    $("#dlg-holder").load("/js/dialog/" + name, oncomplete);
}

出於性能的原因,可以考慮採用客戶端模板。

方法 2:簡單客戶端模板

一段數據項模板:

<li><a href="%s">%s</li>

和一個格式化函數:

function sprintf(text) {
    var i=1, args=arguments; 
    return text.replace(/%s/g, function() {
       return (i < args.length) ? args[i++] : "";
    });
}
// 用法
var result = sprintf(templateText, "/item/4", "Fourth item");

模板通過兩種方法存放在 HTML 頁面裏。

1) 在 HTML 註釋中包含模板文件

<ul id="mylist"><!--<li id="item%s"><a href="%s">%s</li>-->
    <li><a href="/item/1">First item</li> 
    <li><a href="/item/2">Second item</li>
    <li><a href="/item/3">Third item</li>
</ul>
function addItem(url, text) {
    var mylist = document.getElementById("mylist"),
        templateText = mylist.firstChild.nodeValue,
        result = sprintf(templateText, url, text);
        
   div.innerHTML = result;
    mylist.insertAdjacentHTML("beforeend", result);    
} 

// 用法 
addItem("/item/4", "Fourth item");

2) 在 <script> 中包含模板文件

<script type="text/x-my-template" id="list-item">
   <li><a href="%s">%s</li>
</script>
function addItem(url, text) {
    var mylist = document.getElementById("mylist"),
        script = document.getElementById("list-item");
        templateText = script.text,
        result = sprintf(templateText, url, text),
        div = document.createElement("div");
       
    div.innerHTML = result.replace(/^\s*/, ""); // 去除前導空白
    mylist.appendChild(div.firstChild);    
} 

// 用法 
addItem("/item/4", "Fourth item");

方法 3:複雜客戶端模板

考慮使用諸如 Handlebars(http://handlebarsjs.com)所提供的解決方案。

<script type="text/x-handlebars-template" id="list-item">
    <li><a href="`url`">`text`</li>
</script>
function addItem(url, text) {
    var mylist = document.getElementById("mylist"),
        script = document.getElementById("list-item");
        templateText = script.text,
        template = Handlebars.compile(templateText),
        div = document.createElement("div"),
        result;
        
    result = template({
        text: text,
        url: url
    });
       
    div.innerHTML = result;
     mylist.appendChild(div.firstChild);    
} 



// 用法 
addItem("/item/4", "Fourth item");
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章