文章目录
  1. 1. UI层的松耦合
    1. 1.1. 1. 什么是松耦合
      1. 1.1.1. 1.1 什么是耦合:
      2. 1.1.2. 1.2 什么时候才能称作松耦合:
    2. 1.2. 2. 将JavaScript从CSS中抽离
    3. 1.3. 3. 将CSS从JavaScript中抽离
      1. 1.3.1. JavaScript改CSS方式:
        1. 1.3.1.1. 方式一(不好):style属性
        2. 1.3.1.2. 方式二(不好):cssText属性
        3. 1.3.1.3. 方式三(最佳):操作className
    4. 1.4. 4.将JavaScript从HTML中抽离
      1. 1.4.1. 绑定事件方式
        1. 1.4.1.1. 方式一 (不好):使用on属性
        2. 1.4.1.2. 方式二(最佳): 通过script标签来引用
        3. 1.4.1.3. 方式三 (不好):HTML中内联的脚本代码

这是一篇读书笔记,对书中的描述进行精简,归纳,总结,
有时也会自己写一些例子,感想和扩展 O(∩_∩)O~


UI层的松耦合

WEB开发中 UI由三个彼此隔离又相互作用的层定义(HTML,CSS,JavaScript)。

在实际场景中,css和JavaScript是同等重要的,两者更像是兄弟关系并非依赖关系(javascript依赖css)。
一个页面很可能只有HTML和CSS而没有JavaScript,
或………………只有HTML和JavaScript而没有CSS。

在所有Web UI中,JavaScript的正确运行不应依赖CSS—在缺少CSS情况下也要能够正确运行,尽管两者之间可能有互动。

1. 什么是松耦合

1.1 什么是耦合:

如果两个组件耦合太紧,则说明一个组件和另一个组件直接相关,
如果修改一个组件的逻辑,那么另外一个组件的逻辑也需修改。

耦合的例子:有一个贯穿整个站点的css类叫做error,被嵌入到HTML中。如果有一天你要改error这个名字为warning,不仅要修改CSS还要修改用到这个类名的HTML,HTML和CSS紧耦合在一起。

1.2 什么时候才能称作松耦合:

当你能够做到修改一个组件而不需要更改其他组件时,你就做到了松耦合。

松耦合是易于调试的,这对于代码的可维护性来说至关重要。修改某部分代码是不会破坏其他人的代码,那便是极好的 0.0’

在一起工作的组件无法达到“无耦合”,我们的目标是确保对一个组件的修改不会经常性地影响其他部分。

2. 将JavaScript从CSS中抽离

IE8和更早版本的浏览器中有一个特性让人爱少恨多,即CSS表达式(CSS expression)。
CSS表达式允许你将JavaScript直接插入到CSS中,可以在CSS代码中直接执行运算或其他操作。

设置元素宽度以匹配浏览器宽度

1
2
3
4
/* 不好的写法 */
.box{
width:expression(document.body.offsetWidth + "px");
}

CSS表达式包裹在一个特殊的expression()函数中,可以给它传入任意JavaScript代码。
浏览器会以高频率重复计算CSS表达式,严重影响了性能。且难以维护。
IE9不再支持CSS表达式,老版本IE依然可以运行CSS表达式。
有人会用CSS表达式来让低版本浏览器里也达到和高级浏览器一致的表现,但尽量避免使用,以避免浪费不必要的时间精力。

总结:避免使用CSS表达式

3. 将CSS从JavaScript中抽离

CSS和JavaScript互相协作的很不错,所以我们经常将样式数据和JavaScript混写在一起。

JavaScript改CSS方式:

方式一(不好):style属性

直接修改DOM元素的style属性。

style属性是一个对象,包含了可以读取和修改的CSS属性。
如:修改元素文本颜色

1
2
/* 不好的写法 */
element.style.color = "red";

评价:这种写法经常看到,但是这种写法是有问题的。
缺点:当出现样式问题,通常首先去查找CSS,而非JavaScript,浪费时间。
例外:有一种使用style属性的情形是可以接受的:
当你需要给页面中的元素作定位,使其相对于另外一个元素或整个页面重新定位。这种计算在CSS中无法完成,
此时可以使用style.top、style.left、style.bottom、style.right 来对元素作正确定位。
在CSS中定义这个元素的默认属性,而在JavaScript中修改这些默认值。

方式二(不好):cssText属性

给cssText属性赋值整个CSS字符串

1
2
/* 不好的写法 */
element.style.cssText = "color: red; left: 10px; top: 100px; visibility: hidden";

评价:这种写法是一次性设置多个CSS属性的一种快捷方法,同样有问题。
缺点:比如设置单个属性时:将样式信息写入JavaScript带来了可维护性问题。

