[Go to site: main page, start]

0% found this document useful (0 votes)
23 views78 pages

Understanding DOM: Selectors & Manipulation

The document provides a comprehensive overview of the Document Object Model (DOM), detailing its structure, node types, properties, methods, and manipulation techniques. It covers DOM selectors, node traversal, event handling, and rendering, along with examples of how to use various DOM methods. Additionally, it discusses the prototype chain of DOM and its relationship with the browser's representation of web documents.

Uploaded by

杜韦萱
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views78 pages

Understanding DOM: Selectors & Manipulation

The document provides a comprehensive overview of the Document Object Model (DOM), detailing its structure, node types, properties, methods, and manipulation techniques. It covers DOM selectors, node traversal, event handling, and rendering, along with examples of how to use various DOM methods. Additionally, it discusses the prototype chain of DOM and its relationship with the browser's representation of web documents.

Uploaded by

杜韦萱
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

DOM (Document Object Model)

DOM Selector
Read
1. document

2. [Link]('id')

3. [Link]('element')

4. [Link]('class')

5. [Link]('name')

6. [Link]('query')

7. [Link]()

Type of Nodes & Node Value


1. Element Node - 1

2. Attribute Node ** - 2

3. Text Node - 3

4. Comment - 8

5. Document - 9

6. DocumentFragment - 11

Node Properties
1. nodeName

2. nodeValue

3. nodeType

4. attributes

Node Method
1. [Link]()

Node Tree Traversal


1. parentNode
2. childNodes

3. firstChild

4. lastChild

5. nextSibling

6. previousSibling
DOM Tree Traversal
1. parentElement

2. children**

3. [Link] === [Link]

4. firstElementChild

5. lastElementChild

6. nextElementSibling

7. previousElementSibling

Inheritance
Prototype Chain of DOM
Basic Operation
DOM Manipulation
Add / Create
1. [Link](); ***

2. [Link]();

3. [Link]();

4. [Link]();

Insert
1. [Link]() ***

2. [Link](a, b) ***

Delete
1. [Link]()
2. [Link]() - ES5 ***
Replace
1. [Link](new, origin)

Element Node Properties


1. innerHTML ***

2. innerText

3. textContent

Element Node Method


1. [Link]('prop', 'value')

2. [Link]('prop')

3. [Link]
Window Properties and DOM Offset
Viewport Offset (Width and Height)
1. [Link] / [Link]

2. [Link] & [Link]

3. [Link] & [Link]

[Link]
Rect
1. [Link]()

Size
[Link] & [Link]
Position

1. [Link] & [Link]

2. [Link]

Scrolling Distance
1. [Link] & [Link]

2. [Link] & [Link]


3. [Link] & [Link]
Scrolling
1. [Link](x, y) & [Link](x, y)

2. [Link](x, y)

Scripted CSS
Read and Write CSS
1. [Link] / [Link]['prop']**

Change CSS Style


Element Style
Pseudo Element Style
Read CSS
1. [Link](ele, pseduElem)

2. [Link]

Combined for Compatibility


Events
Adding / Register Event Listener
1. inline event handler: [Link] = function() {}

2. [Link](type, handler, useCapture)

3. [Link]('on' + type, handler)

this
Compatibility
Remove Event Listener
1. [Link] = false / ''/ null

2. [Link](type, handlerRef, useCapture)

3. [Link]('on' + type, handler)

event object, e
Stop Default Event
1. return false

2. [Link]

3. [Link] = false
2. Stop Propagation

3. [Link] / [Link]
Bubbling & Capturing
Bubbling
Capturing
Triggering Order
Stop Propagation
1. [Link]()

2. [Link] = true;

Event Delegation
Event Types
Pointer Event
Get mouse button keys(left, middle, right)
Drag and Drop
Keyboard Event
Comparison between keydown and keypress
Text Field Related Event
Focus Event
Input Event
Change Event
Browser Window Related Event
Scrolling
Loading
Rendering
Asynchronous loading
1. defer

2. async

3. Insert Script and Callback

Loading Timeline
Theory
Practicals
BOM
DOM (Document Object Model)
The data representation of the objects that comprise the structure and content of a document on the
web.

DOM is a programming interface for web documents, allowing us to manipulate HTML and XML with
various built-in DOM methods.

Document object represents the entire document.

HTML element is only the root element, which is the most important part of the document, but not the
document itself.
<!---->
<document>
<html>
</html>
</document>

Note: XML has been replaced by JSON, no longer used.

DOM cannot directly manipulate CSS, but we can use it to indirectly add inline styles to HTML
elments.

var div = [Link]('div')[0];


[Link] = '100px';
[Link] = '100px';
[Link] = 'red';

Any collection generated from DOM is an array-like object, thus not able to use array method.

DOM Selector

Read

1. document

2. [Link]('id')
1. returns an Element object representing the element whose id property matches the specified
string.
only one element is returned with given id.
2. IE ver.8 and below, id is case-insensitive.
3. IE ver.8 and below, select an element with name attribute having matching string is possible, if id
attribute is not present.
4. do not rely on id selector too much as connect to backend program might change it.
5. use only when necessary, e.g., each section has an id.

3. [Link]('element')
1. returns a live HTMLCollection - an array-like object of elements with the given tag name.
2. select specific element based on index.
3. select all elements with asterisk(*)
4. very good compatibility in every browser - mainstream

4. [Link]('class')
1. returns an array-like object of all child elements which have all of the given class name(s).
2. IE ver.8 and below not support.
3.

