-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy path14_dom.html
More file actions
574 lines (395 loc) · 110 KB
/
14_dom.html
File metadata and controls
574 lines (395 loc) · 110 KB
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
<!doctype html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DOM یا مدل شیء سند :: Eloquent JavaScript</title>
<link rel=stylesheet href="js/node_modules/codemirror/lib/codemirror.css">
<script src="js/acorn_codemirror.js"></script>
<link rel=stylesheet href="css/ejs.css">
<script src="js/sandbox.js"></script>
<script src="js/ejs.js"></script><script>var chapNum = 14;</script><script>var clicky_site_ids = clicky_site_ids || []; clicky_site_ids.push(101171577);</script>
<script async src="//static.getclicky.com/js"></script>
</head>
<article>
<nav><a href="13_browser.html" title="previous chapter">◀</a> <a href="index.html" title="cover">◆</a> <a href="15_event.html" title="next chapter">▶</a></nav>
<h1><span class=chap_num>فصل 14</span>DOM یا مدل شیء سند</h1>
<blockquote>
<p><a class="p_ident" id="p_2jmj7l5rSw" href="#p_2jmj7l5rSw" tabindex="-1" role="presentation"></a>چه بد! یک داستان تکراری! وقتی کار ساخت خانه را تمام میکنی، متوجه میشوی که چیزی یاد گرفتی که میبایست پیش از شروع کار میدانستی.</p>
<footer>فردریش نیچه, <cite>فراسوی نیک و بد</cite></footer>
</blockquote><figure class="chapter framed"><img src="img/chapter_picture_14.jpg" alt="Picture of a tree with letters and scripts hanging from its branches"></figure>
<p><a class="p_ident" id="p_n3OM6EV/KR" href="#p_n3OM6EV/KR" tabindex="-1" role="presentation"></a>وقتی یک صفحهی وب را در مرورگرتان باز میکنید، مرورگر متن HTML صفحه را گرفته و آن را تفسیر میکند، بسیار شبیه به آنچه تجزیهگر ما برای تجزیهی برنامهها در <a href="12_language.html#parsing">فصل 12</a> انجام می داد. مرورگر یک مدل از ساختار سند می سازد و از آن برای نمایش سند روی صفحهی نمایش استفاده میکند.</p>
<p><a class="p_ident" id="p_ntA3uElDxM" href="#p_ntA3uElDxM" tabindex="-1" role="presentation"></a>این نمایش از سند، یکی از ابزارهایی است که یک برنامهی جاوااسکریپت در جعبهی شنی (sandbox) خود به آن دسترسی دارد. یک ساختار داده که میتواند خوانده شود یا تغییر یابد؛ ساختار دادهای <em>زنده</em>: زمانی که تغییری در آن رخ میدهد، صفحهای که در مانیتور نمایش داده می شود نیز بهروز میشود تا تغییرات را منعکس کند.</p>
<h2><a class="h_ident" id="h_B+jPe26cOz" href="#h_B+jPe26cOz" tabindex="-1" role="presentation"></a>ساختار سند</h2>
<p>میتوانید یک سند HTML را به عنوان مجموعهای از مستطیلهای تودرتو در نظر بگیرید. برچسبهایی مثل <bdo><code><body></code></bdo> و <bdo><code></body></code></bdo>، دیگر برچسبها را در بر می گیرند، که خود نیز حاوی برچسبهای دیگر یا متن میباشند. به عنوان مثال، سندی از <a href="13_browser.html">فصل قبل</a> را مشاهده میکنید:</p>
<pre class="snippet cm-s-default" data-language="text/html" data-sandbox="homepage"><a class="c_ident" id="c_4wSSl86LKl" href="#c_4wSSl86LKl" tabindex="-1" role="presentation"></a><span class="cm-meta"><!doctype html></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">html</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">head</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">title</span><span class="cm-tag cm-bracket">></span>My home page<span class="cm-tag cm-bracket"></</span><span class="cm-tag">title</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">head</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">body</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">h1</span><span class="cm-tag cm-bracket">></span>My home page<span class="cm-tag cm-bracket"></</span><span class="cm-tag">h1</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>Hello, I am Marijn and this is my home page.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>I also wrote a book! Read it
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">a</span> <span class="cm-attribute">href</span>=<span class="cm-string">"http://eloquentjavascript.net"</span><span class="cm-tag cm-bracket">></span>here<span class="cm-tag cm-bracket"></</span><span class="cm-tag">a</span><span class="cm-tag cm-bracket">></span>.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">body</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">html</span><span class="cm-tag cm-bracket">></span></pre>
<p>ساختار این صفحه به شکل زیر است:</p><figure><img src="img/html-boxes.svg" alt="HTML document as nested boxes"></figure>
<p><a class="p_ident" id="p_pjDAG8c7k9" href="#p_pjDAG8c7k9" tabindex="-1" role="presentation"></a>ساختار دادهای که مرورگر برای نمایش این سند استفاده میکند از این شکل پیروی می کند. برای هر مستطیل، یک شیء وجود دارد، که میتوانیم با آن ارتباط برقرار کرده تا چیزهایی مثل برچسب HTML آن یا برچسبها و متونی که در بر دارد را بدست بیاوریم. این طرز نمایش را <em>مدل شیء سند</em> یا به اختصار DOM می گویند.</p>
<p>متغیر سراسری <code>document</code> امکان دسترسی به این اشیاء را فراهم می سازد. خاصیت <code>documentElement</code> آن به شیئی ارجاع میدهد که نمایانگر برچسب <bdo><code><html></code></bdo> است. چون هر سند HTML دارای یک سرصفحه و یک بدنه میباشد ، در نتیجه دارای خاصیتهای <code>head</code> و <code>body</code> نیز میباشد که به آن عناصر اشاره میکنند.</p>
<h2><a class="h_ident" id="h_61lnXO6abr" href="#h_61lnXO6abr" tabindex="-1" role="presentation"></a>درختها</h2>
<p>کمی به درختهای گرامر که در <a href="12_language.html#parsing">فصل 12</a> معرفی شدند فکر کنید. ساختار آنها بسیار شبیه به ساختار یک سند مرورگر است. هر <em>گره</em> ممکن است به دیگر گرهها ارجاع دهد، <em>فرزندان</em>، که خود میتوانند فرزندان خود را داشته باشند. این شکل یک ساختار تودرتوی معمول است که عناصر در آن میتوانند حاوی زیرعنصرهایی مشابه باشند.</p>
<p><a class="p_ident" id="p_Yfb0Ie8yZw" href="#p_Yfb0Ie8yZw" tabindex="-1" role="presentation"></a>یک ساختار داده را زمانی یک درخت مینامیم که دارای شاخههایی بدون دور باشد ( یک گره ممکن نیست به شکل مستقیم یا غیر مستقیم حاوی خودش باشد) و همچنین یک <em>ریشه</em> مشخص داشته باشد. در رابطه با DOM، ریشهی درخت، <bdo><code>document.<wbr>documentElement</code></bdo> میباشد.</p>
<p>درختها در علم کامپیوتر کاربرد زیادی دارند. علاوه بر نمایش ساختارهای درختی مانند اسناد HTML یا برنامهها، اغلب از آنها برای نگهداری مجموعههای مرتب شدهی داده استفاده میشود زیرا معمولا ورود یا جستجوی عناصر در یک درخت با کارایی بیشتری نسبت به یک آرایهی تخت انجام میشود.</p>
<p><a class="p_ident" id="p_2qC0ZocETq" href="#p_2qC0ZocETq" tabindex="-1" role="presentation"></a>یک درخت معمول دارای انواع مختلفی از گرهها میباشد. درخت گرامر <a href="12_language.html">زبان Egg</a> دارای شناسهها، مقادیر، و گرههای کاربرد (Application) بود. گرههای کاربرد میتوانستند دارای فرزند باشند، درحالیکه شناسهها و مقادیر از جنس <em>برگ</em> بودند؛ منظور گرههایی است که فرزندی ندارند.</p>
<p><a class="p_ident" id="p_BPT5caOywU" href="#p_BPT5caOywU" tabindex="-1" role="presentation"></a>همین روال برای DOM هم برقرار است. گرهها به عنوان عناصر، که برچسبهای HTML را نمایش میدهند، ساختار سند را تعیین میکنند. این گرهها میتوانند گرههای فرزند داشته باشند. یک نمونه از این نوع گرهها <bdo><code>document.body</code></bdo> است. بعضی از این فرزندان می توانند گرههایی از نوع برگ باشند، مثل متنها یا گرههای توضیحات.</p>
<p><a class="p_ident" id="p_4vDbo+rf3M" href="#p_4vDbo+rf3M" tabindex="-1" role="presentation"></a>هر شیء گرهی DOM دارای خاصیتی به نام <code>nodeType</code> است که حاوی کدی (عددی) است که نوع آن گره را مشخص میکند. عناصر دارای کد 1 میباشند که همچنین به صورت یک خاصیت ثابت <bdo><code>Node.<wbr>ELEMENT_NODE</code></bdo> نیز در دسترس است. گرههای متنی ، که نمایانگر یک قسمت از متن در سند میباشند دارای کد 3 میباشند (<bdo><code>Node.TEXT_NODE</code></bdo>). کد 8 نیز به توضیحات اختصاص دارد (<bdo><code>Node.<wbr>COMMENT_NODE</code></bdo>).</p>
<p>یک روش دیگر برای به تصویر کشیدن درخت مربوط به سندمان، شکل زیر است.</p><figure><img src="img/html-tree.svg" alt="HTML document as a tree"></figure>
<p>برگها، گرههای متنی هستند و پیکانها نمایانگر روابط والد-فرزندی بین گرهها میباشند.</p>
<h2 id="standard"><a class="h_ident" id="h_oM9lfT151A" href="#h_oM9lfT151A" tabindex="-1" role="presentation"></a>استاندارد</h2>
<p><a class="p_ident" id="p_U31P8vW5B+" href="#p_U31P8vW5B+" tabindex="-1" role="presentation"></a>استفاده از کدهای عددی رمزگونه برای نمایش نوع گرهها چیزی نیست که در جاوااسکریپت معمول باشد. در ادامه فصل می بینیم که دیگر بخشهای رابط DOM نیز حسی نامانوس ایجاد میکنند. دلیل آن این است که DOM فقط برای جاوااسکریپت طراحی نشده است. بلکه تلاش شده که رابط آن نسبت به زبانها بی طرف باشد که بتوان از آن در دیگر سیستمها به خوبی استفاده شود – نه فقط در HTML بلکه همچنین برای XML که فرمتی عمومی برای دادهها است و گرامری شبیه به HTML دارد.</p>
<p>خوب این زیاد مطلوب نیست. استانداردها اغلب مفید میباشند. اما در این مورد خاص، مزیت آن (سازگاری فرا زبانی) آن قدرها قانع کننده نیست. در دست داشتن رابطی که به خوبی با زبانی که استفاده میکنید یکپارچه است، زمان زیادی برای شما صرفه جویی میکند تا اینکه یک رابط عمومی برای همهی زبانها داشته باشیم.</p>
<p>یک نمونه از این یکپارچگی ضعیف، خاصیت <code>childNodes</code> است که در گرههای عنصر در DOM، وجود دارند. این خاصیت یک شیء آرایهطور را نگهداری میکند که خاصیتی به نام <code>length</code> دارد و همچنین خاصیتهایی دارد که توسط اعداد برچسبگذاری شده اند تا بتوان به گرههای فرزند دسترسی داشت. اما این یک نمونه از نوع <code>NodeList</code> است نه یک آرایهی واقعی بنابراین متدهای آرایه مثل <code>slice</code> و <code>map</code> را ندارد.</p>
<p>همچنین مشکلاتی وجود دارد که ناشی از طراحی ضعیف است. به عنوان مثال، راهی برای ایجاد یک گره جدید به همراه گرههای فرزند و خصوصیتها در یک گام وجود ندارد. بلکه باید ابتدا گره را ایجاد کنید، بعد فرزندان و خصوصیتها را یکی پس از دیگری به وسیله اثرات جانبی بسازید. کدهایی که با DOM تعامل زیادی برقرار میکنند، معمولا طولانی، تکراری و بدریخت هستند.</p>
<p>اما این ایرادات، مشکلات مهلکی محسوب نمیشوند. چون جاوااسکریپت این امکان را به ما میدهد که تجریدهای خودمان را بنویسیم، میتوان راههای بهتری را برای انجام عملیات برنامهتان طراحی کنید. خیلی از کتابخانههایی که برای برنامهنویسی مرتبط با مرورگر ایجاد شده اند، این ابزار را فراهم میکنند.</p>
<h2><a class="h_ident" id="h_jrjdfj0V6G" href="#h_jrjdfj0V6G" tabindex="-1" role="presentation"></a>حرکت در درخت</h2>
<p>گرههای DOM حاوی پیوندهای زیادی به دیگر گرههای نزدیک میباشند. نمودار زیر این موضوع را به تصویر می کشد:</p><figure><img src="img/html-links.svg" alt="Links between DOM nodes"></figure>
<p><a class="p_ident" id="p_pD/MhHwik3" href="#p_pD/MhHwik3" tabindex="-1" role="presentation"></a>اگرچه این نمودار فقط 1 پیوند برای هر نوع نشان میدهد، اما هر گره خاصیتی به نام <code>parentNode</code> دارد که در صورت وجود به گرهای اشاره میکند که خودش بخشی از آن است. به همین صورت، هر گرهی عنصر (گره نوع 1) دارای یک خاصیت <code>childNodes</code> است که به یک شیء آرایهطور اشاره میکند که حاوی فرزندان آن گره میباشد.</p>
<p>در تئوری، میتوانید با استفاده از پیوندهای والد و فرزند، به هر جای درخت حرکت کنید. اما جاوااسکریپت پیوندهای مناسب دیگری را در اختیار شما قرار میدهد. خاصیتهای <code>firstChild</code> و <code>lastChild</code> به اولین و آخرین عنصرهای فرزند اشاره میکنند یا مقدار <code>null</code> را در صورتی که فرزندی نداشته باشد خواهند داشت. به طور مشابه، <code>previousSibling</code> و <code>nextSibling</code> به گرههای همجوار اشاره میکنند که گرههایی هستند که تحت والد مشترکی قرار دارند و درست قبل یا بعد از گرهی مورد نظر قرار گرفته اند. برای اولین فرزند، <code>previousSibling</code> برابر با <code>null</code> خواهد بود و برای فرزند آخر، <code>nextSibling</code> برابر <code>null</code> خواهد بود.</p>
<p><a class="p_ident" id="p_NWoZK3kTsE" href="#p_NWoZK3kTsE" tabindex="-1" role="presentation"></a>همچنین خاصیتی به نام <code>children</code> وجود دارد که شبیه به <code>childeNodes</code> است با این تفاوت که فقط فرزندان نوع عنصر (نوع 1) را شامل میشود نه دیگر انواع گره فرزند. این خاصیت میتواند در زمانی که به گره های متنی نیازی ندارید استفاده شود.</p>
<p>وقتی با یک ساختار دادهی تودرتو مثل این ساختار کار میکنید، توابع بازگشتی اغلب مفید میباشند. تابع مثال زیر یک سند را برای یافتن گرههای متنی جستجو میکند که دارای یک رشتهی خاص باشند و در صورت پیدا کردن آن، مقدار <code>true</code> را برمی گرداند.</p>
<pre id="talksAbout" class="snippet cm-s-default" data-language="javascript" data-sandbox="homepage"><a class="c_ident" id="c_mDHDYNTxd7" href="#c_mDHDYNTxd7" tabindex="-1" role="presentation"></a><span class="cm-keyword">function</span> <span class="cm-def">talksAbout</span>(<span class="cm-def">node</span>, <span class="cm-def">string</span>) {
<span class="cm-keyword">if</span> (<span class="cm-variable-2">node</span>.<span class="cm-property">nodeType</span> <span class="cm-operator">==</span> <span class="cm-variable">Node</span>.<span class="cm-property">ELEMENT_NODE</span>) {
<span class="cm-keyword">for</span> (<span class="cm-keyword">let</span> <span class="cm-def">i</span> <span class="cm-operator">=</span> <span class="cm-number">0</span>; <span class="cm-variable-2">i</span> <span class="cm-operator"><</span> <span class="cm-variable-2">node</span>.<span class="cm-property">childNodes</span>.<span class="cm-property">length</span>; <span class="cm-variable-2">i</span><span class="cm-operator">++</span>) {
<span class="cm-keyword">if</span> (<span class="cm-variable">talksAbout</span>(<span class="cm-variable-2">node</span>.<span class="cm-property">childNodes</span>[<span class="cm-variable-2">i</span>], <span class="cm-variable-2">string</span>)) {
<span class="cm-keyword">return</span> <span class="cm-atom">true</span>;
}
}
<span class="cm-keyword">return</span> <span class="cm-atom">false</span>;
} <span class="cm-keyword">else</span> <span class="cm-keyword">if</span> (<span class="cm-variable-2">node</span>.<span class="cm-property">nodeType</span> <span class="cm-operator">==</span> <span class="cm-variable">Node</span>.<span class="cm-property">TEXT_NODE</span>) {
<span class="cm-keyword">return</span> <span class="cm-variable-2">node</span>.<span class="cm-property">nodeValue</span>.<span class="cm-property">indexOf</span>(<span class="cm-variable-2">string</span>) <span class="cm-operator">></span> <span class="cm-operator">-</span><span class="cm-number">1</span>;
}
}
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">talksAbout</span>(<span class="cm-variable">document</span>.<span class="cm-property">body</span>, <span class="cm-string">"book"</span>));
<span class="cm-comment">// → true</span></pre>
<p>چون <code>childNodes</code> یک آرایهی واقعی نیست نمیتوان برای پیمایش آن از <bdo><code>for</code>/<code>of</code></bdo> استفاده کرد بلکه باید یا از یک حلقهی معمولی <code>for</code> بهره برد یا از <bdo><code>Array.from</code></bdo> استفاده نمود.</p>
<p>خاصیت <code>nodeValue</code> یک گرهی متنی، حاوی رشتهی متنی است که گره نشان میدهد.</p>
<h2><a class="h_ident" id="h_jkfe+D+vyO" href="#h_jkfe+D+vyO" tabindex="-1" role="presentation"></a>پیدا کردن عناصر</h2>
<p>حرکت در طول پیوندها به گرههای والد، فرزندان و گرههای همجوار اغلب مفید است. اما اگر بخواهیم یک گرهی خاص را در یک سند پیدا کنیم، شروع از <bdo><code>document.body</code></bdo> و پیمایش یک مسیر ثابت از خاصیتها برای یافتن گره، ایدهی خوبی نیست. برای این کار نیاز است تا فرضهایی دربارهی یک ساختار دقیق از سند داشته باشیم – ساختاری که احتمالا قرار است آن را تغییر دهید. یکی دیگر از فاکتورهایی که کار را پیچیده میکند این است که گرههای متنی برای فضاهای خالی بین گرهها هم ایجاد میشوند. مثلا در برچسب <bdo><code><body></code></bdo> سند، فقط سه فرزند ندارد (<bdo><code><h1></code></bdo> و دو <bdo><code><p></code></bdo> ) بلکه در واقع دارای هفت فرزند میباشد. آن سه عنصر به همراه فضاهای خالی قبل، بعد و بینشان.</p>
<p><a class="p_ident" id="p_Agg/RXngim" href="#p_Agg/RXngim" tabindex="-1" role="presentation"></a>بنابراین اگر بخواهیم خصوصیت <code>href</code> پیوند موجود در سند را به دست بیاوریم، نمی خواهیم دستوری شبیه به ” فرزند دوم ششمین فرزند body سند را به دست بیاور” داشته باشیم. بهتر می بود اگر میتوانستیم دستوری شبیه به “اولین لینکی که در سند آمده است را بگیر” داشته باشیم. و میتوانیم این کار را بکنیم.</p>
<pre class="snippet cm-s-default" data-language="javascript" data-sandbox="homepage"><a class="c_ident" id="c_X6zFdF/80F" href="#c_X6zFdF/80F" tabindex="-1" role="presentation"></a><span class="cm-keyword">let</span> <span class="cm-def">link</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">getElementsByTagName</span>(<span class="cm-string">"a"</span>)[<span class="cm-number">0</span>];
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">link</span>.<span class="cm-property">href</span>);</pre>
<p>تمامی گرههای عنصر، دارای متدی به نام <code>getElementsByTagName</code> هستند که تمامی عناصری که برچسب داده شده را دارند و زیرمجموعهی آن گره محسوب میشوند (فرزند مستقیم و غیر مستقیم) را جمع آوری میکند و به صورت یک شیء آرایهطور برمی گرداند.</p>
<p>برای یافتن یک گرهی خاص <em>واحد</em>، میتوانید به آن یک خصوصیت <code>id</code> اختصاص دهید و از <bdo><code>document.<wbr>getElementById</code></bdo> استفاده کنید.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_CpFVpKYjsr" href="#c_CpFVpKYjsr" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>My ostrich Gertrude:<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">id</span>=<span class="cm-string">"gertrude"</span> <span class="cm-attribute">src</span>=<span class="cm-string">"img/ostrich.png"</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">let</span> <span class="cm-def">ostrich</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">getElementById</span>(<span class="cm-string">"gertrude"</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">ostrich</span>.<span class="cm-property">src</span>);
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p>سومین متد که کاری مشابه انجام میدهد <code>getElementsByClassName</code> است که شبیه به <code>getElementsByTagName</code> عمل میکند و در محتوای یک گرهی عنصر به جستجو می پردازد و تمامی عناصری که رشتهی داده شده را در خصوصیت <code>class</code> شان دارند برمی گرداند.</p>
<h2><a class="h_ident" id="h_mmI08QO0Iz" href="#h_mmI08QO0Iz" tabindex="-1" role="presentation"></a>ایجاد تغییر در سند</h2>
<p>تقریبا تمامی قسمتهای ساختار دادهی DOM را میتوان تغییر داد. میتوان شکل درخت سند را با ایجاد تغییر در روابط والد-فرزندی دستکاری کرد. گرهها دارای متدی به نام <code>remove</code> میباشند که میتوان از آن برای حذف گره از والد کنونیاش استفاده نمود. برای افزودن یک گرهی فرزند به یک گرهی عنصر میتوانیم از <code>appendChild</code> استفاده کنیم که باعث میشود آن گره به انتهای لیست فرزندان اضافه شود. یا از <code>insertBefore</code> استفاده کنیم که گرهای که به عنوان آرگومان اول آمده را قبل از گرهای که به عنوان آرگومان دوم آمده است وارد میکند.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_xdAyPFCEJ5" href="#c_xdAyPFCEJ5" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>One<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>Two<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>Three<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">let</span> <span class="cm-def">paragraphs</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">getElementsByTagName</span>(<span class="cm-string">"p"</span>);
<span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">insertBefore</span>(<span class="cm-variable">paragraphs</span>[<span class="cm-number">2</span>], <span class="cm-variable">paragraphs</span>[<span class="cm-number">0</span>]);
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p><a class="p_ident" id="p_sNOF69+xiE" href="#p_sNOF69+xiE" tabindex="-1" role="presentation"></a>یک گره فقط در یک موقعیت از سند میتواند موجودیت داشته باشد. بنابراین، قراردادن پاراگراف <em>3</em> جلوی پاراگراف <em>1</em> آن را از انتهای سند حذف میکند و بعد جلو پاراگراف <em>1</em> قرار میدهد که نتیجه به این صورت میشود: <bdo><em>3/2/1</em></bdo>. تمامی عملیاتی که گرهای را در جایی قرار میدهد به عنوان یک اثر جانبی موجب میشوند که ابتدا آن گره از جایگاه فعلیاش حذف شود (اگر جایی بوده باشد).</p>
<p>متد <code>replaceChild</code> برای جایگزین کردن یک گرهی فرزند با گرهی فرزندی دیگر استفاده میشود. این متد دو گره به عنوان آرگومان دریافت میکند: گرهی جدید و گرهای که باید جایگزین شود. گرهی جایگزین شده باید فرزند عنصری باشد که متد روی آن فراخوانی شده است. توجه داشته باشید که هر دوی <code>replaceChild</code> و <code>insertBefore</code> به عنوان آرگومان اول گرهای <em>جدید</em> دریافت میکنند.</p>
<h2><a class="h_ident" id="h_riRWH0lO2A" href="#h_riRWH0lO2A" tabindex="-1" role="presentation"></a>ایجاد گرهها</h2>
<p>فرض کنید می خواهیم اسکریپتی بنویسیم که تمامی عکسهای موجود در سند (برچسبهای <bdo><code><img></code></bdo>) را با نوشتهای که در خصوصیت <code>alt</code> آن قرار دارد جایگزین کند، نوشتهای که برای مشخص کردن یک نمایش متنی برای تصویر استفاده میشود.</p>
<p>این کار هم شامل حذف عکسها میشود و هم ایجاد یک گرهی متنی جهت جایگزینی عکس. گرههای متنی توسط <bdo><code>document.<wbr>createTextNode</code></bdo> ایجاد میشوند.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_x13nsyh4X4" href="#c_x13nsyh4X4" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>The <span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">src</span>=<span class="cm-string">"img/cat.png"</span> <span class="cm-attribute">alt</span>=<span class="cm-string">"Cat"</span><span class="cm-tag cm-bracket">></span> in the
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">src</span>=<span class="cm-string">"img/hat.png"</span> <span class="cm-attribute">alt</span>=<span class="cm-string">"Hat"</span><span class="cm-tag cm-bracket">></span>.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"><</span><span class="cm-tag">button</span> <span class="cm-attribute">onclick</span>=<span class="cm-string">"replaceImages()"</span><span class="cm-tag cm-bracket">></span>Replace<span class="cm-tag cm-bracket"></</span><span class="cm-tag">button</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">function</span> <span class="cm-def">replaceImages</span>() {
<span class="cm-keyword">let</span> <span class="cm-def">images</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">getElementsByTagName</span>(<span class="cm-string">"img"</span>);
<span class="cm-keyword">for</span> (<span class="cm-keyword">let</span> <span class="cm-def">i</span> <span class="cm-operator">=</span> <span class="cm-variable-2">images</span>.<span class="cm-property">length</span> <span class="cm-operator">-</span> <span class="cm-number">1</span>; <span class="cm-variable-2">i</span> <span class="cm-operator">>=</span> <span class="cm-number">0</span>; <span class="cm-variable-2">i</span><span class="cm-operator">--</span>) {
<span class="cm-keyword">let</span> <span class="cm-def">image</span> <span class="cm-operator">=</span> <span class="cm-variable-2">images</span>[<span class="cm-variable-2">i</span>];
<span class="cm-keyword">if</span> (<span class="cm-variable-2">image</span>.<span class="cm-property">alt</span>) {
<span class="cm-keyword">let</span> <span class="cm-def">text</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">createTextNode</span>(<span class="cm-variable-2">image</span>.<span class="cm-property">alt</span>);
<span class="cm-variable-2">image</span>.<span class="cm-property">parentNode</span>.<span class="cm-property">replaceChild</span>(<span class="cm-variable-2">text</span>, <span class="cm-variable-2">image</span>);
}
}
}
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p>با دادن یک رشته، تابع <code>createTextNode</code> به ما یک گرهی متنی تحویل میدهد که می توانیم آن را در سند قرار داده تا در صفحهی نمایش نشان داده شود.</p>
<p>حلقهای که عکسها را پیمایش میکند از پایان لیست کارش را شروع میکند. این کار لازم است چرا که لیست گرهها که توسط متدی مثل <code>getElementsByTagName</code> برگردانده میشود ( یا خاصیتی مثل <code>childNodes</code>)، لیستی زنده است. به این معنا که با تغییر سند، لیست هم بهروز می شود. اگر از ابتدا شروع می کردیم، حذف اولین عکس ممکن بود باعث شود لیست اولین عنصرش را از دست بدهد که در این صورت با تکرار حلقه در بار دوم ، زمانی که <code>i</code> برابر 1 میشود، از کار می ایستاد زیرا طول مجموعه اکنون برابر 1 است.</p>
<p>اگر یک مجموعهی ثابت از گرهها را لازم دارید، بهجای یک مجموعهی زنده از آن ها، میتوانید مجموعه را با فراخوانی <bdo><code>Array.from</code></bdo> به یک آرایهی واقعی تبدیل کنید.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_YYMkVyoN/K" href="#c_YYMkVyoN/K" tabindex="-1" role="presentation"></a><span class="cm-keyword">let</span> <span class="cm-def">arrayish</span> <span class="cm-operator">=</span> {<span class="cm-number cm-property">0</span>: <span class="cm-string">"one"</span>, <span class="cm-number cm-property">1</span>: <span class="cm-string">"two"</span>, <span class="cm-property">length</span>: <span class="cm-number">2</span>};
<span class="cm-keyword">let</span> <span class="cm-def">array</span> <span class="cm-operator">=</span> <span class="cm-variable">Array</span>.<span class="cm-property">from</span>(<span class="cm-variable">arrayish</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">array</span>.<span class="cm-property">map</span>(<span class="cm-def">s</span> <span class="cm-operator">=></span> <span class="cm-variable-2">s</span>.<span class="cm-property">toUpperCase</span>()));
<span class="cm-comment">// → ["ONE", "TWO"]</span></pre>
<p>برای ایجاد گرههای عنصر، میتوانید از متد <bdo><code>document.<wbr>createElement</code></bdo> استفاده کنید. این متد یک نام برچسب گرفته و یک گرهی تهی از نوع داده شده را بر می گرداند.</p>
<p id="elt">در مثال پیش رو یک تابع کاربردی به نام <code>elt</code> ایجاد میشود که یک گرهی عنصر را ایجاد کرده و دیگر آرگومانهایش را به عنوان فرزندان آن گره در نظر میگیرد. در ادامه از همین تابع برای افزودن یک خصوصیت به یک برچسب نقل قول استفاده میشود.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_3rSOndXJQI" href="#c_3rSOndXJQI" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">blockquote</span> <span class="cm-attribute">id</span>=<span class="cm-string">"quote"</span><span class="cm-tag cm-bracket">></span>
No book can ever be finished. While working on it we learn
just enough to find it immature the moment we turn away
from it.
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">blockquote</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">function</span> <span class="cm-def">elt</span>(<span class="cm-def">type</span>, <span class="cm-meta">...</span><span class="cm-def">children</span>) {
<span class="cm-keyword">let</span> <span class="cm-def">node</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">createElement</span>(<span class="cm-variable-2">type</span>);
<span class="cm-keyword">for</span> (<span class="cm-keyword">let</span> <span class="cm-def">child</span> <span class="cm-keyword">of</span> <span class="cm-variable-2">children</span>) {
<span class="cm-keyword">if</span> (<span class="cm-keyword">typeof</span> <span class="cm-variable-2">child</span> <span class="cm-operator">!=</span> <span class="cm-string">"string"</span>) <span class="cm-variable-2">node</span>.<span class="cm-property">appendChild</span>(<span class="cm-variable-2">child</span>);
<span class="cm-keyword">else</span> <span class="cm-variable-2">node</span>.<span class="cm-property">appendChild</span>(<span class="cm-variable">document</span>.<span class="cm-property">createTextNode</span>(<span class="cm-variable-2">child</span>));
}
<span class="cm-keyword">return</span> <span class="cm-variable-2">node</span>;
}
<span class="cm-variable">document</span>.<span class="cm-property">getElementById</span>(<span class="cm-string">"quote"</span>).<span class="cm-property">appendChild</span>(
<span class="cm-variable">elt</span>(<span class="cm-string">"footer"</span>, <span class="cm-string">"—"</span>,
<span class="cm-variable">elt</span>(<span class="cm-string">"strong"</span>, <span class="cm-string">"Karl Popper"</span>),
<span class="cm-string">", preface to the second editon of "</span>,
<span class="cm-variable">elt</span>(<span class="cm-string">"em"</span>, <span class="cm-string">"The Open Society and Its Enemies"</span>),
<span class="cm-string">", 1950"</span>));
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<h2><a class="h_ident" id="h_O0wNoz3KxF" href="#h_O0wNoz3KxF" tabindex="-1" role="presentation"></a>خصوصیتها</h2>
<p>بعضی از خصوصیتهای عناصر مثل <code>href</code> برای پیوندها را میتوان به عنوان خاصیتی با همین نام روی شیء DOM عنصر، مورد دستیابی قرار داد. این برای بیشتر خصوصیتهای استاندارد رایج، برقرار است.</p>
<p>اما HTML این امکان را فراهم کرده است که هر خصوصیتی که بخواهید را به گرهها اضافه کنید. این امکان میتواند مفید باشد زیرا به شما اجازه میدهد اطلاعات بیشتری را در یک سند ذخیره کنید. با این وجود اگر نام خصوصیتهای خودتان را بسازید، این خصوصیتها به عنوان خاصیت شیء گره در دسترس نخواهند بود. برای کار با آن ها باید از متدهای <code>getAttribute</code> و <code>setAttribute</code> استفاده کنید.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_S977zg3XyT" href="#c_S977zg3XyT" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span> <span class="cm-attribute">data-classified</span>=<span class="cm-string">"secret"</span><span class="cm-tag cm-bracket">></span>The launch code is 00000000.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span> <span class="cm-attribute">data-classified</span>=<span class="cm-string">"unclassified"</span><span class="cm-tag cm-bracket">></span>I have two feet.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">let</span> <span class="cm-def">paras</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">getElementsByTagName</span>(<span class="cm-string">"p"</span>);
<span class="cm-keyword">for</span> (<span class="cm-keyword">let</span> <span class="cm-def">para</span> <span class="cm-keyword">of</span> <span class="cm-variable">Array</span>.<span class="cm-property">from</span>(<span class="cm-variable">paras</span>)) {
<span class="cm-keyword">if</span> (<span class="cm-variable">para</span>.<span class="cm-property">getAttribute</span>(<span class="cm-string">"data-classified"</span>) <span class="cm-operator">==</span> <span class="cm-string">"secret"</span>) {
<span class="cm-variable">para</span>.<span class="cm-property">remove</span>();
}
}
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p>توصیه شده که نام این گونه خصوصیتهای ساختگی را با پیشوند <bdo><code>data-</code></bdo> آغاز کنید تا مطمئن شوید که تداخلی با دیگر خصوصیتها پیش نخواهد آمد.</p>
<p>خصوصیت <code>class</code> که یکی از خصوصیتهای رایج است، یک کلیدواژه در جاوااسکریپت محسوب می شود. به دلایل تاریخی – بعضی از پیادهسازیهای قدیمی جاوااسکریپت نمیتوانستند نامهای خاصیتی که با کلیدواژهها مطابقت داشتند را مدیریت کنند – خاصیتی که برای دسترسی به این خصوصیت در نظر گرفته شده است <code>className</code> است. همچنین میتوانید تحت نام واقعی خودش <code>"class"</code> نیز به وسیلهی متدهای <code>getAttribute</code> و <code>setAttribute</code> به آن دسترسی داشته باشید.</p>
<h2><a class="h_ident" id="h_AvxsvFKyUv" href="#h_AvxsvFKyUv" tabindex="-1" role="presentation"></a>طرحبندی (layout)</h2>
<p><a class="p_ident" id="p_bpk35930LG" href="#p_bpk35930LG" tabindex="-1" role="presentation"></a>ممکن است متوجه شده باشید که انواع مختلف عنصرها به صورت متفاوتی طرح بندی میشوند. بعضی مانند پاراگراف ها (<bdo><code><p></code></bdo>) یا سرعنوانها (<code><h1></code>)، تمامی عرض سند را اشغال کرده و هر کدام در خط جدیدی به نمایش در میآیند. این عناصر، عناصر بلاک نامیده میشوند. دیگر عناصر، مثل پیوندها (<code><a></code>) یا عنصر <bdo><code><strong></code></bdo> در همان خط کنار متن پیرامونشان نمایش داده میشوند. این عنصرها را عناصر درون خطی (inline) مینامند.</p>
<p>برای هر سند داده شده، مرورگرها میتوانند با درنظر گرفتن موقعیت و اندازهی هر عنصر، یک طرح را محاسبه کنند. این طرح بعد برای به تصویر کشیدن سند استفاده می شود.</p>
<p>اندازه و موقعیت یک عنصر را میتوان از طریق جاوااسکریپت به دست آورد. خاصیتهای <code>offsetWidth</code> و <code>offsetHeight</code> فضایی که یک عنصر اشغال میکند را در واحد <em>پیکسل</em> نشان می دهند. یک پیکسل واحد بنیادی اندازهگیری در مرورگر است. به طور سنتی این واحد به کوچکترین نقطهای که صفحهنمایش میتواند به تصویر بکشد مرتبط است اما در مانیتورهای مدرن، که قادرند نقطههای <em>خیلی</em> کوچک را به تصویر بکشند، دیگر موضوعیت ندارد و یک پیکسل مرورگر ممکن است چند نقطه را در صفحهی نمایش پوشش دهد.</p>
<p><a class="p_ident" id="p_ymvNS28/qS" href="#p_ymvNS28/qS" tabindex="-1" role="presentation"></a>به طور مشابه، <code>clientWidth</code> و <code>clientHeight</code> به شما اندازهی فضای <em>درون</em> یک عنصر را نشان میدهد و عرض خط مرزی (border) در نظر گرفته نمیشود.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_E5M9cwi2qC" href="#c_E5M9cwi2qC" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span> <span class="cm-attribute">style</span>=<span class="cm-string">"border: 3px solid red"</span><span class="cm-tag cm-bracket">></span>
I'm boxed in
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">let</span> <span class="cm-def">para</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">getElementsByTagName</span>(<span class="cm-string">"p"</span>)[<span class="cm-number">0</span>];
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-string">"clientHeight:"</span>, <span class="cm-variable">para</span>.<span class="cm-property">clientHeight</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-string">"offsetHeight:"</span>, <span class="cm-variable">para</span>.<span class="cm-property">offsetHeight</span>);
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p id="boundingRect">موثرترین روش برای بدست آوردن موقعیت دقیق یک عنصر روی صفحهی نمایش، استفاده از متد <code>getBoundingClientRect</code> است. این متد یک شیء بر می گرداند که شامل خاصیتهای <code>top</code>، <code>bottom</code>، <code>left</code> و <code>right</code> میباشد که مشخص میکنند موقعیت هر ضلع یک عنصر به نسبت بالا و چپ صفحهنمایش چند پیکسل است. اگر این اعداد را نسبت به کل سند لازم دارید، باید موقعیت اسکرول فعلی را به آن اضافه کنید. این موقعیت را میتوان در متغیرهای <code>pageXOffset</code> و <code>pageYOffset</code> بدست آورد.</p>
<p>طرح بندی یک سند میتواند کار زیادی ببرد. برای اعمال سرعت بیشتر، موتور مرورگر با هر بار تغییر در سند آن را دوباره طرح بندی نمیکند بلکه تا زمانی که بتواند آن را به تاخیر می اندازد .زمانی که برنامهی جاوااسکریپت که سند را تغییر داده است به پایان اجرایش برسد، مرورگر باید یک طرح جدید محاسبه کند تا بتواند سند تغییریافته را به تصویر بکشد. زمانی که یک برنامه موقعیت یا اندازهی چیزی را با خواندن خاصیتهایی مثل <code>offsetHeight</code> یا فراخوانی <code>getBoundingClientRect</code> درخواست می کند، فراهم ساختن اطلاعات صحیح نیز نیاز به محاسبهی طرح دارد.</p>
<p><a class="p_ident" id="p_8iX6WJG+D2" href="#p_8iX6WJG+D2" tabindex="-1" role="presentation"></a>برنامهای که زیاد و به تکرار به خواندن اطلاعات طرح DOM و تغییر DOM می پردازد باعث میشود که محاسبات طرحبندی زیاد اتفاق بیفتد که در نتیجه این برنامه به کندی اجرا خواهد شد. کد پیش رو مثالی از این گونه برنامه است. این مثال از دو برنامه تشکیل یافته است که خطی از کاراکترهای <em>X</em> با پهنای <bdo>2,000</bdo> پیکسل می سازند و زمانی که هرکدام طول می کشد را محاسبه میکنند.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_Mmn5ZrRT52" href="#c_Mmn5ZrRT52" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span> <span class="cm-attribute">id</span>=<span class="cm-string">"one"</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span> <span class="cm-attribute">id</span>=<span class="cm-string">"two"</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">function</span> <span class="cm-def">time</span>(<span class="cm-def">name</span>, <span class="cm-def">action</span>) {
<span class="cm-keyword">let</span> <span class="cm-def">start</span> <span class="cm-operator">=</span> <span class="cm-variable">Date</span>.<span class="cm-property">now</span>(); <span class="cm-comment">// Current time in milliseconds</span>
<span class="cm-variable-2">action</span>();
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable-2">name</span>, <span class="cm-string">"took"</span>, <span class="cm-variable">Date</span>.<span class="cm-property">now</span>() <span class="cm-operator">-</span> <span class="cm-variable-2">start</span>, <span class="cm-string">"ms"</span>);
}
<span class="cm-variable">time</span>(<span class="cm-string">"naive"</span>, () <span class="cm-operator">=></span> {
<span class="cm-keyword">let</span> <span class="cm-def">target</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">getElementById</span>(<span class="cm-string">"one"</span>);
<span class="cm-keyword">while</span> (<span class="cm-variable-2">target</span>.<span class="cm-property">offsetWidth</span> <span class="cm-operator"><</span> <span class="cm-number">2000</span>) {
<span class="cm-variable-2">target</span>.<span class="cm-property">appendChild</span>(<span class="cm-variable">document</span>.<span class="cm-property">createTextNode</span>(<span class="cm-string">"X"</span>));
}
});
<span class="cm-comment">// → naive took 32 ms</span>
<span class="cm-variable">time</span>(<span class="cm-string">"clever"</span>, <span class="cm-keyword">function</span>() {
<span class="cm-keyword">let</span> <span class="cm-def">target</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">getElementById</span>(<span class="cm-string">"two"</span>);
<span class="cm-variable-2">target</span>.<span class="cm-property">appendChild</span>(<span class="cm-variable">document</span>.<span class="cm-property">createTextNode</span>(<span class="cm-string">"XXXXX"</span>));
<span class="cm-keyword">let</span> <span class="cm-def">total</span> <span class="cm-operator">=</span> <span class="cm-variable">Math</span>.<span class="cm-property">ceil</span>(<span class="cm-number">2000</span> <span class="cm-operator">/</span> (<span class="cm-variable-2">target</span>.<span class="cm-property">offsetWidth</span> <span class="cm-operator">/</span> <span class="cm-number">5</span>));
<span class="cm-variable-2">target</span>.<span class="cm-property">firstChild</span>.<span class="cm-property">nodeValue</span> <span class="cm-operator">=</span> <span class="cm-string">"X"</span>.<span class="cm-property">repeat</span>(<span class="cm-variable-2">total</span>);
});
<span class="cm-comment">// → clever took 1 ms</span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<h2><a class="h_ident" id="h_HCjm+UpXpb" href="#h_HCjm+UpXpb" tabindex="-1" role="presentation"></a>سبک دهی</h2>
<p><a class="p_ident" id="p_DZMJ1GOqkX" href="#p_DZMJ1GOqkX" tabindex="-1" role="presentation"></a>تاکنون دیدهایم که عناصر مختلف HTML به شکل متفاوتی به تصویر کشیده میشوند. بعضی به عنوان بلاک و بعضی درونخطی (inline) نشان داده میشوند. بعضی سبک بصری اضافه میکنند – <code><strong></code> محتوایش را توپر میکند و <code><a></code> محتوایش را آبی رنگ و زیر آن خط می اندازد.</p>
<p>شیوهای که یک برچسب <code><img></code> تصویر را نمایش میدهد یا یک برچسب <code><a></code> متنی را به یک لینک تبدیل میکند، به طور کامل به نوع آن عنصر وابسته است. اما سبک بصریای که به صورت پیشفرض به یک عنصر اضافه میشود، مثل رنگ متن یا داشتن زیرخط، را میتوانیم تغییر دهیم. در اینجا مثالی که از خصوصیت <code>style</code> استفاده میکند را می بینیم.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_Qie8s1kOFZ" href="#c_Qie8s1kOFZ" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"><</span><span class="cm-tag">a</span> <span class="cm-attribute">href</span>=<span class="cm-string">"."</span><span class="cm-tag cm-bracket">></span>Normal link<span class="cm-tag cm-bracket"></</span><span class="cm-tag">a</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"><</span><span class="cm-tag">a</span> <span class="cm-attribute">href</span>=<span class="cm-string">"."</span> <span class="cm-attribute">style</span>=<span class="cm-string">"color: green"</span><span class="cm-tag cm-bracket">></span>Green link<span class="cm-tag cm-bracket"></</span><span class="cm-tag">a</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span></pre>
<p><a class="p_ident" id="p_JuyNAPtrVU" href="#p_JuyNAPtrVU" tabindex="-1" role="presentation"></a>یک خصوصیت style میتواند حاوی یک یا چند <em>اعلان</em> باشد که شامل یک خاصیت (مثل <code>color</code>) که به همراه دونقطه و مقدارش میآید. زمانی که بیش از یک اعلان وجود دارد، باید هر اعلان با یک نقطهویرگول جدا شود مثل <bdo><code>"color: red; border: none"</code></bdo>.</p>
<p>خیلی از جنبههای مربوط به سند وجود دارند که میتوانند توسط سبکدهی تاثیر بپذیرند. به عنوان مثال خاصیت <code>display</code> برای کنترل نحوهی نمایش یک عنصر به صورت درونخطی یا بلاک استفاده میشود.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_NN8SrlwTXB" href="#c_NN8SrlwTXB" tabindex="-1" role="presentation"></a>This text is displayed <span class="cm-tag cm-bracket"><</span><span class="cm-tag">strong</span><span class="cm-tag cm-bracket">></span>inline<span class="cm-tag cm-bracket"></</span><span class="cm-tag">strong</span><span class="cm-tag cm-bracket">></span>,
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">strong</span> <span class="cm-attribute">style</span>=<span class="cm-string">"display: block"</span><span class="cm-tag cm-bracket">></span>as a block<span class="cm-tag cm-bracket"></</span><span class="cm-tag">strong</span><span class="cm-tag cm-bracket">></span>, and
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">strong</span> <span class="cm-attribute">style</span>=<span class="cm-string">"display: none"</span><span class="cm-tag cm-bracket">></span>not at all<span class="cm-tag cm-bracket"></</span><span class="cm-tag">strong</span><span class="cm-tag cm-bracket">></span>.</pre>
<p>برچسب <code>block</code> در خط خودش به پایان میرسد به دلیل اینکه عناصر بلاکی به صورت درون خطی کنار متن پیرامونشان نشان داده نمیشوند. برچسب آخر اصلا نمایش داده نمیشود – <bdo><code>display: none</code></bdo> مانع از نمایش یک عنصر در صفحهی نمایش میشود. این روشی برای مخفی کردن عناصر است. معمولا ترجیح داده میشود بجای حذف کامل یک عنصر از سند، از این روش استفاده شود به دلیل این که بازگرداندن آن در آینده در این روش آسان تر است.</p>
<p>کدهای جاوااسکریپت میتوانند مستقیما سبکدهی یک عنصر را با استفاده از خاصیت <code>style</code> دستکاری کنند. این خاصیت شیئی را نگهداری میکند که خاصیتهایی برای همهی ویژگیهای سبکدهی دارد. مقدار این خاصیتها از نوع رشته است که میتوانیم برای تغییر یک جنبهی خاص از سبک بصری عنصر مورد نظر آن را بنویسیم.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_WtWpdICuOL" href="#c_WtWpdICuOL" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span> <span class="cm-attribute">id</span>=<span class="cm-string">"para"</span> <span class="cm-attribute">style</span>=<span class="cm-string">"color: purple"</span><span class="cm-tag cm-bracket">></span>
Nice text
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">let</span> <span class="cm-def">para</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">getElementById</span>(<span class="cm-string">"para"</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">para</span>.<span class="cm-property">style</span>.<span class="cm-property">color</span>);
<span class="cm-variable">para</span>.<span class="cm-property">style</span>.<span class="cm-property">color</span> <span class="cm-operator">=</span> <span class="cm-string">"magenta"</span>;
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p>نام بعضی از خاصیتهای سبکدهی حاوی کاراکتر خط پیوند <bdo>(-)</bdo> است مانند <bdo><code>font-family</code></bdo>. به دلیل این که کار با این نوع نام ها در جاوااسکریپت کمی دشوار است (برای دسترسی باید چیزی مثل <bdo><code>style["font-family"]</code></bdo> داشته باشید)، نام خاصیتهای این گونه نامها در شیء <code>style</code> آن خط پیوند را حذف کرده و حرف بعد از آن را با حروف بزرگ می نویسند <bdo>(<code>style.fontFamily</code>)</bdo>.</p>
<h2><a class="h_ident" id="h_tSG6LG86on" href="#h_tSG6LG86on" tabindex="-1" role="presentation"></a>سبکهای آبشاری</h2>
<p><a class="p_ident" id="p_xYoGBd2Q++" href="#p_xYoGBd2Q++" tabindex="-1" role="presentation"></a>به سیستم سبکدهی بصری در اچتیامال، CSS گفته میشود که مخفف برگههای سبک آبشاری یا سلسلهمراتبی (cascading style sheets) است. یک برگهی سبک به مجموعهای از دستورات گفته میشود که برای سبکدهی ظاهری به عناصر یک سند استفاده میشوند. میتوان آن را درون یک جفت برچسب <bdo><code><style></code></bdo> قرار داد.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_WnNZqmUMzQ" href="#c_WnNZqmUMzQ" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">style</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag">strong</span> {
<span class="cm-property">font-style</span>: <span class="cm-atom">italic</span>;
<span class="cm-property">color</span>: <span class="cm-keyword">gray</span>;
}
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">style</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>Now <span class="cm-tag cm-bracket"><</span><span class="cm-tag">strong</span><span class="cm-tag cm-bracket">></span>strong text<span class="cm-tag cm-bracket"></</span><span class="cm-tag">strong</span><span class="cm-tag cm-bracket">></span> is italic and gray.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span></pre>
<p>معنای <em>آبشاری</em> این است که قوانینی با سلسلهمراتب با هم ترکیب میشوند تا سبک نهایی را برای یک عنصر تولید کنند. در مثال بالا، سبک پیشفرض برای برچسبهای <bdo><code><strong></code></bdo>، که در آن <bdo><code>font-weight: bold</code></bdo> تعریف شده بود، توسط دستوری دیگر که در برچسب <code><style></code> آمده است تغییر یافته و <bdo><code>font-style</code></bdo> و <code>color</code> به آن اضافه شده است.</p>
<p>وقتی چندین دستور یک مقدار را برای یک خاصیت واحد تعریف میکنند، آخرین دستوری که خوانده شود دارای حق تقدم بالاتری خواهد بود و اعمال میشود. بنابراین اگر دستوری که در برچسب <bdo><code><style></code></bdo> آمده است <bdo><code>font-weight: normal</code></bdo> را داشته باشد، دستور پیشفرض <bdo><code>font-weight</code></bdo> در نظر گرفته نمیشود و متن به شکل نرمال نمایش داده میشود نه به صورت توپر. دستوراتی که در خصوصیت <code>style</code> به صورت مستقیم به یک گره اعمال میشوند دارای بالاترین حق تقدم هستند و همیشه در سلسلهمراتب برنده میشوند.</p>
<p><a class="p_ident" id="p_vFS2daQmbc" href="#p_vFS2daQmbc" tabindex="-1" role="presentation"></a>میتوان چیزهایی بجز نام برچسبها را در دستورات CSS مورد هدف قرار داد. دستوری به شکل <bdo><code>.abc</code></bdo>، به همهی عناصری که خصوصیت classشان دارای مقدار <code>"abc"</code> است اعمال میشود. دستوری به شکل <bdo><code>#xyz</code></bdo> به عنصری اعمال میشود که خصوصیت <code>id</code> آن برابر <code>"xyz"</code> باشد (که باید در سند منحصر به فرد باشد).</p>
<pre class="snippet cm-s-default" data-language="text/css" ><a class="c_ident" id="c_0kqCdknBKh" href="#c_0kqCdknBKh" tabindex="-1" role="presentation"></a><span class="cm-qualifier">.subtle</span> {
<span class="cm-property">color</span>: <span class="cm-keyword">gray</span>;
<span class="cm-property">font-size</span>: <span class="cm-number">80%</span>;
}
<span class="cm-builtin">#header</span> {
<span class="cm-property">background</span>: <span class="cm-keyword">blue</span>;
<span class="cm-property">color</span>: <span class="cm-keyword">white</span>;
}
<span class="cm-comment">/* p elements with id main and with classes a and b */</span>
<span class="cm-tag">p</span><span class="cm-builtin">#main</span><span class="cm-qualifier">.a</span><span class="cm-qualifier">.b</span> {
<span class="cm-property">margin-bottom</span>: <span class="cm-number">20px</span>;
}</pre>
<p><a class="p_ident" id="p_bUnjoivX3+" href="#p_bUnjoivX3+" tabindex="-1" role="presentation"></a>قاعدهی حق تقدمی که موجب میشد دستوری که آخر تعریف شده بود اعمال شود، زمانی موثر است که دستورات دارای specificity (درجهی صراحت) یکسانی باشند. درجهی صراحت یک دستور، معیاری از میزان دقتی است که آن دستور، عناصر هدفش را توصیف میکند که توسط عدد و نوع (برچسب، class و ID) عناصر مورد هدف تعیین میشود. به عنوان مثال، دستوری که <bdo><code>p.a</code></bdo> را هدف قرار میدهد دارای صراحت بیشتری از دستوراتی است که <code>p</code> یا فقط <bdo><code>.a</code></bdo> را هدف قرار میدهند و بنابراین حق تقدم بیشتری خواهد داشت.</p>
<p>دستوری به شکل <bdo><code>p > a {…}</code></bdo> سبکهای تعریف شده را به همهی برچسبهای <code><a></code> که فرزند مستقیم برچسبهای <code><p></code> محسوب میشوند اعمال میکند. به طور مشابه، <bdo><code>p a {…}</code></bdo> به همهی برچسبهای <code><a></code> که درون برچسبهای <code><p></code> باشند اعمال میشود فارغ از اینکه فرزند مستقیم یا غیر مستقیم باشند.</p>
<h2><a class="h_ident" id="h_KjINefn2Lo" href="#h_KjINefn2Lo" tabindex="-1" role="presentation"></a>گزینشگرهای پرس و جو</h2>
<p>ما در این کتاب زیاد از برگههای سبکدهی استفاده نخواهیم کرد. درک آن ها برای برنامهنویسی در مرورگر مفید است اما دامنهی بحث دربارهی سبکدهی به اندازهای گسترده میباشد که نیاز به کتاب مجزایی داشته باشند.</p>
<p><a class="p_ident" id="p_G/OP24PLTX" href="#p_G/OP24PLTX" tabindex="-1" role="presentation"></a>علت اینکه قواعد گزینشگر (selector) – منظور شیوهی نشانگذاری استفاده شده در برگههای سبکدهی برای تعیین عناصر هدف برای اعمال سبکها میباشد – را معرفی کردم این است که میتوانیم از این زبان نصف و نیمه به عنوان روشی موثر برای پیدا کردن عناصر DOM استفاده کنیم.</p>
<p>متد <code>querySelectorAll</code> که هم در شیء <code>document</code> موجود است و هم روی گرههای عنصر، یک رشتهی گزینشگر دریافت میکند و یک <code>NodeList</code> که حاوی تمامی عناصر تطبیق خورده است را برمی گرداند.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_yJ0zujW+YH" href="#c_yJ0zujW+YH" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>And if you go chasing
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span> <span class="cm-attribute">class</span>=<span class="cm-string">"animal"</span><span class="cm-tag cm-bracket">></span>rabbits<span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>And you know you're going to fall<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>Tell 'em a <span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span> <span class="cm-attribute">class</span>=<span class="cm-string">"character"</span><span class="cm-tag cm-bracket">></span>hookah smoking
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span> <span class="cm-attribute">class</span>=<span class="cm-string">"animal"</span><span class="cm-tag cm-bracket">></span>caterpillar<span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>Has given you the call<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">function</span> <span class="cm-def">count</span>(<span class="cm-def">selector</span>) {
<span class="cm-keyword">return</span> <span class="cm-variable">document</span>.<span class="cm-property">querySelectorAll</span>(<span class="cm-variable-2">selector</span>).<span class="cm-property">length</span>;
}
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">count</span>(<span class="cm-string">"p"</span>)); <span class="cm-comment">// All <p> elements</span>
<span class="cm-comment">// → 4</span>
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">count</span>(<span class="cm-string">".animal"</span>)); <span class="cm-comment">// Class animal</span>
<span class="cm-comment">// → 2</span>
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">count</span>(<span class="cm-string">"p .animal"</span>)); <span class="cm-comment">// Animal inside of <p></span>
<span class="cm-comment">// → 2</span>
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">count</span>(<span class="cm-string">"p > .animal"</span>)); <span class="cm-comment">// Direct child of <p></span>
<span class="cm-comment">// → 1</span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p>برخلاف متدهایی مثل <code>getElementsByTagName</code>، شیءای که توسط <code>querySelectorAll</code> برگردانده میشود زنده یا پویا نیست. با تغییر سند، این شیء به روز نمیشود و هنوز یک آرایهی واقعی نیست و اگر لازم دارید تا از ویژگیهای آرایهها بهره ببرید باید <bdo><code>Array.from</code></bdo> را روی آنها فراخوانی کنید.</p>
<p><a class="p_ident" id="p_EvBRWcWEg4" href="#p_EvBRWcWEg4" tabindex="-1" role="presentation"></a>متد <code>querySelector</code> (بدون All) به شکل مشابهی عمل میکند. این متد برای زمانی که قصد دارید یک عنصر مشخص را هدف قرار دهید مناسب است. این متد فقط اولین عنصری که مطابق گزینشگر بود را برمی گرداند و در صورت پیدا نکردن هیچ عنصری مقدار null را تولید می کند.</p>
<h2 id="animation"><a class="h_ident" id="h_DpcLDonzDU" href="#h_DpcLDonzDU" tabindex="-1" role="presentation"></a>موقعیت دهی و متحرکسازی</h2>
<p><a class="p_ident" id="p_o4FWKvoOFs" href="#p_o4FWKvoOFs" tabindex="-1" role="presentation"></a>خاصیت <code>position</code> در سبکدهی، تاثیر مهمی در در طرحبندی صفحه میگذارد. به صورت پیش فرض مقدار آن برابر <code>static</code> است که یعنی عنصر مورد نظر در موقعیت نرمال خودش در سند قرار میگیرد. زمانی که این مقدار به <code>relative</code> تغییر می یابد، عنصر همچنان فضایی در سند اشغال میکند اما اکنون میتوان از خاصیتهای <code>top</code> و <code>left</code> برای تغییر مکان آن نسبت به جایگاه نرمالش استفاده کرد. زمانی که <code>position</code> برابر <code>absolute</code> قرار گیرد، عنصر مورد نظر از جریان چیدمان صفحه خارج میشود – به این معنا که دیگر فضایی را اشغال نمیکند و ممکن است روی دیگر عناصر بیفتد. همچنین در این حالت خاصیتهای <code>top</code> و <code>left</code> را میتوان برای موقعیت دهی مطلق عنصر نسبت به گوشهی بالا و چپ نزدیک ترین عنصر والدش (که دارای مقدار <code>position</code> غیر از static است) استفاده کرد یا در صورت نبود آن، نسبت به کل سند موقعیت دهی میشود.</p>
<p>میتوانیم از این خاصیت برای ایجاد یک پویانمایی استفاده کنیم. صفحهی پیش رو تصویری از یک گربه را نشان میدهد که به دور دایرهای حرکت میکند.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_SCZYa8azNm" href="#c_SCZYa8azNm" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span> <span class="cm-attribute">style</span>=<span class="cm-string">"text-align: center"</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">src</span>=<span class="cm-string">"img/cat.png"</span> <span class="cm-attribute">style</span>=<span class="cm-string">"position: relative"</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">let</span> <span class="cm-def">cat</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">querySelector</span>(<span class="cm-string">"img"</span>);
<span class="cm-keyword">let</span> <span class="cm-def">angle</span> <span class="cm-operator">=</span> <span class="cm-variable">Math</span>.<span class="cm-property">PI</span> <span class="cm-operator">/</span> <span class="cm-number">2</span>;
<span class="cm-keyword">function</span> <span class="cm-def">animate</span>(<span class="cm-def">time</span>, <span class="cm-def">lastTime</span>) {
<span class="cm-keyword">if</span> (<span class="cm-variable-2">lastTime</span> <span class="cm-operator">!=</span> <span class="cm-atom">null</span>) {
<span class="cm-variable">angle</span> <span class="cm-operator">+=</span> (<span class="cm-variable-2">time</span> <span class="cm-operator">-</span> <span class="cm-variable-2">lastTime</span>) <span class="cm-operator">*</span> <span class="cm-number">0.001</span>;
}
<span class="cm-variable">cat</span>.<span class="cm-property">style</span>.<span class="cm-property">top</span> <span class="cm-operator">=</span> (<span class="cm-variable">Math</span>.<span class="cm-property">sin</span>(<span class="cm-variable">angle</span>) <span class="cm-operator">*</span> <span class="cm-number">20</span>) <span class="cm-operator">+</span> <span class="cm-string">"px"</span>;
<span class="cm-variable">cat</span>.<span class="cm-property">style</span>.<span class="cm-property">left</span> <span class="cm-operator">=</span> (<span class="cm-variable">Math</span>.<span class="cm-property">cos</span>(<span class="cm-variable">angle</span>) <span class="cm-operator">*</span> <span class="cm-number">200</span>) <span class="cm-operator">+</span> <span class="cm-string">"px"</span>;
<span class="cm-variable">requestAnimationFrame</span>(<span class="cm-def">newTime</span> <span class="cm-operator">=></span> <span class="cm-variable">animate</span>(<span class="cm-variable-2">newTime</span>, <span class="cm-variable-2">time</span>));
}
<span class="cm-variable">requestAnimationFrame</span>(<span class="cm-variable">animate</span>);
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<p>تصویر ما در مرکز صفحه قرار گرفته است و مقدار <code>position</code> آن برابر <code>relative</code> است. ما پیوسته مقدار <code>top</code> و <code>left</code> تصویر را برای ایجاد حرکت بهروز رسانی میکنیم.</p>
<p id="animationFrame"><a class="p_ident" id="p_5sPdYwQo/V" href="#p_5sPdYwQo/V" tabindex="-1" role="presentation"></a>این اسکریپت از <code>requestAnimationFrame</code> برای زمانبندی اجرای تابع <code>animate</code> هنگامی که مرورگر آماده است تا تصویر صفحه را دوباره بکشد، استفاده میکنیم. تابع <code>animate</code> خود دوباره <code>requestAnimationFrame</code> را برای زمانبندی بهروزرسانی بعدی فراخوانی میکند. زمانی که پنجرهی مرورگر (یا تب مرورگر) فعال است، این باعث میشود که بهروزرسانیها با نرخ 60 بار در ثانیه انجام شود که پویانمایی روانی را تولید میکند.</p>
<p>اگر فقط DOM را در حلقه بهروزرسانی می کردیم، صفحه ممکن بود قفل شود چیزی در تصویر نمایش داده نشود. مرورگرها صفحهی نمایش خود را در هنگام اجرای یک برنامهی جاوااسکریپت بهروزرسانی نمیکنند و اجازهی هیچ تعاملی با صفحه را هم فراهم نمی کنند. به همین دلیل است که به <code>requestAnimationFrame</code> نیاز داریم – این تابع به مرورگر می گوید که کار ما در این لحظه تمام است و میتواند به کارش ادامه دهد، مثل بهروزرسانی صفحه نمایش و پاسخ به درخواستهای کاربر.</p>
<p>تابع پویانمایی، زمان فعلی را به عنوان یک آرگومان دریافت میکند. برای کسب اطمینان از اینکه میزان حرکت گربه در هزارم ثانیه مداوم و باثبات است، این تابع سرعت را در قسمتهایی که زاویه تغییر میکند بر اساس تفاوت بین زمان فعلی و آخرین باری که تابع اجرا شد در نظر میگیرد. اگر با هر قدم مقدار ثابتی حرکت در زاویه انجام میشد، ممکن بود حرکت تصویر لنگ بزند، درصورتی که به عنوان مثال یک برنامهی سنگین دیگر روی همان کامپیوتر اجرا میشد که تابع را برای کسری از ثانیه از حرکت می انداخت.</p>
<p id="sin_cos">برای حرکت دایرهای از توابع مثلثات مثل <bdo><code>Math.cos</code></bdo> و <bdo><code>Math.sin</code></bdo> استفاده میشود. برای افرادی که با این مفاهیم آشنا نیستند، به طور خلاصه آن ها را معرفی خواهم کرد چرا که کم و بیش از آن ها در کتاب استفاده خواهیم کرد.</p>
<p><a class="p_ident" id="p_DRhHBjyVId" href="#p_DRhHBjyVId" tabindex="-1" role="presentation"></a>متدهای <bdo><code>Math.cos</code></bdo> و <bdo><code>Math.sin</code></bdo> برای پیدا کردن نقاطی که روی محیط دایرهای با مرکز <bdo>(0,0)</bdo> و شعاع یک استفاده میشوند. هر دوی این متدها ورودیهایشان را به عنوان موقعیتهایی روی این دایره تفسیر میکنند، که صفر به معنای نقطهای است که در راستترین قسمت دایره قرار گرفته است و حرکت در جهت گردش عقربههای ساعت تا <bdo>2π</bdo> می باشد (حدود <bdo>6.28</bdo>) که یک دور کامل دایره انجام میشود. <bdo><code>Math.cos</code></bdo> مختصات x نقطهای که مربوط به موقعیت داده شده است را برمیگرداند در حالیکه <bdo><code>Math.sin</code></bdo> مختصات y آن را می دهد. موقعیتهایی (یا زاویهها) که از <bdo>2π</bdo> بزرگتر باشند یا از 0 کوچکتر باشند معتبر محسوب میشوند – یعنی چرخش تکرار میشود بنابراین <bdo><em>a</em>+2π</bdo> معادل همان زاویهی <em>a</em> خواهد بود.</p>
<p><a class="p_ident" id="p_iBcDofBaKA" href="#p_iBcDofBaKA" tabindex="-1" role="presentation"></a>این واحد اندازهگیری برای زاویهها را رادیان مینامند- یک دایرهی کامل برابر <bdo>2π</bdo> رادیان است، مشابه 360 در واحد درجه. ثابت π در جاوااسکریپت توسط <bdo><code>Math.PI</code></bdo> در دسترس است.</p><figure><img src="img/cos_sin.svg" alt="Using cosine and sine to compute coordinates"></figure>
<p><a class="p_ident" id="p_4n84s1DpT5" href="#p_4n84s1DpT5" tabindex="-1" role="presentation"></a>کد پویانمایی گربه یک شمارنده نیز نگهداری میکند، <code>angle</code>، تا بتواند زاویهی فعلی حرکت را داشته باشد و با هر بار فراخوانی تابع <code>animate</code> آن را افزایش میدهد. بعدا میتواند از این زاویه برای محاسبه موقعیت فعلی عنصر تصویر استفاده کند. مقدار خاصیت سبکی <code>top</code> هم به وسیلهی <bdo><code>Math.sin</code></bdo> و ضرب آن در 20 محاسبه میشود که نمایانگر شعاع عمودی در بیضی ما است. مقدار <code>left</code> نیز بر اساس <bdo><code>Math.cos</code></bdo> و ضرب آن در 200 است بنابراین بیضی ما دارای عرض بسیار بیشتری نسبت به طولش میباشد.</p>
<p><a class="p_ident" id="p_/aRZoq1buo" href="#p_/aRZoq1buo" tabindex="-1" role="presentation"></a>توجه داشته باشید که مقادیر مربوط به سبکها معمولا به واحد نیاز دارند. در این مثال، ما باید <code>"px"</code> را به عدد اضافه کنیم تا به مرورگر اعلام کنیم که شمارش در واحد پیکسل میباشد (نه سانتیمتر، “em”، یا دیگر واحدها). ممکن است به آسانی از این نکته غفلت شود. استفاده از اعداد بدون واحدها باعث میشود که سبکدهی شما اعمال نگردد- مگر اینکه آن عدد 0 باشد که همیشه معنای یکسانی دارد.</p>
<h2><a class="h_ident" id="h_EzvDUHyjs2" href="#h_EzvDUHyjs2" tabindex="-1" role="presentation"></a>خلاصه</h2>
<p>برنامههای جاوااسکریپت میتوانند در صفحهای که مرورگر به نمایش می گذارد، با استفاده از یک ساختار داده به نام DOM، دخالت و دستکاری کنند. این ساختار داده نمایانگر مدل مرورگر از صفحه است و یک برنامهی جاوااسکریپت میتواند آن را تغییر دهد و در سندی که به نمایش درمی آید تغییر ایجاد کند.</p>
<p>DOM به شکل یک درخت سازماندهی شده است که در آن عناصر به صورت سلسلهمراتبی براساس ساختار سند مرتب میشوند. اشیائی که نمایندهی عناصر هستند دارای خاصیتهایی مانند <code>parentNode</code> و <code>childNodes</code> هستند که میتوان از آن ها برای حرکت در این درخت استفاده کرد.</p>
<p>نحوهی نمایش یک سند را میتوان با سبکدهی تغییر داد و این کار به دو روش چسباندن سبکها به عناصر به صورت مستقیم و یا با تعریف دستوراتی که عناصر خاصی را هدف قرار میدهند صورت میپذیرد. خاصیتهای سبکدهی زیاد و متنوعی وجود دارد مثل <code>color</code> یا <code>display</code>. کدهای جاوااسکریپت میتوانند سبک یک عنصر را مستقیما از طریق خصوصیت <code>style</code> دستکاری کنند.</p>
<h2><a class="h_ident" id="h_ggOFdVwDCk" href="#h_ggOFdVwDCk" tabindex="-1" role="presentation"></a>تمرینها</h2>
<h3 id="exercise_table"><a class="i_ident" id="i_cG/PUQtNdg" href="#i_cG/PUQtNdg" tabindex="-1" role="presentation"></a>ساخت یک جدول</h3>
<p>یک جدول HTML به وسیلهی ساختار برچسبهای زیر ساخته میشود:</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_MudCG4cYiG" href="#c_MudCG4cYiG" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">table</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">tr</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">th</span><span class="cm-tag cm-bracket">></span>name<span class="cm-tag cm-bracket"></</span><span class="cm-tag">th</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">th</span><span class="cm-tag cm-bracket">></span>height<span class="cm-tag cm-bracket"></</span><span class="cm-tag">th</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">th</span><span class="cm-tag cm-bracket">></span>place<span class="cm-tag cm-bracket"></</span><span class="cm-tag">th</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">tr</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">tr</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">td</span><span class="cm-tag cm-bracket">></span>Kilimanjaro<span class="cm-tag cm-bracket"></</span><span class="cm-tag">td</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">td</span><span class="cm-tag cm-bracket">></span>5895<span class="cm-tag cm-bracket"></</span><span class="cm-tag">td</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">td</span><span class="cm-tag cm-bracket">></span>Tanzania<span class="cm-tag cm-bracket"></</span><span class="cm-tag">td</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">tr</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">table</span><span class="cm-tag cm-bracket">></span></pre>
<p>برای هر ردیف، برچسب <bdo><code><table></code></bdo> یک برچسب <bdo><code><tr></code></bdo> خواهد داشت. درون این برچسبهای <bdo><code><tr></code></bdo> میتوانیم سلولهای جدول را قرار دهیم: سلولهای معمولی (<bdo><code><td></code></bdo>) یا سلولهای عنوان (<bdo><code><th></code></bdo>).</p>
<p>با در دست داشتن مجموعه اطلاعاتی دربارهی کوهها، آرایهای از اشیاء شامل <code>name</code>، <code>height</code> و <code>place</code> ، یک ساختار DOM برای جدولی که این اشیاء را میشمارد ایجاد کنید. این جدول باید یک ستون برای هر کلید و یک ردیف برای هر شیء داشته باشد، مازاد بر آن یک ردیف عنوان به وسیلهی عنصرهای <bdo><code><th></code></bdo> در قسمت بالا که نام ستونها را لیست کند.</p>
<p>این برنامه را به صورتی بنویسید که در آن ستونها به طور خودکار از اشیاء گرفته میشوند و این کار با گرفتن نامهای خاصیتهای اولین شیء در مجموعهی دادهها رخ میدهد.</p>
<p>به این صورت بنویسید که ستونها به صورت خودکار با گرفتن نام خاصیتهای اولین شیء در مجموعهی دادهها ایجاد شوند.</p>
<p>جدول نهایی را به عنصری که دارای خصوصیت <code>id</code> برابر با <code>"mountains"</code> میباشد اضافه کنید تا در صفحهی نمایش داده شود.</p>
<p>بعد از این که این قسمت را تکمیل کردید سلولهایی که حاوی مقادیر عددی هستند را راست چین کنید و این کار را با تنظیم <bdo><code>style.textAlign</code></bdo> برابر با <code>"right"</code> انجام دهید.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_SaASguUQJh" href="#c_SaASguUQJh" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">h1</span><span class="cm-tag cm-bracket">></span>Mountains<span class="cm-tag cm-bracket"></</span><span class="cm-tag">h1</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">id</span>=<span class="cm-string">"mountains"</span><span class="cm-tag cm-bracket">></span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">const</span> <span class="cm-def">MOUNTAINS</span> <span class="cm-operator">=</span> [
{<span class="cm-property">name</span>: <span class="cm-string">"Kilimanjaro"</span>, <span class="cm-property">height</span>: <span class="cm-number">5895</span>, <span class="cm-property">place</span>: <span class="cm-string">"Tanzania"</span>},
{<span class="cm-property">name</span>: <span class="cm-string">"Everest"</span>, <span class="cm-property">height</span>: <span class="cm-number">8848</span>, <span class="cm-property">place</span>: <span class="cm-string">"Nepal"</span>},
{<span class="cm-property">name</span>: <span class="cm-string">"Mount Fuji"</span>, <span class="cm-property">height</span>: <span class="cm-number">3776</span>, <span class="cm-property">place</span>: <span class="cm-string">"Japan"</span>},
{<span class="cm-property">name</span>: <span class="cm-string">"Vaalserberg"</span>, <span class="cm-property">height</span>: <span class="cm-number">323</span>, <span class="cm-property">place</span>: <span class="cm-string">"Netherlands"</span>},
{<span class="cm-property">name</span>: <span class="cm-string">"Denali"</span>, <span class="cm-property">height</span>: <span class="cm-number">6168</span>, <span class="cm-property">place</span>: <span class="cm-string">"United States"</span>},
{<span class="cm-property">name</span>: <span class="cm-string">"Popocatepetl"</span>, <span class="cm-property">height</span>: <span class="cm-number">5465</span>, <span class="cm-property">place</span>: <span class="cm-string">"Mexico"</span>},
{<span class="cm-property">name</span>: <span class="cm-string">"Mont Blanc"</span>, <span class="cm-property">height</span>: <span class="cm-number">4808</span>, <span class="cm-property">place</span>: <span class="cm-string">"Italy/France"</span>}
];
<span class="cm-comment">// Your code here</span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<div class="solution"><div class="solution-text">
<p>میتوانید از <bdo><code>document.<wbr>createElement</code></bdo> برای ایجاد گرههای جدید استفاده کنید، همچنین از <bdo><code>document.<wbr>createTextNode</code></bdo> برای ایجاد گرههای متنی و از <bdo><code>appendChild</code></bdo> نیز برای قرار دادن گرهها در دیگر گرهها.</p>
<p>در ادامه لازم دارید تا نام کلیدها را پیمایش کنید؛ یک بار برای پر کردن ردیف بالایی و بعد دوباره برای هر همهی اشیاء موجود در آرایه تا بتوانید ردیفهای داده را بسازید. برای بدست آوردن یک آرایه از نام کلیدها از شیء اول، <bdo><code>Object.keys</code></bdo> به دردتان خواهد خورد.</p>
<p>برای اضافه کردن جدول به گرهی والد فعلی، میتوانید از <bdo><code>document.<wbr>getElementById</code></bdo> یا <bdo><code>document.<wbr>querySelector</code></bdo> برای پیدا کردن گرهای با خاصیت <code>id</code> مورد نظر استفاده کنید.</p>
</div></div>
<h3><a class="i_ident" id="i_fZAmRnDswn" href="#i_fZAmRnDswn" tabindex="-1" role="presentation"></a>گرفتن عناصر به وسیلهی نام برچسبها</h3>
<p>متد <bdo><code>document.<wbr>getElementsByTagName</code></bdo> تمامی عناصر فرزند را برای نام برچسب داده شده برمی گرداند. نسخهی خودتان از این متد را به عنوان یک تابع بنویسید که یک گره و یک رشته (نام برچسب) را به عنوان ورودیها بگیرد و آرایهای که حاوی تمامی گرههای فرزند متعلق به آن برچسب را برگرداند.</p>
<p>برای پیدا کردن نام برچسب یک عنصر، از خاصیت <code>nodeName</code> استفاده کنید. اما توجه داشته باشید که این خاصیت نام برچسب را با حروف بزرگ برمی گرداند. از متدهای رشته، <code>toLowerCase</code> یا <code>toUpperCase</code> برای درست کردن آن استفاده کنید.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_SHm9FthIXO" href="#c_SHm9FthIXO" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">h1</span><span class="cm-tag cm-bracket">></span>Heading with a <span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span>span<span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span> element.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">h1</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>A paragraph with <span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span>one<span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span>, <span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span>two<span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span>
spans.<span class="cm-tag cm-bracket"></</span><span class="cm-tag">p</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">function</span> <span class="cm-def">byTagName</span>(<span class="cm-def">node</span>, <span class="cm-def">tagName</span>) {
<span class="cm-comment">// Your code here.</span>
}
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">byTagName</span>(<span class="cm-variable">document</span>.<span class="cm-property">body</span>, <span class="cm-string">"h1"</span>).<span class="cm-property">length</span>);
<span class="cm-comment">// → 1</span>
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">byTagName</span>(<span class="cm-variable">document</span>.<span class="cm-property">body</span>, <span class="cm-string">"span"</span>).<span class="cm-property">length</span>);
<span class="cm-comment">// → 3</span>
<span class="cm-keyword">let</span> <span class="cm-def">para</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">querySelector</span>(<span class="cm-string">"p"</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">byTagName</span>(<span class="cm-variable">para</span>, <span class="cm-string">"span"</span>).<span class="cm-property">length</span>);
<span class="cm-comment">// → 2</span>
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<div class="solution"><div class="solution-text">
<p>سادهترین روش پیادهسازی این راهحل استفاده از یک تابع بازگشتی است، شبیه به <a href="14_dom.html#talksAbout"><code>talksAbout</code> تابع</a> که پیشتر در این فصل تعریف گردید.</p>
<p>میتوانید عناصر آرایهی تولیدی را به وسیلهی فراخوانی تابع <code>byTagname</code> به صورت بازگشتی به هم بچسبانید تا خروجی را تولید کنید. یا میتوانید تابعی درونی تعریف کنید که خودش را به صورت بازگشتی فراخوانی کند که این تابع به یک متغیر آرایه که در تابع بیرونیاش تعریف شده دسترسی دارد و میتواند عناصری که پیدا میکند را به آن اضافه نماید. فراموش نکنید که باید تابع درونی را یک بار از تابع بیرونی فراخوانی کنید تا روند کار شروع شود.</p>
<p>تابع بازگشتی باید نوع گره را بررسی کیند. در اینجا فقط مایلیم تا گره نوع 1 (<code>Node.<wbr>ELEMENT_NODE</code>) را در نظر بگیریم. برای این نوع گرهها، ما باید فرزندانشان را پیمایش کنیم و برای هر فرزند، مشاهده کنیم که آیا با پرسوجوی ما مطابقت دارد یا خیر و همچنین یک فراخوانی بازگشتی روی آن نیز داشته باشیم تا فرزندان آن را نیز پوشش داده باشیم.</p>
</div></div>
<h3><a class="i_ident" id="i_6HcsNCNcZW" href="#i_6HcsNCNcZW" tabindex="-1" role="presentation"></a>کلاه گربه</h3>
<p>پویانمایی <a href="14_dom.html#animation">ایجاد شده در قبل</a> را توسعه دهید تا گربه و کلاهش (<bdo><code><img src="img/<wbr>hat.<wbr>png"></code></bdo>) هر کدام در جهت مخالف هم بچرخند.</p>
<p>یا کاری کنید که کلاه دور گربه بچرخد. یا پویانمایی را به صورتی که جالب باشد تغییر دهید.</p>
<p>برای ساده سازی روند موقعیت دهی چند شیء، احتمالا ایدهی خوبی است که به سراغ موقعیت دهی مطلق برویم. به این معنا که <code>top</code> و <code>left</code> بر اساس گوشهی چپ و بالای سند محاسبه بشوند. برای جلوگیری از مختصات منفی، که باعث میشود که تصاویر به بیرون از فضای قابل مشاهده صفحه منتقل شوند، میتوانید یک عدد مشخص و ثابت را به مقادیر موقعیت ها اضافه کنید.</p>
<pre class="snippet cm-s-default" data-language="text/html" ><a class="c_ident" id="c_h3Gqsempqw" href="#c_h3Gqsempqw" tabindex="-1" role="presentation"></a><span class="cm-tag cm-bracket"><</span><span class="cm-tag">style</span><span class="cm-tag cm-bracket">></span><span class="cm-tag">body</span> { <span class="cm-property">min-height</span>: <span class="cm-number">200px</span> }<span class="cm-tag cm-bracket"></</span><span class="cm-tag">style</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">src</span>=<span class="cm-string">"img/cat.png"</span> <span class="cm-attribute">id</span>=<span class="cm-string">"cat"</span> <span class="cm-attribute">style</span>=<span class="cm-string">"position: absolute"</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">src</span>=<span class="cm-string">"img/hat.png"</span> <span class="cm-attribute">id</span>=<span class="cm-string">"hat"</span> <span class="cm-attribute">style</span>=<span class="cm-string">"position: absolute"</span><span class="cm-tag cm-bracket">></span>
<span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span>
<span class="cm-keyword">let</span> <span class="cm-def">cat</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">querySelector</span>(<span class="cm-string">"#cat"</span>);
<span class="cm-keyword">let</span> <span class="cm-def">hat</span> <span class="cm-operator">=</span> <span class="cm-variable">document</span>.<span class="cm-property">querySelector</span>(<span class="cm-string">"#hat"</span>);
<span class="cm-keyword">let</span> <span class="cm-def">angle</span> <span class="cm-operator">=</span> <span class="cm-number">0</span>;
<span class="cm-keyword">let</span> <span class="cm-def">lastTime</span> <span class="cm-operator">=</span> <span class="cm-atom">null</span>;
<span class="cm-keyword">function</span> <span class="cm-def">animate</span>(<span class="cm-def">time</span>) {
<span class="cm-keyword">if</span> (<span class="cm-variable">lastTime</span> <span class="cm-operator">!=</span> <span class="cm-atom">null</span>) <span class="cm-variable">angle</span> <span class="cm-operator">+=</span> (<span class="cm-variable-2">time</span> <span class="cm-operator">-</span> <span class="cm-variable">lastTime</span>) <span class="cm-operator">*</span> <span class="cm-number">0.001</span>;
<span class="cm-variable">lastTime</span> <span class="cm-operator">=</span> <span class="cm-variable-2">time</span>;
<span class="cm-variable">cat</span>.<span class="cm-property">style</span>.<span class="cm-property">top</span> <span class="cm-operator">=</span> (<span class="cm-variable">Math</span>.<span class="cm-property">sin</span>(<span class="cm-variable">angle</span>) <span class="cm-operator">*</span> <span class="cm-number">40</span> <span class="cm-operator">+</span> <span class="cm-number">40</span>) <span class="cm-operator">+</span> <span class="cm-string">"px"</span>;
<span class="cm-variable">cat</span>.<span class="cm-property">style</span>.<span class="cm-property">left</span> <span class="cm-operator">=</span> (<span class="cm-variable">Math</span>.<span class="cm-property">cos</span>(<span class="cm-variable">angle</span>) <span class="cm-operator">*</span> <span class="cm-number">200</span> <span class="cm-operator">+</span> <span class="cm-number">230</span>) <span class="cm-operator">+</span> <span class="cm-string">"px"</span>;
<span class="cm-comment">// Your extensions here.</span>
<span class="cm-variable">requestAnimationFrame</span>(<span class="cm-variable">animate</span>);
}
<span class="cm-variable">requestAnimationFrame</span>(<span class="cm-variable">animate</span>);
<span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></pre>
<div class="solution"><div class="solution-text">
<p><a class="p_ident" id="p_wwW0b1Mdqm" href="#p_wwW0b1Mdqm" tabindex="-1" role="presentation"></a><bdo><code>Math.cos</code></bdo> و <bdo><code>Math.sin</code></bdo> زاویهها را در واحد رادیان اندازهگیری میکنند، جاییکه یک دایرهی کامل برابر با <bdo>2π</bdo> میباشد. برای یک زاویهی داده شده، میتوانید برای بهدست آوردن زاویهی مخالف، نصف <bdo>2π</bdo> که میشود <bdo><code>Math.PI</code></bdo>. این کار برای قرار دادن کلاه در طرف دیگر دایره کاربرد دارد.</p>
</div></div><nav><a href="13_browser.html" title="previous chapter">◀</a> <a href="index.html" title="cover">◆</a> <a href="15_event.html" title="next chapter">▶</a></nav>
</article>