The DOM API is really hard to use, each API stinks and has a long source code link: github.com/huyiling111… We provide a global window.dom object
// How to declare an object as a global object? // Mount the object to windowCopy the code
Next, “add, delete, change and check” are explained
First, add elements, add nodes
Create node dom.create(<div>hi</div>
)
The DOM API requires document.createElement(‘div’), div. InnerText = ‘hi’ and we only need one sentence here, dom.create(
)
// Target effect
// Type create("
hello
")
// Automatically create div and span
// Write the string directly into InnerHTML
// We use template because this tag can hold all tags,
// div can't put a tag, whereas template can
create(string) {
const container = document.createElement("template")
container.innerHTML = String.prototype.trim.call(string) // Remove extra Spaces
return container.content.firstChild
},
Copy the code
Two keys:
- The template tag is used as the Container because it can hold all the tags
- Trim () to remove extra whitespace because whitespace also counts as nodes and may interfere with our results
Add brother dom.after(node, node2)
Ideas: Since DOM only provides an Insertbefore operation, not an insertAfter operation, So we need to use a little bit of dark magic let’s say we have two nodes div1 — > div3 and we want to add div2 after div1, which is equivalent to inserting div2 before div3 so we have node.nextsibling to get the next node of the current node, InsertBefore again
after(node, newNode) {
// The goal is to insert node2 after Node
// But DOM only provides an insertBefore interface
/ / 1 - > 3
// Inserting 2 after 1 is equivalent to inserting 2 before 3
// So we switch to inserting node2 before the next node of node
node.parentNode.insertBefore(newNode, node.nextSibling)
},
Copy the code
Add brother dom.before(node, node2)
Find the father node, then insertBefore
before(node, newNode) {
node.parentNode.insertBefore(newNode, node)
},
Copy the code
Add child dom. Append (parent, child)
Find the parent node (appendChild)
append(parent, node) {
parent.appendChild(node)
},
Copy the code
New dad dom.wrap(<div></div>
)
wrap(node, newParent) {
// put Newparent in front of node
// Add node append to newparent
// Target: div1
/ / left -- -- -- -- > div2
/ / div1
/ / left -- -- -- -- > div3
/ / left -- -- -- -- > div2
Div3. AppendChild (div2)
node.before.call(null, node, newParent)
newParent.append(node)
},
Copy the code
Usage:
const div3 = dom.create('<div id="parent"></div>')
dom.wrap(test, div3)
Copy the code
2. Delete a node
Remove node dom.remove(node)
RemoveChild = removeChild
remove(node) {
node.parentNode.removeChild(node)
return node
},
Copy the code
Delete descendant dom.empty(parent)
An easy way to think about it is to loop through Parent. ChildNodes and remove each time but there is a pit called childNodes. Length and the length changes in real time so here we use a while loop as long as the node has children, I just keep iterating
// empty deletes all child nodes
// pit: childNodes. Length The length changes each time
empty(node) {
// const {childNodes} = node is equivalent to const childNodes = node.childnodes
const array = []
let x = node.firstChild
while (x) {
array.push(dom.remove(node.firstChild))
x = node.firstChild
}
return array
},
Copy the code
Three, modify,
Read property dom.attr(node, ‘title’,?)
So we’re using overloading, so we’re doing different things when the function has different parameters when there’s only two parameters, we’re reading the property, we’re returning the property when there’s three parameters, we’re modifying the property and we’re using getter and setter design patterns because we can read and write the property at the same time
// Implement different functions depending on the number of arguments. This is called function overloading
attr(node, name, value) {
if (arguments.length === 3) {
node.setAttribute(name, value)
} else if (arguments.length === 2) {
return node.getAttribute(name)
}
},
Copy the code
Method of use
test
// the title attribute of #test is hello world
dom.attr(test, 'title'.'hello world') // Modify attributes
const title = dom.attr(test, 'title') / / read the properties
console.log(`title: ${title}`)
Copy the code
Read and write text content dom.text(node,?)
InnerText = string if there is only one parameter, we return node.innerText. If there are two parameters, we write the innerText
text(node, string) {
if (arguments.length === 2) {
// Adapt to different browsers
if ('innerText' in node) { //ie
node.innerText = string
} else { // firefox / chrome
node.textContent = string
}
} else if (arguments.length === 1) {
if ('innerText' in node) { //ie
return node.innerText
} else { // firefox / chrome
return node.textContent
}
}
},
Copy the code
Read and write HTML content dom.html(node,?)
html(node, string) {
if (arguments.length === 2) {
/ / modify
node.innerHTML = string
} else if (arguments.length === 1) {
// Get the content
return node.innerHTML
}
},
Copy the code
Modify dom.style(node, {color:’red’})
Node.style. color = ‘red’ Note that there are three cases where the style function will be used
- Dom.style (node, ‘color’, ‘red’) sets a property
- Dom.style (node, ‘color’) reads a property
- Dom.style (node, {‘color’: ‘red’, ‘border’: ‘1px solid black’}) pass an object and set multiple properties simultaneously
So we need to deal with different parameters, again using the adapter pattern first we need to determine the number of parameters,
- Node.style. color = ‘red’
- If it is 2
- If the second argument is a string
- Typeof XXXXX === ‘string’
- If the second argument is a string
typeof name === 'string'
Copy the code
- Then return node.style[name]Copy the code
- If the second argument is an object
- Instanceof: XXX instanceof Object === true
- And then iterate over the object
- Iterate over an object
for (let key in object) {
......
}
Copy the code
Implementation code:
/ / change style
style(node, name, value) {
if (arguments.length === 3) {
// dom.style(div, 'color', 'red')
node.style[name] = value
} else if (arguments.length === 2) {
if (typeof name === 'string') {
//dom.style(test, 'border')
// Get a CSS property
return node.style[name]
}
if (name instanceof Object) {
//dom.style(test, {border: '1px solid red', color: 'blue'})
let object = name
for (let key in object) {
// key : border / color
// node.style.border = ....
// node.style.color = ...
node.style[key] = object[key]
}
}
}
},
Copy the code
Add class dom.class.add(node, ‘blue’)
Node.classlist.add (class)
class: {
add(node, className) {
node.classList.add(className)
},
remove(node, className) {
node.classList.remove(className)
},
has(node, className) {
return node.classList.contains(className)
}
},
Copy the code
Note: The contains method is used to find if an element’s classlist contains a class
Add event listener dom.on(node, ‘click’, fn)
on(node, eventName, fn) {
node.removeEventListener(eventName, fn)
},
Copy the code
Remove event listener dom.off(node, ‘click’, fn)
off(node, eventName, fn) {
node.removeEventListener(eventName, fn)
},
Copy the code
Four,
Get tags or tags dom.find(‘ selector ‘, scope)
Document. QuerySelector (‘selector’)
// Get the element according to the selector
find(selector, scope) {
return (scope || document).querySelectorAll(selector)
},
Copy the code
Get the parent element dom.parent(node)
parent(node) {
return node.parentNode
},
Copy the code
Get the child element dom.children(node)
children(node) {
return node.children
},
Copy the code
Gets the dom.siblings(node) element
Find the dad node and delete the element that’s me
siblings(node) {
Of all my parents' children, either I am my brother or my sister
return Array.from(node.parentNode.children).filter(n= >n ! == node) },Copy the code
Next (node)
Note: while (x && x.nodetype! == 1) means if x exists and x is not an HTML element node, we go on to the next node until we find a node that is an HTML element node and the reason for this is that nodes contain HTML tags, text, comments, etc., so we need to do this to make sure we find an HTML tag
next(node) {
let x = node.nextSibling
while(x && x.nodeType ! = =1) {
// x is not the desired HTML tag
x = x.nextSibling
}
return x
},
Copy the code
Get older dom. Previous (node)
prev(node) {
let x = node.previousSibling
while(x && x.nodeType ! = =1) {
// x is not the desired HTML tag
x = x.previousSibling
}
return x
}
Copy the code
Dom.each (Nodes, fn)
each(nodelist, fn) {
for (let i = 0; i < nodelist.length; i++) {
fn.call(null, nodelist[i])
}
}
Copy the code
Dom. Index (node)
index(node) {
let nodeList = dom.children(dom.parent(node))
let i
for (i = 0; i < nodeList.length; i++) {
console.log(nodeList[i])
if (nodeList[i] === node) {
return i
}
}
return -1 // Not found
}
Copy the code