5. [Link]('name')
1. returns a NodeList Collection of elements with a given name attribute in the document.
2. only specific elements works, e.g., form, form elements: e.g., input, img, iframe where name
attribute has meaning.
3. in previous browser ver, elements like div did not support selection by name, but in current
browser, it is already supported.
6. [Link]('query')
1. returns the first Element within the document that matches the specified selector, or group of
selectors. If no matches are found, null is returned.
2. query is similar to how we write CSS selector.
3. IE ver.7 and below not support.
4. manipulate element (styles) is allowed.
5. weakness: not live (a copy): changing (e.g., deleting) doesn't reflect on nodelist, but the element
on display is changed.

<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var div1 = [Link]('div');
[Link]();
[Link](div1); // changes doesn't reflect.
[Link]([Link]('div')[0]); // changes does reflect. index 0 is no
</script>
</body>

7. [Link]()
1. returns a static (not live) NodeList representing a list of the document's elements that match the
specified group of selectors.
2. IE ver.7 and below not support.
3. manipulate element (style) is allowed.
4. weakness: not live (a copy): changing (e.g., deleting) doesn't reflect on nodelist, but the element
on display is changed.

<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var static = [Link]('div');
var live = [Link]('div');
static[0].remove(); // remove the first div
[Link](static); // the nodelist is not updated.
[Link](live); // live HTMLcollection reflect the change accordingly
</script>
</body>

Type of Nodes & Node Value

1. Element Node - 1

2. Attribute Node ** - 2
Attr objects inherit the Node interface, but since they are not actually child nodes of the element they
describe, the DOM does not consider them part of the document tree.
3. Text Node - 3

4. Comment - 8

5. Document - 9

6. DocumentFragment - 11

Node Properties

1. nodeName
returns the name of the current node as a string.
changing nodeName is not allowed, it is read-only.

2. nodeValue
returns or sets the value of the current node.
text, comment, CDATA nodes, return the content.
else, return null.
nodes with null nodeValues (e.g., DOM elements) are not modifiable.
3. nodeType
return integers representing node type to distinguishes different kind of nodes from each other.
var div = [Link]('div')[0];

function retElementChild(node) {
var nodeList = [Link];
var len = [Link]; // save efficiency -method chaining every time is not efficient.
var temp = {
length: 0,
push: [Link],
splice: [Link],
};
for (let i = 0; i < len; i ++) {
if (nodeList[i].nodeType === 1) {
[Link](nodeList[i]);
}

}
return [Link](temp);
}
[Link](retElementChild(div));

4. attributes
returns a live collection of all attribute nodes registered to the specified node.
access attribute name by attributes[i].name: we cannot change attribute name.
access attribute value by attributes[i].value: we can change value.
[Link];
[Link][i];
[Link][i].value;
[Link][i].name;
[Link][i].value = 123; // we can change the value
[Link][i].name = 123; // changing name is not allowed

// Example
[Link]('old value: ', [Link][0].value);
[Link]('old name: ', [Link][0].name);
[Link][0].value = 'hahahaha';
[Link][0].name = 'hahahaha';
[Link]('new value: ', [Link][0].value);
[Link]('new name: ', [Link][0].name);

Node Method

1. [Link]()
returns a boolean value indicating whether the given Node has child nodes or not.
<!--Example 1-->
<div></div>

<!--Example 2-->
<div> </div>

<!--Example 3-->
<div>
<!--comment-->
</div>
<script>
// Example 1
[Link]([Link]()); // false

// Example 2
[Link]([Link]()); // true - when there is a space between opening and closing ta

// Example 3
[Link]([Link]()); // true
</script>

Node Tree Traversal


based on relationship of elements.

compatible for all browsers.

1. parentNode
returns the parent of the specified node in the DOM tree.
#document is the top of the node and can't have parentNode (null)
<body>
<div>
<strong></strong>
<span></span>
<em></em>
</div>
<script>
var strong = [Link]('strong')[0];
[Link]([Link]); // <div>...</div>
[Link]([Link]); // <body>...</body>
[Link]([Link]); // #document (the top node
[Link]([Link]); // null
</script>
</body>

2. childNodes
returns a live NodeList of child nodes of the given element where the first child node is assigned
index 0.

<body>
<div>
<!--This is a comments-->
<strong>
<span>
1
</span>
</strong>
<span></span>
<em></em>
</div>
<script>
var div = [Link]('div')[0];
[Link]([Link]); // NodeList(9) [text, comment, text, strong, text, span, text,
[Link]([Link]); // 9 - includes text nodes - empty spaces. Note: remove
</script>
</body>
3. firstChild
returns the node's first child in the tree, or null if the node has no children.

4. lastChild
returns the last child of the node, or null if there are no child nodes.

5. nextSibling
returns the node immediately following the specified one in their parent's childNodes, or returns
null if the specified node is the last child in the parent element.

6. previousSibling
returns the node immediately preceding the specified one in its parent's childNodes list, or null if
the specified node is the first in that list.

DOM Tree Traversal


Note:

1. Convenient but low compatibility


2. Only children is supported in all browser.

1. parentElement
returns the DOM node's parent Element, or null if the node either has no parent, or its parent isn't
a DOM Element.
IE ver. 9 and below not support.

2. children**
similar to [Link], but includes only element nodes.
3. [Link] === [Link]
returns the number of child elements of this element.
IE ver. 9 and below not support.

4. firstElementChild
returns an element's first child, or null if there are no child elements.
IE ver. 9 and below not support.

5. lastElementChild
returns an element's last child Element, or null if there are no child elements.
IE ver. 9 and below not support.

6. nextElementSibling
returns the element immediately following the specified one in its parent's children list, or null if
the specified element is the last one in the list.

7. previousElementSibling
returns the Element immediately prior to the specified one in its parent's children list, or null if the
specified element is the first one in the list.
IE ver. 9 and below not support.
Inheritance

Document Object Model (DOM API) is represented as a hierarchical tree-like structure in web browser,
each individual parts represents as nodes.
Each nodes could correspond to the specific constructor functions and relate to each other via
prototype chain.

