In a previous article, I demonstrated how to simplify the Resize Observer API:
“`javascript
// From this
const observer = new ResizeObserver(observerFn)
function observerFn (entries) {
for (let entry of entries) {
// Do something with each entry
}
}
const element = document.querySelector(‘#some-element’)
observer.observe(element);
“`
“`javascript
// To this
const node = document.querySelector(‘#some-element’)
const obs = resizeObserver(node, {
callback({ entry }) {
// Do something with each entry
}
})
“`
Today, we’ll do the same for `MutationObserver` and `IntersectionObserver`.
### Refactoring Mutation Observer
`MutationObserver` has a similar API to `ResizeObserver`, so we can adapt the code for `resizeObserver` to `mutationObserver`.
“`javascript
export function mutationObserver(node, options = {}) {
const observer = new MutationObserver(observerFn)
const { callback, …opts } = options
observer.observe(node, opts)
function observerFn(entries) {
for (const entry of entries) {
if (options.callback) options.callback({ entry, entries, observer })
else {
node.dispatchEvent(
new CustomEvent(‘mutate’, {
detail: { entry, entries, observer },
})
)
}
}
}
}
“`
You can now use `mutationObserver` with the `callback` pattern or event listener pattern.
“`javascript
const node = document.querySelector(‘.some-element’)
// Callback pattern
const obs = mutationObserver(node, {
callback ({ entry, entries }) {
// Do what you want with each entry
}
})
// Event listener pattern
node.addEventListener(‘mutate’, event => {
const { entry } = event.detail
// Do what you want with each entry
})
“`
Much easier!
#### Disconnecting the observer
`MutationObserver` only has the `disconnect` method to stop observing elements.
“`javascript
export function mutationObserver(node, options = {}) {
// …
return {
disconnect() {
observer.disconnect()
}
}
}
“`
Use `takeRecords` before `disconnect` to get unprocessed records.
“`javascript
export function mutationObserver(node, options = {}) {
// …
return {
disconnect() {
const records = observer.takeRecords()
observer.disconnect()
if (records.length > 0) observerFn(records)
}
}
}
“`
Now you can disconnect your mutation observer easily.
“`javascript
const node = document.querySelector(‘.some-element’)
const obs = mutationObserver(/* … */)
obs.disconnect()
“`
#### MutationObserver’s observe options
`MutationObserver`’s `observe` method can take in 7 options. Each defaults to `false`.
– `subtree`: Monitors the entire subtree of nodes
– `childList`: Monitors for addition or removal of child elements
– `attributes`: Monitors for a change of attributes
– `attributeFilter`: Array of specific attributes to monitor
– `attributeOldValue`: Records the previous attribute value if changed
– `characterData`: Monitors for change in character data
– `characterDataOldValue`: Records the previous character data value
### Refactoring Intersection Observer
The API for `IntersectionObserver` is similar to other observers.
1. **Create a new observer:** with the `new` keyword. This observer takes an observer function to execute.
2. **Do something with the observed changes:** via the observer function.
3. **Observe a specific element:** using the `observe` method.
4. **(Optionally) unobserve the element:** using the `unobserve` or `disconnect` method.
`IntersectionObserver` requires options in Step 1. Here’s the code to use the `IntersectionObserver` API.
“`javascript
// Step 1: Create a new observer and pass in relevant options
const options = {/*…*/}
const observer = new IntersectionObserver(observerFn, options)
// Step 2: Do something with the observed changes
function observerFn (entries) {
for (const entry of entries) {
// Do something with entry
}
}
// Step 3: Observe the element
const element = document.querySelector(‘#some-element’)
observer.observe(element)
// Step 4 (optional): Disconnect the observer
observer.disconnect(element)
“`
We can adapt the code for `mutationObserver` to `intersectionObserver`, remembering to pass options into `IntersectionObserver`.
“`javascript
export function intersectionObserver(node, options = {}) {
const { callback, …opts } = options
const observer = new IntersectionObserver(observerFn, opts)
observer.observe(node)
function observerFn(entries) {
for (const entry of entries) {
if (options.callback) options.callback({ entry, entries, observer })
Discover more from WIREDGORILLA
Subscribe to get the latest posts sent to your email.