We use cookies to enhance your experience on the site
CodeWorlds

Advanced DOM APIs - Observers and Modern Interfaces

Monitoring systems in Jurassic Park must react to changes in real time - a dinosaur appearing in a zone, a change in the viewing area size, mutations in data structures. JavaScript offers advanced APIs for observing these changes without the need for constant polling.

IntersectionObserver - Observing Visibility

IntersectionObserver informs you when an element enters or leaves the visible area of the page. Ideal for lazy loading, infinite scroll, and scroll-triggered animations.

1// Basic usage
2const observer = new IntersectionObserver((entries) => {
3  entries.forEach(entry => {
4    if (entry.isIntersecting) {
5      console.log(entry.target.id + ' is visible');
6      entry.target.classList.add('visible');
7    } else {
8      entry.target.classList.remove('visible');
9    }
10  });
11}, {
12  threshold: 0.5,    // Requires 50% visibility
13  rootMargin: '100px' // Additional margin "before" the element
14});
15
16// Observe elements
17document.querySelectorAll('.zone-card').forEach(card => {
18  observer.observe(card);
19});
20
21// Lazy loading images
22const imageObserver = new IntersectionObserver((entries) => {
23  entries.forEach(entry => {
24    if (entry.isIntersecting) {
25      const img = entry.target;
26      img.src = img.dataset.src; // Load image
27      imageObserver.unobserve(img); // Stop observing
28    }
29  });
30});
31
32document.querySelectorAll('img[data-src]').forEach(img => {
33  imageObserver.observe(img);
34});

MutationObserver - Observing DOM Changes

MutationObserver reacts to changes in the DOM tree - adding/removing elements, attribute changes, text modifications.

1// Observe changes in a container
2const mutObserver = new MutationObserver((mutations) => {
3  mutations.forEach(mutation => {
4    if (mutation.type === 'childList') {
5      mutation.addedNodes.forEach(node => {
6        if (node.nodeType === 1) { // Element
7          console.log('Element added:', node.tagName);
8        }
9      });
10      mutation.removedNodes.forEach(node => {
11        if (node.nodeType === 1) {
12          console.log('Element removed:', node.tagName);
13        }
14      });
15    }
16    if (mutation.type === 'attributes') {
17      console.log('Attribute changed:', mutation.attributeName);
18    }
19  });
20});
21
22const container = document.getElementById('dino-list');
23mutObserver.observe(container, {
24  childList: true,   // Observe adding/removing children
25  attributes: true,  // Observe attribute changes
26  subtree: true      // Also observe descendants
27});
28
29// Stop observing
30// mutObserver.disconnect();

ResizeObserver - Observing Size Changes

ResizeObserver reacts to element size changes - not just the window, but any DOM element.

1const resizeObserver = new ResizeObserver((entries) => {
2  entries.forEach(entry => {
3    const { width, height } = entry.contentRect;
4    console.log(entry.target.id + ':', width + 'x' + height);
5
6    // Adjust layout based on size
7    if (width < 400) {
8      entry.target.classList.add('compact');
9    } else {
10      entry.target.classList.remove('compact');
11    }
12  });
13});
14
15resizeObserver.observe(document.getElementById('dashboard'));

Web Storage API

localStorage and sessionStorage allow you to store data in the browser.

1// localStorage - data persists after closing the browser
2localStorage.setItem('parkSettings', JSON.stringify({
3  theme: 'dark',
4  alertLevel: 3,
5  lastVisit: Date.now()
6}));
7
8const settings = JSON.parse(localStorage.getItem('parkSettings'));
9console.log(settings.theme); // 'dark'
10
11// sessionStorage - data disappears after closing the tab
12sessionStorage.setItem('currentZone', 'A');
13
14// Listening for changes (between tabs!)
15window.addEventListener('storage', (event) => {
16  console.log('Changed:', event.key);
17  console.log('Old value:', event.oldValue);
18  console.log('New value:', event.newValue);
19});
20
21// Removing
22localStorage.removeItem('parkSettings');
23localStorage.clear(); // Remove everything

Clipboard API

1// Copying text
2async function copyToClipboard(text) {
3  try {
4    await navigator.clipboard.writeText(text);
5    console.log('Copied:', text);
6  } catch (err) {
7    console.error('Copy error:', err);
8  }
9}
10
11// Pasting text
12async function pasteFromClipboard() {
13  try {
14    const text = await navigator.clipboard.readText();
15    return text;
16  } catch (err) {
17    console.error('No clipboard access');
18  }
19}
20
21// Copy button with feedback
22const copyBtn = document.getElementById('copy-btn');
23copyBtn.addEventListener('click', async () => {
24  const data = document.getElementById('sensor-data').textContent;
25  await copyToClipboard(data);
26  copyBtn.textContent = 'Copied!';
27  setTimeout(() => copyBtn.textContent = 'Copy', 2000);
28});

History API and Navigation

1// Adding a history entry (without page reload)
2history.pushState({ zone: 'A' }, '', '/park/zone-a');
3history.pushState({ zone: 'B' }, '', '/park/zone-b');
4
5// Responding to the "Back" button
6window.addEventListener('popstate', (event) => {
7  if (event.state) {
8    console.log('Returning to zone:', event.state.zone);
9    loadZone(event.state.zone);
10  }
11});
12
13// Replacing the current entry (without adding a new one)
14history.replaceState({ zone: 'A', view: 'map' }, '', '/park/zone-a?view=map');

DocumentFragment - DOM Optimization

Adding many elements at once is expensive. DocumentFragment allows you to prepare elements "outside the DOM" and add them in a single operation:

1// WITHOUT fragment - each appendChild causes a reflow
2const list = document.getElementById('dino-list');
3const dinosaurs = ['Rex', 'Blue', 'Brachio', 'Stego', 'Trike'];
4
5// BAD - 5 separate DOM operations
6dinosaurs.forEach(name => {
7  const li = document.createElement('li');
8  li.textContent = name;
9  list.appendChild(li); // 5x reflow!
10});
11
12// GOOD - DocumentFragment
13const fragment = document.createDocumentFragment();
14dinosaurs.forEach(name => {
15  const li = document.createElement('li');
16  li.textContent = name;
17  fragment.appendChild(li); // Operation "in memory"
18});
19list.appendChild(fragment); // 1x reflow!

"Advanced DOM APIs are the radar and early warning systems of the Park" - Ray Arnold summarizes. "IntersectionObserver is a thermal camera, MutationObserver is an alarm system, and ResizeObserver is an adaptive control screen. Use them wisely!"

Go to CodeWorlds