<script>
[Link] = 'abc';
var body = [Link]('body')[0];
var head = [Link]('head')[0];
</script>

Prototype Chain of DOM


1. Document and document is not same.

Document: constructor function, its prototype is inherited by [Link], and


eventually document.
document object is created by HTMLDocument.
[Link].__proto__ == [Link] is true.

[Link] = {
__proto__: [Link]
}

[Link] === document.__proto__ is true.

2. thus, the inheritance is as follow:


document (instance) --> [Link] --> [Link]
3. demonstrate the prototype chain of DOM, in which [Link] is the end of chain before
null.

thus, DOM elements can access properties and methods from [Link].

[Link](); // '[object HTMLBodyElement]'


Basic Operation
1. getElementById is defined on [Link].

HTMLDocument & XMLDocument can use.


Element nodes are inaccessible.

2. getElementsByName is defined on [Link].

Element nodes are inaccessible.

3. getElementByTagName is defined on both [Link] and [Link].

thus, both html document and element are accessible.

var div = [Link]('div')[0]; // select from document


var span = [Link]('span')[0]; // select from div element

4. [Link] has defined some commonly-used properties.

we don't need to select them again.


body: ...
head: ...
// predefined properties that ease our life.
[Link]; // <body>...</body>
[Link]; // <head>...</head>

5. [Link] has defined documentElement property, representing root element <html> of


the document.

[Link]; // <html>...</html>

6. getElementsByClassName , querySelectorAll , querySelector are defined on both


[Link] and [Link].

DOM Manipulation

Add / Create
create nodes by Js, only effective when we insert into HTML.

1. [Link](); ***

var div = [Link]('div'); // create element node


[Link](div);

2. [Link]();

var text = [Link]('text'); // create text node

3. [Link]();

var comment = [Link]('This is a comment'); // create comment node


4. [Link]();

Insert

1. [Link]() ***
every element have this method.

similar to [Link] , adding node to the end of the list of children of a specific parent node.

if the element doesn't exist, it insert the element into another element.

if the element already exist, appendChild cut and move it to the element we append to.

var divElem = [Link]('div')[0];


var span = [Link]('span');
var text = [Link]('HI, this is a text');
var comment = [Link]('This is a comment');

[Link](comment);
[Link](span);
[Link](text);

2. [Link](a, b) ***
inserts a node before a reference node as a child of a specified parent node.

insert a before b.

var divElem = [Link]('div')[0];


var strong = [Link]('strong');
[Link](strong, span);
var span = [Link]('span');
var text = [Link]('HI, this is a text');
[Link](text);
[Link](span);
[Link](strong, span);
Delete

1. [Link]()
removes a child node from the DOM and returns the removed node.
the removed child is still exist in memory, and can be reused later.

[Link](span);

// removeChild return removed part, which we can store for later use.
var a = [Link](span);

2. [Link]() - ES5 ***


removes the element from the DOM.
literally remove and no return anything.
when we no longer need an element

[Link]();

Replace

1. [Link](new, origin)
replaces a child node within the given (parent) node.

the replaced part still exist, store it in a variable for future use.

var p = [Link]('p');
var replaced = [Link](p, strong);
Element Node Properties

1. innerHTML ***
gets or sets the HTML or XML markup contained within the element.
use to set html element, and adding styles.

var div = [Link]('div');


[Link](div);
[Link]([Link]); // ''
[Link] = '123';
[Link] += '456';
[Link] = '<span style="background-color: green;">123</span>'

2. innerText
gets or sets inner text - give you text node.
old Firefox not support.
cause reflow - computational expensive***
setting innerText might remove all of the node's children and replace with a single text node based
on given string value.
3. textContent
get the content of all elements, including <script> and <style> elements.
previous version IE not support.
setting innerText might remove all of the node's children and replace with a single text node based
on given string value.

<!--Difference between innerText and textContent-->


<div>
123
<span>123</span>
456
</div>

<script>
// be careful replace text using innerText and textContent
[Link] = 123; // it replaces all the content in div.

</script>
Element Node Method

1. [Link]('prop', 'value')

[Link]('id', 'only');
<!--Example Setting Attr-->
<div></div>
<i></i>
<strong></strong>

<script>
var all = [Link]('*');
for (var i = 0; i < [Link]; i ++) {
all[i].setAttribute('this-name', all[i].nodeName);
}
</script>

2. [Link]('prop')
returns the value of a specified attribute on the element.

[Link]('id'); // only

var attr = [Link]('id');

// Example 2 - work with data-attribute


var div = [Link]('div');
var a = [Link]('a')[0];

[Link] = function () {
[Link]([Link]('data-log'));
}

3. [Link]
gets and sets the value of the class attribute of the specified element.
Window Properties and DOM Offset

Viewport Offset (Width and Height)


viewport: the visible part of the HTML on a browser.

get the width and height of the viewport.

viewport offset changes if zoom.

1. [Link] / [Link]
1. work in IE ver. 8 and below.
2. [Link] &
[Link]
1. in standards mode, every browser supports.

3. [Link] & [Link]


1. works in quirks mode.

Note:

1. New updates of browser might break some codes.


2. Standards mode: indicated by document type definition, DTD (e.g., <!DOCTYPE html> ), render
webpage based on latest syntax.
3. Quirks mode exists for back compatibility: supports previous browser version syntax despite a big
update in new browser version.
4. Usually, previous IE browser might use quirks mode.
5. save resources and the need to rewrite webpage for the latest syntax for compatibility.

[Link]
check compatibility mode: standards or quirks mode

[Link]; // 'CSS1Compat': standards


[Link]; // 'BackCompat': quirks

<!--Standards Mode-->
<!DOCTYPE html>
<html>
...
</html>

<!--Quirks Mode: Back Compatibility Mode-->


<html>
...
</html>
/**
* Note: different browsers have different values.
* @returns width and height of viewport
*/