方式三(最佳):操作className

操作CSS的className

例:在页面中显示一个对话框,css中的样式定义像下面这样

1
2
3
4
5
6
.reveal{
color: red;
left: 10px;
top: 100px;
visibility: visible;
}

在JavaScript中像这样将样式添加至元素。

1
2
/* 好的写法 - 原生方法 */
element.className += " reveal";
1
2
/* 好的写法 - HTML5 */
element.classList.add("reveal");
1
2
/* 好的写法 - YUI */
Y.one(element).addClass("reveal");
1
2
/* 好的写法 - jQuery */
$(element).addClass("reveal");
1
2
/* 好的写法 - Dojo */
dojo.addClass(element, "reveal");

评价:JavaScript可以随意添加删除元素的className,而className定义的样式则在CSS代码中。
CSS样式随时可以修改,而不必更新JavaScript。
优点:JavaScript未直接操作样式,保持了和CSS的松耦合。

4.将JavaScript从HTML中抽离

很多人学习JavaScript之初所做的第一件事是,将脚本嵌入HTML中来运行。

绑定事件方式

方式一 (不好):使用on属性

使用on属性( 比如onclick )绑定一个事件处理程序

1
2
<!-- 不好的写法 -->
<button onclick="doSomething()" id="action-btn">Click Me</button>

评价:此写法2000年时非常流行,尽管这种代码多数场景下是正常工作的,但却是两个UI层(HTML和JavaScript)的深耦合,这种写法有一些问题
缺点

  1. 点击事件发生时,doSomething()函数必须存在,否则会报JavaScript错误,页面或弹出错误信息或点击事件不会有任何响应。
  2. 如果修改了doSomething()的函数名或如果此时点击按钮调用了其他函数,需要同时修改JavaScript和HTML代码。给维护带来了困难,这是典型的紧耦合的代码。

方式二(最佳): 通过script标签来引用

绝大多数(并非所有的)JavaScript代码包含在外部文件中,并在页面中通过script标签来引用。
对于支持2级DOM模型的浏览器来说,用下代码可完成上面例子中的功能:

1
2
3
4
5
function doSomething(){
//代码
}
var btn = document.getElementById("action-btn");
btn.addEventListener("click", doSomething, false);

关于addEventListener()函数
IE8及其更早的版本不支持addEventListener()函数,因此需要一个标准的函数将这些差异性做封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
* 这个函数可以做到在各种浏览器中给一个元素添加事件处理程序
* 甚至可以降级到支持给0级DOM模型对象的on属性赋值处理程序
* (只有在非常古老的浏览器),比如Netscape4中,才会执行这一步,
* 因此这段代码可以在所有情形下都正常工作)
*/
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;
}
}

我们常常像下面这样来使用这个方法

1
2
3
4
5
function doSomething(){
//代码
}
var btn = document.getElementById("action-btn");
addListener(btn, "click", doSomething);

如果你用了 JavaScript 类库,可以使用类库提供的方法来给元素挂载事件处理程序
这里给出一些流行类库中的实例代码。

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

评价:优势在于,函数doSomething()的定义和事件处理程序绑定都是在一个文件中完成的。如果函数名称需要修改,则只需修改一个文件;
如果点击事件发生时想额外做些动作,也只需在一处做修改。
优点:不需同时修改多个文件,可维护性提高,实现了松耦合。

方式三 (不好):HTML中内联的脚本代码

在HTML中使用<script>标签,标签内包含内联的脚本代码。

1
2
3
4
<!-- 不好的写法 -->
<script>
doSomething();
</script>

评价:最好将所有JavaScript代码都放入外置文件中,以确保在HTML代码中不会有内联的JavaScript代码,利于调试。
缺点:不利于确信(而非猜测)从何下手调试bug

文章目录
  1. 1. UI层的松耦合
    1. 1.1. 1. 什么是松耦合
      1. 1.1.1. 1.1 什么是耦合:
      2. 1.1.2. 1.2 什么时候才能称作松耦合:
    2. 1.2. 2. 将JavaScript从CSS中抽离
    3. 1.3. 3. 将CSS从JavaScript中抽离
      1. 1.3.1. JavaScript改CSS方式:
        1. 1.3.1.1. 方式一(不好):style属性
        2. 1.3.1.2. 方式二(不好):cssText属性
        3. 1.3.1.3. 方式三(最佳):操作className
    4. 1.4. 4.将JavaScript从HTML中抽离
      1. 1.4.1. 绑定事件方式
        1. 1.4.1.1. 方式一 (不好):使用on属性
        2. 1.4.1.2. 方式二(最佳): 通过script标签来引用
        3. 1.4.1.3. 方式三 (不好):HTML中内联的脚本代码