the-dom
A lightweight module providing a clean API to work with DOM nodes.
The DOM is the result of years of implementation-specific inventions kept
for backwards compatibility and patterns that simply have no place in
Javascript. This makes the DOM slow and ugly.
While we can't easily solve the performance issues, this module attempts
to make the DOM API more usable.
Install
npm install --save the-dom
Usage
You can use this module in a browser (using browserify)
or with Node.JS. Use the html()
method to import an HTML document and start working, or
the more generic import()
method to import any kind of DOM node.
Example
Consider the following HTML document:
<!doctype html>
<head></head>
<body>
<div>
<h1>Section 1</h1>
<div class="clickable">Test</div>
</div>
<div>
<h1>Section 2</h1>
<div class="clickable">Test</div>
</div>
</body>
The following script:
const dom = require('the-dom').html(document);
const body = dom.body;
body.findAll('div')
.filter(el => el.class.has('clickable'))
.on('click', () => alert('clicked!'));
would alert every time you click on a div that has the clickable
class.
The findAll()
methods returns an augmented Array that makes it possible
to filter DOM nodes based on their attributes or contents.
Reference
With the-dom
, you can:
- Find children
- Navigate in the tree
- Change classes and styles
- Listen to events
- Add and remove elements
- Change contents
- Something else?
Finding children
Given any node, you can search among its children elements using
the find()
and findAll()
methods.
body.findAll('div');
body.find('span');
The fact that find()
returns null
when there is no
matches unlike other DOM modules like jQuery will throw
errors whenever you try to call a method on it:
body.find('span').style.set('color', 'red');
This enables you to identify problems right from the source,
rather than wondering why a statement has no effect.
Navigating in the tree
You can access the element's neighborhood easily without
needing to remember complex names like nextElementSibling
.
body.find('h1').following.children[0];
Use following
, preceding
, parent
and children
to
get to the element you want quickly. You can also check whether
two elements are at a given relative position:
el1.follows(el2);
body.contains(el1);
Use precedes()
, follows()
, contains()
and contained()
to check relative positions.
Changing classes and styles
Classes and styles of an element are exposed through
a natural API that replicates Set
s and Map
s.
element.style
is a Map
of properties to their values,
so you can call
any method that can be called on a Map
on it. Similarly, element.class
is a Set
of classes
and you can call
any method of Set
on it.
if (body.class.has('landscape')) {
body.style.set('background-image', 'images/landscape.jpg');
}
Listening to events
The two usual methods for listening to events,
addEventListener()
and removeEventListener()
have been
aliased to on()
and off()
for convenience. They are
also extended so that if you give it a list of whitespace-separated
events, listeners will be set up for every event.
You can also call on()
and off()
on a list of nodes, and
listeners will be set up for each node in the list.
body.find('form#login')
.on('submit', evt => {
evt.preventDefault();
});
Adding and removing elements
To attach an element to a parent node, use child.attach(parent)
,
and for the other way round, parent.append(child)
. You can also
remove an element with remove()
. If called without any argument,
remove()
will remove the node by itself. If called with an argument,
it will remove the argument node from the element.
const div = dom.create('div');
div.text = 'Just testing element addition';
div.attach(body);
body.remove(div);
Changing contents
Aliases have been set up for textContent
and
innerHTML
to text
and html
for convenience. They
work just like the normal DOM properties.
head.find('title').text = 'New title';
Something else?
This module is not in its stable state. We have probably
missed some features or added some that aren't necessary.
If you see one, please
fill in an issue
(or maybe fix it by yourself?)
so that we can try to fix that as soon as possible.
In the meantime, please consider that due to this module being
unstable, its API might change anytime. While we are in the
0.x.x series, a minor bump means that we added or removed a feature, or changed
the way a feature works. Please review this repo before upgrading.
Contributing
Check out the contribution guide.
License
This module is dedicated to the public domain with hope that
it will be useful to others.
No rights reserved. For more information,
see the LICENSE.