function getViewportOffset() {
if ([Link]) {
[Link]('standard mode');
return {
w : [Link],
h : [Link],
}
} else {
if ([Link] === 'BackCompat') {
[Link]('quirk mode');
return {
w : [Link],
h : [Link],
}
} else {
[Link]('standard mode')
return {
w : [Link],
h : [Link],
}
}
}
}

Rect

1. [Link]()
return a DOMRect object containing information about size and position of an element, relative to the
viewport.

1. rather good compatibility.


2. however, height and width is not realized in IE ver. 8 and below.
3. top & left: upper left corner
4. bottom & right: lower right corner
5. return values is static, not live.

var div = [Link]('div')[0];


[Link](); // DOMRect {x: 309, y: 301, width: 200, height: 200, top: 301, …}

Size

[Link] & [Link]


return width of an element including borders, padding, not including margin.

1. similar to width and height obtained from [Link]().


var div = [Link]('div')[0];
[Link];
[Link];

Position

1. [Link] & [Link]


Not taking into account the position of the element itself.

return position of the element relative to the document if the parent position set is default / static.

return position of the element relative to its closest positioned ancestor if the parent has its position set
other than default/ static.
<!--Example 1-->
<body>
<style>
.outer {
width: 300px;
height: 300px;
border: 2px solid black;
position: relative;
top: 100px;
left: 100px;
/* margin-top: 100px;
margin-left: 100px; */
}
.inner {
width: 100px;
height: 100px;
position: absolute;
/* top: 100px;
left: 100px; */
margin-left: 100px;
margin-top: 100px;
background-color: red;
}
</style>

<div class="outer">
<div class="inner"></div>
</div>

<script>
var outer = [Link]('outer')[0];
var inner = [Link]('inner')[0];
[Link]([Link]); // 100 - distance of the element with its parent element
[Link]([Link]); // 100 - distance of the element with its parent element
</script>
</body>

<!--Example 2-->
<body>
<style>
.outer {
width: 300px;
height: 300px;
border: 2px solid black;
position: static;
top: 100px;
left: 100px;

}
.inner {
width: 100px;
height: 100px;
position: absolute;
margin-left: 100px;
margin-top: 100px;
background-color: red;
}
</style>

<div class="outer">
<div class="inner"></div>
</div>

<script>
var outer = [Link]('outer')[0];
var inner = [Link]('inner')[0];
[Link]([Link]); // 210 - relative to the doc: 100 (inner) + 102 (outer + bord
[Link]([Link]); // 202 - relative to the doc: 100 (inner) + 102 (outer + borde
</script>
</body>

Example 1: parent position set to default.


Example 2: parent position set to relative.
2. [Link]
return the closest positioned parent of an element.

If no, return body.


Note: [Link] => null

// based on previous example


// Example 1
[Link]; // <div class="outer">...</div>
// Example 2
[Link]; // <body>...</body>

Scrolling Distance
return how many pixel the document has scrolled horizontally or vertically.
1. [Link] & [Link]
[Link]: pageXOffset - alias of scrollX
[Link]: pageYOffset - alias of scrollY

note: IE ver. 8 and below is not compatible.

2. [Link] & [Link]

3. [Link] &
[Link]
note:

1. work in IE ver. 8 and below.


2. but has confusing compatibility issue: suggest adding ## 2 and ## 3.
3. Either one (e.g., ## 2) could have value, another (e.g., ## 3) will have to be 0.

/**
* Compatibility: if [Link] exists, the code inside if will be adopted.
* @returns scroll distance from x and y.
*/
function getScrollOffset() {
if ([Link]) {
return {
x : [Link],
y : [Link],
}
} else {
return {
x : [Link] + [Link],
y : [Link] + [Link],
}
}
}
Scrolling

1. [Link](x, y) & [Link](x, y)


scroll the window to particular x, y position (destination).

Note: set x or y to 0 return them to their starting position.


+x: to the left
-x: to the right
+y: to the top
-y: to the bottom

Note: from 0 -> x

[Link](0, 100); // scroll to y at 100 px


[Link](0, 100); // stay at where it is.

2. [Link](x, y)
scroll the window to x, y position by a specific amount, and the amount can be accumulated.

Next usage will scroll to another amount based on previous value.

e.g., from 0 -> x -> 2x -> 3x ->...incremental amount

[Link](0, 100);
[Link](0, 100); // accumulate
[Link](0, 100); // accumulate
[Link](0, 100); // accumulate

Scripted CSS

Read and Write CSS


1. [Link] / [Link]['prop']**
[Link] returns inline style of an element in the form of a live array-like object
CSSStyleDeclaration .
no compatibility issue.

the one and only way to write CSS style via Js.

var div = [Link]('div')[0];


[Link]([Link]); // CSSStyleDeclaration {accentColor: '', additiveSymbols: '', alignConte

styles in CSSStyleDeclaration is readable and writable.

Note:

1. name containing '-' is not allowed in js, consider bracket notation or camelCase.
2. only works for inline style of any dom elements, accessing internal stylesheet or external
stylesheet return an empty string, ''.
3. css property containing 'float' should be replaced with 'cssFloat': float is a reserved word.
4. not recommend writing shorthand property - although it works.
5. value must be string.
<body>
<style>
div {
border-radius:50%;
width: 100px;
height: 200px;
border: 1px solid black;
text-align: center;
line-height: 100px;
}
</style>
<div style="width: 200px; height: 100px; background-color: yellow;">123</div>
<script>
var div = [Link]('div')[0];
// read
[Link]([Link]); // 200px
[Link]([Link]['background-color']); // yellow
[Link]([Link]); // ''
[Link]([Link]); // ''

// write
[Link]['background-color'] = 'red';
[Link] = 'left';
[Link] = '5px dashed white';

</script>
</body>

Change CSS Style


Element Style

Example 2 is better:

1. efficient
2. maintainable

Example 1 is used only when we have to dynamically changing the style.

e.g., animation.
Note: we can only modify inline-style via js.
<body>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
}
/*Pre-defined Class*/
.active {
width = '200px';
height = '200px';
background-color = 'green';
}
</style>
<div></div>
<script>
var div = [Link]('div')[0];
// Example 1 - through [Link]
[Link] = function () {
[Link] = '200px';
[Link] = '200px';
[Link] = 'green';
}

