blob: 7e584a3dd677c04d2e51679c1eec7e1370bbbfb2 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
---
title: DOM 中的空白字元
slug: Web/API/Document_Object_Model/Whitespace
tags:
- DOM
- 所有類別
translation_of: Web/API/Document_Object_Model/Whitespace
---
<h4 id=".E5.95.8F.E9.A1.8C.E8.AA.AA.E6.98.8E" name=".E5.95.8F.E9.A1.8C.E8.AA.AA.E6.98.8E">問題說明</h4>
<p><a href="zh_tw/DOM">DOM</a> 裡的空白字元會讓處理節點結構時增加不少麻煩。Mozilla 相關軟體中,原始文件裡所有空白字元都會在 DOM 中出現(不包括標籤內含的空白字元)。這樣的處理方式有其必要,一方面編輯器中可逕行排列文字、二方面 <a href="zh_tw/CSS">CSS</a> 裡的 <code>white-space: pre</code> 也才能發揮作用。 如此一來就表示:</p>
<ul>
<li>有些空白字元會自成一個文字節點。</li>
<li>有些空白字元會與其他字串合成一個文字節點。</li>
</ul>
<p>換句話說,下面這段程式碼的 DOM 節點結構就如附圖一般,其中「\n」代表換行字元:</p>
<pre class="eval"><!-- My document -->
<html>
<head>
<title>My Document</title>
</head>
<body>
<h1>Header</h1>
<p>
Paragraph
</p>
</body>
</html>
</pre>
<p><img height="306" src="https://mdn.mozillademos.org/files/854/whitespace_tree.png" width="618"></p>
<p>這麼一來,要使用 DOM 遊走於節點結構間又不想要無用的空白字元時,會有點困難。</p>
<h4 id=".E5.8A.A9.E4.BD.A0.E4.B8.80.E8.87.82.E4.B9.8B.E5.8A.9B" name=".E5.8A.A9.E4.BD.A0.E4.B8.80.E8.87.82.E4.B9.8B.E5.8A.9B">助你一臂之力</h4>
<p>以下的 JavaScript 程式碼定義了許多函式,讓你處理 DOM 中的空白字元時能輕鬆點:</p>
<pre>/**
* 以下所謂的「空白字元」代表:
* "\t" TAB \u0009 (移位字元)
* "\n" LF \u000A (換行字元)
* "\r" CR \u000D (歸位字元)
* " " SPC \u0020 (真正的空白)
*
* 不包括 JavaScript 的「\s」,因為那代表如不斷行字元等其他字元。
*/
/**
* 測知某節點的文字內容是否全為空白。
*
* @參數 nod |CharacterData| 類的節點(如 |Text|、|Comment| 或 |CDATASection|)。
* @傳回值 若 |nod| 的文字內容全為空白則傳回 true,否則傳回 false。
*/
function is_all_ws( nod )
{
// Use ECMA-262 Edition 3 String and RegExp features
return !(/[^\t\n\r ]/.test(nod.data));
}
/**
* 測知是否該略過某節點。
*
* @參數 nod DOM1 |Node| 物件
* @傳回值 若 |Text| 節點內僅有空白字元或為 |Comment| 節點時,傳回 true,
* 否則傳回 false。
*/
function is_ignorable( nod )
{
return ( nod.nodeType == 8) || // 註解節點
( (nod.nodeType == 3) && is_all_ws(nod) ); // 僅含空白字元的文字節點
}
/**
* 此為會跳過空白字元節點及註解節點的 |previousSibling| 函式
* ( |previousSibling| 是 DOM 節點的特性值,為該節點的前一個節點。)
*
* @參數 sib 節點。
* @傳回值 有兩種可能:
* 1) |sib| 的前一個「非空白、非註解」節點(由 |is_ignorable| 測知。)
* 2) 若該節點前無任何此類節點,則傳回 null。
*/
function node_before( sib )
{
while ((sib = sib.previousSibling)) {
if (!is_ignorable(sib)) return sib;
}
return null;
}
/**
* 此為會跳過空白字元節點及註解節點的 |nextSibling| 函式
*
* @參數 sib 節點。
* @傳回值 有兩種可能:
* 1) |sib| 的下一個「非空白、非註解」節點。
* 2) 若該節點後無任何此類節點,則傳回 null。
*/
function node_after( sib )
{
while ((sib = sib.nextSibling)) {
if (!is_ignorable(sib)) return sib;
}
return null;
}
/**
* 此為會跳過空白字元節點及註解節點的 |lastChild| 函式
* ( lastChild| 是 DOM 節點的特性值,為該節點之中最後一個子節點。)
*
* @參數 par 節點。
* @傳回值 有兩種可能:
* 1) |par| 中最後一個「非空白、非註解」節點。
* 2) 若該節點中無任何此類子節點,則傳回 null。
*/
function last_child( par )
{
var res=par.lastChild;
while (res) {
if (!is_ignorable(res)) return res;
res = res.previousSibling;
}
return null;
}
/**
* 此為會跳過空白字元節點及註解節點的 |firstChild| 函式
*
* @參數 par 節點。
* @傳回值 有兩種可能:
* 1) |par| 中第一個「非空白、非註解」節點。
* 2) 若該節點中無任何此類子節點,則傳回 null。
*/
function first_child( par )
{
var res=par.firstChild;
while (res) {
if (!is_ignorable(res)) return res;
res = res.nextSibling;
}
return null;
}
/**
* 此為傳回值不包含文字節點資料的首尾所有空白字元、
* 並將兩個以上的空白字元縮減為一個的 |data| 函式。
*( data 是 DOM 文字節點的特性值,為該文字節點中的資料。)
*
* @參數 txt 欲傳回其中資料的文字節點
* @傳回值 文字節點的內容,其中空白字元已依前述方式處理。
*/
function data_of( txt )
{
var data = txt.data;
// Use ECMA-262 Edition 3 String and RegExp features
data = data.replace(/[\t\n\r ]+/g, " ");
if (data.charAt(0) == " ")
data = data.substring(1, data.length);
if (data.charAt(data.length - 1) == " ")
data = data.substring(0, data.length - 1);
return data;
}
</pre>
<h4 id=".E7.AF.84.E4.BE.8B" name=".E7.AF.84.E4.BE.8B">範例</h4>
<p>以下示範上述函式的應用方法,在節點結構中依序檢查、找出內容為「<code>"This is the third paragraph"</code>」的節點,並修改其 class 屬性及文字內容。</p>
<pre>var cur = first_child(document.getElementById("test"));
while (cur)
{
if (data_of(cur.firstChild) == "This is the third paragraph.")
{
cur.className = "magic";
cur.firstChild.data = "This is the magic paragraph.";
}
cur = node_after(cur);
}
</pre>
<div class="originaldocinfo">
<h4 id=".E5.8E.9F.E6.96.87.E8.B3.87.E8.A8.8A" name=".E5.8E.9F.E6.96.87.E8.B3.87.E8.A8.8A">原文資訊</h4>
<ul>
<li>作者:<a class="external" href="http://dbaron.org">L. David Baron</a></li>
<li>最後更新:January 1, 2003</li>
<li>版權資訊:© 1998-2005 by individual mozilla.org contributors; 內容部份以 <a class="external" href="http://www.mozilla.org/foundation/licensing/website-content.html">創意公用</a>方式授權。</li>
</ul>
</div>
|