aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/api/document_object_model/whitespace/index.html
blob: 929b77472ac181174f2e5df70ccbe81a39efbbb4 (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
184
185
186
187
188
189
190
191
192
193
194
---
title: DOM中的空白符
slug: Web/API/Document_Object_Model/Whitespace
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>换句话说,下面这段 HTML 代码对应的 DOM 节点结构会如附图所示,其中“\n”代表换行符:</p>

<pre class="eval">&lt;!-- My document --&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;My Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Header&lt;/h1&gt;
  &lt;p&gt;
    Paragraph
  &lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>

<p><img src="https://mdn.mozillademos.org/files/854/whitespace_tree.png" style="height: 306px; width: 618px;"></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) &amp;&amp; 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>

<h2 id="Example" name="Example">示例</h2>

<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>

<p> </p>