// Example 2 - add pre-defined class


[Link] = function () {
[Link] = 'active';
}
</script>
Pseudo Element Style

<body>
<style>
div {
background-color: red;
width: 400px;
height: 100px;
}
.green::after {
content: "";
width: 10px;
height: 10px;
background-color: green;
display: inline-block;
}
.yellow::after {
content: "";
width: 10px;
height: 10px;
background-color: yellow;
display: inline-block;
}
</style>

<div class="green"></div>

<script>
// read element
var div = [Link]('div')[0];
[Link] = function() {
[Link] = 'yellow';
}

</script>
</body>
Read CSS
1. [Link](ele, pseduElem)
return computed styles in the form of live CSSStyleDeclaration object.

returned style value is in absolute unit, no relative unit.

more accurate as it returns the final computed style.

IE ver.8 and below not compatible.

Note:

1. computed styles are styles that has been computed and displayed on screen.
2. unlike [Link] , the CSSStyleDeclaration object style is read-only, we can't set style in it.
3. can be used to select pseudo element.**
<body>
<style>
div {
background-color: red;
width: 400px;
height: 100px;
}
div::after {
content: "";
width: 10px;
height: 10px;
background-color: green;
display: inline-block;
}
</style>

<div></div>

<script>
// read element
var div = [Link]('div')[0];
var styles = [Link](div, null);
[Link]([Link]);
// read pseudo element
var pseudoElemStyles = [Link](div, 'after');
[Link]([Link]); // 10px
</script>
</body>

2. [Link]
function similar to [Link] .

unique to IE only.

read-only

returned style value that is eventually displayed on the screen but not converted to absolute unit.

[Link]([Link]['width']);
Combined for Compatibility

function getStyle(elem, prop) {


if ([Link]) {
return [Link](elem, null)[prop];
} else {
return [Link][prop];
}
}

Events
Event: action / anything happens inside the programming system (e.g., browser window).

event occurs => system fires a signal => something else happens.

event listening is not handled by Js engine.

browser basic - queue.

// [Link]: clicking event


[Link] = function() {
// do something after clicking
}

interaction: do something, get feedback.

Importance: user interaction experience.

Example: drag and drop, clicking, etc.

Adding / Register Event Listener


handler: a function that run when an event is triggered.

1. inline event handler: [Link] = function() {}


the same event of an element can only register one handler function.
resembles writing inline js

<div >

Q: look like normal property but how could it interacts with event?

[Link] = function() {};

[Link] = function() {};

[Link] = function() {}; // overridden

2. [Link](type, handler, useCapture)


w3c standards, IE ver.9 and below not support.

support attaching multiple handlers to an event of the element.

Note: handlers with the same reference is only allowed once.

// with annonymous fn
[Link]('click', function() {}, false);

// handler store fn reference


[Link]('mousemove', move, false);

// register multiple handler functions under the same event of an element


[Link]('click', function() {}, false);

// Not working, move - reference has been existed.


[Link]('mousemove', move, false);

function move() {}

3. [Link]('on' + type, handler)


unique to IE.

similar to [Link]

allow attaching handlers of similar reference multiple times.


// IE

[Link]('onclick', function(){})

this

Q: the value of this inside the following method?

1. [Link] = function() {}: this refers to elem


2. [Link](): this refers to elem
3. [Link](): this refers to window.

Q: how to let attachEvent this value refers to obj?

using call / apply to call the handler function

[Link]('onclick', function() {
[Link](div);
});

function handle() {
[Link](this);
}

Compatibility

function addEvent(elem, type, handler) {


if ([Link]) {
[Link](type, handler, false);
} else if ([Link]) {
[Link]('on' + type, function() {
[Link](elem);
});
} else {
elem['on' + type] = handler;
}
}
Remove Event Listener
use case:

1. one-time pop-up advertisement.

1. [Link] = false / ''/ null

[Link] = function(){};
[Link] = null; // removed

// one time event


[Link] = function() {
// do something
[Link] = null;
}

2. [Link](type, handlerRef, useCapture)


note: annonymous fn handler couldn't be found, thus this method couldn't remove the event listener.

[Link]('click', demo , false);

[Link]('click', demo, false)

function demo(){}

// annonymous fn - couldn't remove


[Link]('click', function(){} , false);

3. [Link]('on' + type, handler)


similar to removeEventListener

unique to IE.

note: annonymous fn handler couldn't be found, thus this method couldn't remove the event listener.
event object, e
When an event occurs, browser creates an event object, containing details of the event.

handlers only takes event object as arguments.

browser will pass event object into handlers - only in non-IE browsers!

IE browser, event detail is recorded and stored in [Link] .

[Link] = function(e) {
// compatibility
var event = e || [Link];
}

Stop Default Event


cancel default behaviour for better interaction experience.

e.g., default behavior of events

1. form submission
2. a tag redirection
3. right click menu
4. etc.

1. return false

only works with inline handler function that assigns event handler directly to a specific event property
of an element.

e.g., oncontextmenu event: mouse right click menu

// setting return false -> right click no longer show menu.


[Link] = function(){
return false;
}

2. [Link]

W3C standard
IE ver.9 and below not support.
[Link] = function (e) {
[Link]();
}

[Link]('contextmenu', function(e) {
[Link]();
}, false)

3. [Link] = false

support IE

[Link] = function(e) {
[Link] = false;
}

<!--
use of one of the URI schemes=> javascript:xxx to prevent default
similar to return undefined / false
-->
<a href="javascript: void(0);">void</a>

<script>
var a = [Link]('a')[0];
//
[Link] = function(e) {
[Link]();
}
</script>

2. Stop Propagation
look at latter section for more details.

3. [Link] / [Link]
[Link] - firefox support.
[Link] - IE support.
Chrome supports both.
Q: who triggers the event?
the one we click on - known as [Link] / [Link] .

<div class="wrapper" style="width: 100px; height: 100px; background-color: red;">


<div class="box" style="width: 50px; height: 50px; background-color: green;"></div>
</div>

<script>
var wrapper = [Link]('wrapper')[0];
var box = [Link]('box')[0];
// get srcElement - compatibility writing
[Link] = function (e) {
var event = e || [Link];
var target = [Link] || [Link];
[Link]('srcElement: 'target);
}
</script>

Bubbling & Capturing

Bubbling
default
In a structurally nested elements (non-visually), a triggered event bubbles from the inner child
element to the outer parent element.
In any way, yellow div is the innermost child element, while the red div is the outermost parent
element.
<div class="wrapper">
<div class="content">
<div class="box"></div>
</div>
</div>
<script>
var wrapper = [Link]('wrapper')[0];
var content = [Link]('content')[0];
var box = [Link]('box')[0];

[Link]('click', function(){
[Link]('wrapperBubble');
}, false);

[Link]('click', function(){
[Link]('contentBubble');
}, false);

[Link]('click', function(){
[Link]('boxBubble');
}, false);
</script>

Note: box -> content -> wrapper

Capturing
The opposite of bubbling.

parent elements captures the event triggerred by child element until that child element.

child element: srcElement / target

child element doesn't capture event, it is executing as usual.

Note:
IE not support.
Chrome, firefox, opera latest ver. support.

How to invoke capturing mode?

set useCapture to true

[Link]('click', function(){}, true);


<div class="wrapper">
<div class="content">
<div class="box"></div>
</div>
</div>
<script>
var wrapper = [Link]('wrapper')[0];
var content = [Link]('content')[0];
var box = [Link]('box')[0];

[Link]('click', function(){
[Link]('wrapper');
}, true);

[Link]('click', function(){
[Link]('content');
}, true);

[Link]('click', function(){
[Link]('box');
}, true);
</script>

Triggering Order
Capturing first, Bubbling later.
Note:

Each registered handler function for a specific event type of an element can only follow one event
propagation model (bubbling or capturing).
different registered handler functions can be set to different propagation model - run on different
phase.
events such as focus, blur, change, submit, reset, select don't have bubbling.
<div class="wrapper">
<div class="content">
<div class="box"></div>
</div>
</div>
<script>
var wrapper = [Link]('wrapper')[0];
var content = [Link]('content')[0];
var box = [Link]('box')[0];

// Default: Bubbling Model


[Link]('click', function(){
[Link]('wrapperBubble');
}, false);

[Link]('click', function(){
[Link]('contentBubble');
}, false);

[Link]('click', function(){
[Link]('boxBubble');
}, false);

// Capturing model
[Link]('click', function(){
[Link]('wrapper');
}, true);

[Link]('click', function(){
[Link]('content');
}, true);

[Link]('click', function(){
[Link]('box');
}, true);
</script>
Stop Propagation
1. [Link]()
W3C standard
IE ver. 9 and below not support.

<div style="width:100px; height: 100px; background-color: red;"></div>


<script>
/*
Problem: clicking on div (without setting eventlistener yet) trigger click event of document.

Reason: clicking on div (not having event listener yet) does cause bubbling, propagate to docu

Solution: use [Link] in child element div. The propagation is stop, document will n
*/
[Link] = function() {}
var div = [Link]('div')[0];
[Link] = function(e) {
[Link]();
// other codes.
}
</script>

2. [Link] = true;
initially, unique to IE.
now, it is available in chrome.

Event Delegation
bubbling + srcElement

use case:

1. register infinite numbers of elements with event listener.


2. add a lot of new elements into another element.
3. deals with elements with similar functions.

Benefits:
1. performance: no need to iterate through every element to register event listener.
2. flexible: adding in new elements without the need of registering event listener.

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<!--...-->
</ul>

<script>
var ul = [Link]('ul')[0];

[Link] = function(e) {
var event = e || [Link];
var target = [Link] || [Link];
[Link]([Link]);
}
</script>

Event Types

Pointer Event
types - case sensitive:

1. click: mousedown + mouseup


2. mousedown
3. mouseup
[Link] = function(){[Link]('click');}

[Link] = function(){[Link]('mousedown');}

[Link] = function(){[Link]('mouseup');}

// mousedown - first
// mouseup
// click - last

4. mousemove: pointer movement


5. contextmenu: right-click triggered menu
6. mouseover: old
7. mouseout: old
8. mousenter: new - pointer enter
9. mouseleave: new - pointer out

[Link] = function() {};


[Link] = function() {};

[Link] = function() {};


[Link] = function() {};

Note: Hover in CSS is written using JS pointer event, but more effient - it use engine.

Get mouse button keys(left, middle, right)


through [Link]

0: left
1: middle wheel
2: right

Note (DOM3 Standard):

1. recommends using mousedown and mouseup to listen to mousekeys


2. click only works for left button key.
[Link] = function (e) {
[Link](e);
}

// listening to whichever button click - left, middle, right using mousedown and mouseup
[Link] = function (e) {
[Link](e);
if ([Link] == 2) {
[Link]('right');
} else if ([Link] == 0) {
[Link]('left');
} else {
[Link]('middle');
}
}

[Link] = function (e) {


[Link](e);
if ([Link] == 2) {
[Link]('right');
} else if ([Link] == 0) {
[Link]('left');
} else {
[Link]('middle');
}
}

// only works for left click


[Link] = function (e) {
[Link](e);
if ([Link] == 2) {
[Link]('right');
} else if ([Link] == 0) {
[Link]('left');
} else {
[Link]('middle');
}
}

Drag and Drop


Note: mouse pointer frame rate > event listener frame rate, the pointer will be out of the element.
var div = [Link]('div')[0];
var posX;
var posY;
[Link]('mousedown', function (e) {
var event = e || [Link];
posX = [Link] - parseInt([Link]);
posY = [Link] - parseInt([Link]);
// set to document: to capture event even the mouse is out of elem.
// instead of div, set to document
[Link]('mousemove', move, false);
// instead of div, set to document
[Link]('mouseup', release, false);
}, false);

function move(e) {
var event = e || [Link];
[Link] = `${[Link] - posX}px`;
[Link] = `${[Link] - posY}px`;
}

function release(e) {
var event = e || [Link];
[Link]('mousemove', move, false);
}

Q: Is there any capturing method to solve pointer out of element issue during drag and drop?

[Link](); // set
[Link](); // release
// capture every event back to elem itself.

unique to IE.

Keyboard Event
1. keydown:

trigger (continously) when key is pressed.


fire for all keys except fn.

2. keypress:
trigger (continuously) when key is pressed.
fire only for keys that produces a character values (has associated ASCII code)
ASCII code returned can be converted to string letter.

[Link] = function(e) {
[Link]([Link]([Link]));
}

has been deprecated.

1. keyup: trigger only when key is released.


Note:

1. keydown/ keypress is continuously triggered once a key is hold.


2. recommend register event listener on keydown.

[Link] = function(){[Link]('keydown');}

[Link] = function(){[Link]('keypress');}

[Link] = function(){[Link]('keyup');}

// keydown - first
// keypress
// keyup - last

Comparison between keydown and keypress


keydown:

charcode is 0.
which & keycode based on what is visually on the keyboard.
can't distinguish small and big cap letters.
can't distinguish key values obtained through shift + key .
e.g., small cap alphabet - 'a' has a ASCII code of 97, but keycode & which only shows ASCII
code of 65 (which represents capital A).

keypress:

charcode has value.


only listen or works for keys that has associated ASCII code.
can accurately distinguish between small cap and big cap using ASCII code, even value obtained
through shift + key .
Text Field Related Event
Focus Event
1. focus
2. blur

<input type="text" value="enter your name" style="color: #999;" >
if([Link] === 'enter your name'){[Link] = ''; [Link]='blue'}" >

Input Event
1. input:
trigger every time a value is modified by the user.
not necessary triggered by keyboard, pasting into input field also works.

[Link] = function(e) {
[Link]([Link]);
}

Change Event
1. change: triggers when an element finished changing.

[Link] = function(e) {
[Link]([Link]);
}

Browser Window Related Event


Scrolling
1. scroll
Note: IE ver. 6 has no position: fixed CSS.

[Link] = function() {
[Link]([Link] + " " + [Link]);
}

Exercise: mirror position fixed using position absolute.

Loading
1. load
triggers when a page has fully loaded.

usually, script comes before div won't work.

[Link] event makes it works as if the script comes after div.

Anything related to downloading has load event.


<script>
[Link] = function() {
// codes...
}
</script>

<div></div>

Importance: recommend not putting main programme inside [Link]!

meaningless.
performance wise, the slowest!

Q: Why [Link] is the slowest?


when a page has been fully loaded - meaning that after parsing, after creating dom render tree, after
downloading other resources e.g., img, video,...

Use case:

1. use to alert us the moment the page has been fully loaded and running.
2. use to show advertisement after everything on the page has fully shown up.
Rendering
HTML, CSS, JS ==> display after painting
Q: How are HTML, CSS, JS related?

<!--HTML-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Position Fixed</title>
<style>
/* CSS */
div {
width:100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div>
<strong>
<em></em>
</strong>
</div>
<script>
// JS
var div = [Link]('div')[0];

</script>
</body>
</html>
// DOM
html
/ \
head body
/ | \ |
meta title style div
|
strong
|
em

Recognize and parse HTML: create DOM tree.

CSS is parsing separately, creating CSSOM tree.

DOM tree creation follows the depth-first search (dfs) principle.


parsing order: html -> head -> meta -> title -> style -> body -> div -> div -> strong -> em
downloading/ loading of resources within each element happens asynchronously.
HTML parsing won't wait for everything loading.

<div></div>
<img src="xxx">
<iframe src="yyy"></iframe>
<span></span>

DOM tree + CSSOM tree => Render tree ----- rendering engine -----> paint the page
Js dynamically change DOM tree & indirectly change CSS --------> reflow.

Reflow
recreate render tree, possessing performance issue.

avoid doing the following:

1. DOM node manipulation (insert, delete)


2. Change of position and geometry

display: none ==> display: block;


3. Recalculation: offsetWidth, offsetLeft

Repaint
acceptable

1. change of color, background color


2. etc.

Asynchronous loading
Normal js: download and execute immediately, blocking HTML and CSS parsing.

JS dynamically modify HTML and CSS.

How to asynchronously load JS?

use case:

1. load multiple js modules.


2. load js not related to rendering.
3. precaution for network problem.

1. defer
download js asynchrously in the background.

only execute when DOM is ready, when html parsing is done - this is also done asynchronously.

Note: other resources might in the process of downloading.

only works in IE.

<script src="/[Link]" defer></script>

<script src="/[Link]" defer="defer"></script>

<script src="/[Link]" defer="defer">


// can write js inside
</script>
2. async
w3c standard
chrome, IE ver.9 and above, Opera, firefox
asynchronously loading, once finished, execute immediately.
only support external script

<script src="/[Link]" async></script>

<script src="/[Link]" async="async"></script>

<script src="/[Link]" async>


// can't write js inside.
</script>

Compatibility Issue:
Neither works.

<!--Example 1: Not working-->


<script src="/[Link]" defer="defer" async="async"></script>

<!--Example 2: Might cause conflict - overriding issue-->


<script src="/[Link]" defer="defer">
// execute after parsing phase
</script>
<script src="/[Link]" async="async">
// asynchronous execute once finished loading
</script>

3. Insert Script and Callback


more common.

compatibility.

achieve asynchronous loading, and loading based on-demand.

e.g., a button on the page only 0.1% user might click, the js resource can be downloaded dynamically
by need - for optimisation performance.
// Example 1 - setTimeout
var script = [Link]('script');
[Link] = "text/javascript";
[Link] = "/[Link]"; // non-blocking download asynchronously -> send a request, and get feed

[Link](script); // execute only when insert into DOM.

// waiting for downloading js before running test() from the [Link]


setTimeout(function(){
test();
}, 1000); // 1 sec - programme run in millisec

// Example 2 - Non IE
var script = [Link]('script');
[Link] = "text/javascript";
[Link] = "/[Link]";

// [Link] ensure the js resource is downloaded before execute.


// safari chrome firefox opera supports
// IE has no load event, not support.
[Link] = function () {
test();
}

[Link](script);

// Example 3 - IE
// IE has readyState to store the status of downloading resource.
[Link] = 'loading';
[Link] = 'complete';
[Link] = 'loaded';

// event listener looking for the status change


[Link] = function() {
if ([Link] === 'complete' || [Link] === 'loaded') {
test();
}
}

// Example 4 - Compat fn
// extreme case: when having extremely fast network, resource can potentially download in an ins
function loadScript(url, callback) {
var script = [Link]('script');
[Link] = 'text/javascript';
/* [Link] = url; */ // moving this step after registering event listener.
if ([Link]) {
[Link] = function () {
if ([Link] === 'complete' || [Link] === 'loaded') {
callback();
}
}
} else {
[Link] = function () {
callback();
}
}
[Link] = url; // download resource asynchronously after finished registering event listene
[Link](script);
}

Loading Timeline

Theory
1. create Document object & parsing HTML document: [Link] = loading
2. encounter external css in link element, the browser creates thread for loading, continue parsing
html.
3. encounter external js in script element without async / defer, load js files and execute codes, and
block html parsing.
4. encounter external js with async / defer, the browser creates thread for loading, continue parsing
html.

aysnc: execute code once finished loading.


defer: execute code oncde finished html parsing.
Don't use [Link]('xxx') in asynchronous loading: it might override the page content
with xxx.
<!--Example 1: before painting
[Link] in this case doesm't clear out the content.
-->
<div style="width: 100px; height: 100px; background-color: red;"></div>
<script>
[Link]('a');
</script>
<!--Example 2: when everything has been parsed and loaded
[Link] clear the document flow, replaced by its content.
-->
<div style="width: 100px; height: 100px; background-color: red;"></div>
<script>
[Link] = function () {
[Link]('a');
}
</script>

<!--Example 3: defer and async


[Link] clear the document flow, replaced by its content.
-->
<div style="width: 100px; height: 100px; background-color: red;"></div>
<script defer>
setTimeout(function () {
[Link]('a');
}, 1000);
</script>

5. encounter img etc, parsing html as usual to create dom tree, browser asynchronously load src,
and continue html parsing.
6. HTML parsing finished (DOM & CSSOM tree has been created): [Link] =
'interactive'
7. In the meantime, execute deferred Js accordingly
8. document object triggers DOMContentLoaded event: ready to listen to events.
9. Asynchronously loaded js executed + img loaded: [Link] = 'complete' + window
object triggers load event.
10. After that, page works as expected - deal with user interaction and network event asynchronously.

Short summary:

1. create Document (HTML parsing): [Link] = loading


2. HTML parsing finished: [Link] = 'interactive'
3. HTML parsing finished + js execution finished + src loading finished:
[Link] = 'complete'

Practicals
1. [Link]
2. [Link]
3. [Link]('DOMContentLoaded', handler, useCapture)

Note: 'DOMContentLoaded' only works in addEventListener method!

check ready state of each phase.

<div></div>
<script>
[Link]([Link]); // loading
</script>
<script>
[Link]([Link]); // loading

[Link] = function() {
[Link]([Link]);// interactive
}

[Link]('DOMContentLoaded', function() {
[Link]([Link]); // interactive
}, false)

[Link] = function() {
[Link]([Link]); // complete
}
</script>

Q: Why do we put script element at the end of the body element?

Everything before script has been done parsing and form DOM structure, providing opportunity for
codes inside script element to manipulate them.

In fact, the way we wrote is not really waiting until DOM tree fully created - it is a shortcut.
Ideally, script should be loaded and executed when DOM tree is created, during which
[Link] = 'interactive' & DOMContentLoaded event has been triggered by document.

Note: The following JQuery function use the ideal concept.

$(document).ready(function(){

})

<!--Example:
Compared to [Link] = function(){}
1. looks neat and tidy
2. better performance: happens once html parsing finished, not need to wait until all src loaded

-->
<head>
<script>
// with DOMContentLoaded, it can handle DOM element in the body, despite the script is in th
[Link]('DOMContentLoaded', function() {
var div = [Link]('div')[0];
[Link](div);
}, false)
</script>
</head>
<body>
<div></div>
</body>

[Link] = function(){} should only be used when everything has been parsed and loaded. It
is the slowest method and should be used cautiously.

Note: the convention way is the fastest as it is short-cut - loaded and execute before html parsing
finishes.

BOM

You might also like