avatar
Siz Long

My name is Siz. I am a computer science graduate student specializing in backend development with Golang and Python, seeking opportunities in innovative tech projects. My personal website is me.longsizhuo.com .Connect with me on LinkedIn: https://www.linkedin.com/in/longsizhuo/.

  • Resume
  • Archives
  • Categories
  • Photos
  • Music



{{ date }}

{{ time }}

avatar
Siz Long

My name is Siz. I am a computer science graduate student specializing in backend development with Golang and Python, seeking opportunities in innovative tech projects. My personal website is me.longsizhuo.com .Connect with me on LinkedIn: https://www.linkedin.com/in/longsizhuo/.

  • 主页
  • Resume
  • Archives
  • Categories
  • Photos
  • Music

Browser APIs & DOM Manipulation

  2023-06-08        
字数统计: 4.6k字   |   阅读时长: 29min

Browser APIs & DOM Manipulation

Modern web browsers provide a rich set of APIs (Application Programming Interfaces) that allow JavaScript to interact with the browser environment and manipulate web page content. This guide covers the DOM (Document Object Model) and various browser APIs that are essential for frontend development.

The Document Object Model (DOM)

The DOM is a programming interface for HTML documents. It represents the page as nodes and objects that JavaScript can interact with.

DOM Structure

The DOM represents an HTML document as a tree of nodes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
document
└── html
├── head
│ ├── title
│ ├── meta
│ └── link
└── body
├── header
│ └── nav
├── main
│ ├── h1
│ ├── p
│ └── div
└── footer

Selecting DOM Elements

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// By ID (returns a single element)
const header = document.getElementById('header');

// By class name (returns a live HTMLCollection)
const paragraphs = document.getElementsByClassName('paragraph');

// By tag name (returns a live HTMLCollection)
const divs = document.getElementsByTagName('div');

// By CSS selector (returns the first match)
const mainSection = document.querySelector('main');

// By CSS selector (returns all matches as a static NodeList)
const buttons = document.querySelectorAll('.btn');

// Finding elements relative to another element
const firstListItem = document.querySelector('ul li');
const list = firstListItem.parentElement;
const nextItem = firstListItem.nextElementSibling;
const allItems = list.children;

Manipulating DOM Elements

Creating Elements

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Create a new element
const newDiv = document.createElement('div');

// Add content to the element
newDiv.textContent = 'Hello, World!';
// or
newDiv.innerHTML = '<span>Hello</span>, World!';

// Add classes
newDiv.className = 'container highlight';
// or
newDiv.classList.add('container');
newDiv.classList.add('highlight');
newDiv.classList.remove('highlight');
newDiv.classList.toggle('active');
newDiv.classList.contains('container'); // true

// Set attributes
newDiv.id = 'main-container';
newDiv.setAttribute('data-test', 'value');
newDiv.getAttribute('id'); // 'main-container'
newDiv.hasAttribute('data-test'); // true
newDiv.removeAttribute('data-test');

// Set styles
newDiv.style.color = 'red';
newDiv.style.backgroundColor = 'white';
newDiv.style.cssText = 'color: red; background-color: white;';

Modifying the DOM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Append elements
document.body.appendChild(newDiv);

// Insert before a specific element
const referenceElement = document.getElementById('reference');
document.body.insertBefore(newDiv, referenceElement);

// Modern insertion methods
parentElement.append(element1, element2); // Adds at the end, accepts multiple nodes
parentElement.prepend(element); // Adds at the beginning
referenceElement.before(element); // Adds before the reference element
referenceElement.after(element); // Adds after the reference element
referenceElement.replaceWith(element); // Replaces the reference element

// Remove elements
element.remove(); // Modern way
// or
element.parentElement.removeChild(element); // Old way, more compatible

Cloning Elements

1
2
3
// Clone an element (false = without children, true = with children)
const clone = element.cloneNode(false);
const deepClone = element.cloneNode(true);

DOM Properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Text content
element.textContent = 'New text'; // Sets text (safer, no HTML parsing)
element.innerText = 'New text'; // Similar, but respects CSS styling
element.innerHTML = '<b>Bold text</b>'; // Sets HTML content (careful with XSS)

// Element dimensions and position
const rect = element.getBoundingClientRect(); // Position relative to viewport
console.log(rect.width, rect.height, rect.top, rect.left);

element.offsetWidth; // Width including padding and border
element.offsetHeight; // Height including padding and border
element.clientWidth; // Width including padding but not border
element.clientHeight; // Height including padding but not border

// Scroll position
element.scrollTop; // Pixels scrolled vertically
element.scrollLeft; // Pixels scrolled horizontally
element.scrollTo(0, 0); // Scroll to specific coordinates
element.scrollIntoView(); // Scroll the element into view

DOM Events

DOM events allow JavaScript to register different event handlers on elements in an HTML document.

Event Handling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Adding event listeners
element.addEventListener('click', function(event) {
console.log('Element clicked!', event);
});

// With arrow function
element.addEventListener('mouseover', (event) => {
console.log('Mouse over!');
});

// Removing event listeners (reference to the original function needed)
function handleClick(event) {
console.log('Clicked!');
}

element.addEventListener('click', handleClick);
element.removeEventListener('click', handleClick);

// Older methods (avoid using)
element.onclick = function() {
console.log('Clicked!');
};

Event Object Properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
element.addEventListener('click', function(event) {
// General event properties
console.log(event.type); // "click"
console.log(event.target); // Element that triggered the event
console.log(event.currentTarget); // Element the listener is attached to
console.log(event.timeStamp); // Time the event was created

// Mouse event properties
console.log(event.clientX, event.clientY); // Coordinates relative to viewport
console.log(event.pageX, event.pageY); // Coordinates relative to document
console.log(event.button); // Mouse button pressed

// Keyboard event properties
console.log(event.key); // Key value ("a", "Enter", etc.)
console.log(event.code); // Physical key code ("KeyA", "Enter", etc.)
console.log(event.ctrlKey, event.shiftKey, event.altKey); // Modifier keys
});

Event Propagation

Events in the DOM propagate in three phases:

  1. Capture Phase: From the root down to the target
  2. Target Phase: The event reaches the target
  3. Bubbling Phase: From the target back up to the root
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Capturing phase (third parameter true)
parent.addEventListener('click', function(event) {
console.log('Parent captured!');
}, true);

// Bubbling phase (default behavior)
child.addEventListener('click', function(event) {
console.log('Child bubbled!');

// Stop propagation to parent elements
event.stopPropagation();

// Prevent default browser behavior
event.preventDefault();
});

// Event delegation (handling events for multiple elements)
document.getElementById('todo-list').addEventListener('click', function(event) {
// Check if clicked element is a list item
if (event.target.tagName === 'LI') {
event.target.classList.toggle('completed');
}
});

Common DOM Events

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Mouse events
element.addEventListener('click', handler); // Single click
element.addEventListener('dblclick', handler); // Double click
element.addEventListener('mouseover', handler); // Mouse enters element
element.addEventListener('mouseout', handler); // Mouse leaves element
element.addEventListener('mousedown', handler); // Mouse button pressed
element.addEventListener('mouseup', handler); // Mouse button released
element.addEventListener('mousemove', handler); // Mouse moved

// Keyboard events
element.addEventListener('keydown', handler); // Key pressed
element.addEventListener('keyup', handler); // Key released
element.addEventListener('keypress', handler); // Key pressed (character keys)

// Form events
form.addEventListener('submit', handler); // Form submitted
input.addEventListener('focus', handler); // Element received focus
input.addEventListener('blur', handler); // Element lost focus
input.addEventListener('change', handler); // Value changed (after blur)
input.addEventListener('input', handler); // Value changed (immediately)

// Document/Window events
window.addEventListener('load', handler); // Page fully loaded
document.addEventListener('DOMContentLoaded', handler); // DOM fully loaded
window.addEventListener('resize', handler); // Window resized
window.addEventListener('scroll', handler); // Window scrolled

Custom Events

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Creating a custom event
const customEvent = new CustomEvent('userLoggedIn', {
detail: { userId: 123, username: 'john_doe' },
bubbles: true,
cancelable: true
});

// Dispatching the event
document.dispatchEvent(customEvent);

// Listening for the custom event
document.addEventListener('userLoggedIn', function(event) {
console.log('User logged in:', event.detail.username);
});

Browser Storage APIs

Browsers provide several ways to store data on the client side.

Local Storage

Data persists until explicitly cleared. Available across browser sessions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Store data
localStorage.setItem('username', 'john_doe');
localStorage.setItem('preferences', JSON.stringify({ theme: 'dark', fontSize: 16 }));

// Retrieve data
const username = localStorage.getItem('username');
const preferences = JSON.parse(localStorage.getItem('preferences'));

// Remove specific item
localStorage.removeItem('username');

// Clear all data
localStorage.clear();

// Storage event (fires when storage changes in another tab/window)
window.addEventListener('storage', function(event) {
console.log('Storage changed:', event.key, event.oldValue, event.newValue);
});

Session Storage

Similar to localStorage, but data is cleared when the session ends (window/tab closed).

1
2
3
4
5
// Same API as localStorage
sessionStorage.setItem('sessionId', 'abc123');
const sessionId = sessionStorage.getItem('sessionId');
sessionStorage.removeItem('sessionId');
sessionStorage.clear();

Cookies

Traditional way to store small amounts of data. Sent with HTTP requests.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Set a cookie
document.cookie = "username=john_doe; expires=Fri, 31 Dec 2023 23:59:59 GMT; path=/; Secure; SameSite=Strict";

// Read all cookies
const allCookies = document.cookie; // "username=john_doe; sessionId=abc123"

// Parse cookies
function getCookie(name) {
const cookies = document.cookie.split('; ');
for (const cookie of cookies) {
const [cookieName, cookieValue] = cookie.split('=');
if (cookieName === name) {
return cookieValue;
}
}
return null;
}

// Delete a cookie (set expiration in the past)
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;";

IndexedDB

A more powerful, asynchronous client-side storage API for larger amounts of structured data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Open a database
const request = indexedDB.open('MyDatabase', 1);

// Create schema (called when DB is created or version changes)
request.onupgradeneeded = function(event) {
const db = event.target.result;
const store = db.createObjectStore('users', { keyPath: 'id' });
store.createIndex('by_name', 'name', { unique: false });
};

// On success
request.onsuccess = function(event) {
const db = event.target.result;

// Start a transaction
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');

// Add data
store.add({ id: 1, name: 'John', email: 'john@example.com' });

// Get data
const getRequest = store.get(1);
getRequest.onsuccess = function() {
console.log('User:', getRequest.result);
};

// Transaction complete
transaction.oncomplete = function() {
console.log('Transaction completed');
db.close();
};
};

// On error
request.onerror = function(event) {
console.error('Database error:', event.target.error);
};

Network Requests

XMLHttpRequest (Legacy)

The older way to make HTTP requests, still supported by all browsers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const xhr = new XMLHttpRequest();

xhr.open('GET', 'https://api.example.com/data', true);

xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
const data = JSON.parse(xhr.responseText);
console.log('Data:', data);
} else {
console.error('Request failed with status:', xhr.status);
}
};

xhr.onerror = function() {
console.error('Request failed');
};

xhr.send();

// POST request with data
const postXhr = new XMLHttpRequest();
postXhr.open('POST', 'https://api.example.com/submit', true);
postXhr.setRequestHeader('Content-Type', 'application/json');
postXhr.send(JSON.stringify({ name: 'John', email: 'john@example.com' }));

Fetch API (Modern)

The modern way to make HTTP requests, based on Promises.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Basic GET request
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json(); // Parse as JSON
})
.then(data => {
console.log('Data:', data);
})
.catch(error => {
console.error('Fetch error:', error);
});

// POST request with options
fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
body: JSON.stringify({ name: 'John', email: 'john@example.com' })
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('Error:', error));

// Using async/await
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log('Data:', data);
return data;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}

// Fetch with abort controller
const controller = new AbortController();
const signal = controller.signal;

fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.then(data => console.log('Data:', data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
});

// Abort the fetch after 5 seconds
setTimeout(() => controller.abort(), 5000);

Geolocation API

Access the user’s geographical location.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Check if geolocation is supported
if ('geolocation' in navigator) {
// Get current position
navigator.geolocation.getCurrentPosition(
// Success callback
function(position) {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
console.log(`Location: ${latitude}, ${longitude}`);

// Other available data
console.log('Accuracy:', position.coords.accuracy, 'meters');
console.log('Altitude:', position.coords.altitude);
console.log('Timestamp:', position.timestamp);
},
// Error callback
function(error) {
switch(error.code) {
case error.PERMISSION_DENIED:
console.error('User denied geolocation permission');
break;
case error.POSITION_UNAVAILABLE:
console.error('Location information unavailable');
break;
case error.TIMEOUT:
console.error('Location request timed out');
break;
default:
console.error('Unknown error:', error.message);
}
},
// Options
{
enableHighAccuracy: true, // More accurate position
timeout: 5000, // Time to wait for response in ms
maximumAge: 0 // Don't use cached position
}
);

// Watch position (gets updates when user moves)
const watchId = navigator.geolocation.watchPosition(
position => console.log(`Updated location: ${position.coords.latitude}, ${position.coords.longitude}`),
error => console.error('Error watching position:', error),
{ enableHighAccuracy: true }
);

// Stop watching
// navigator.geolocation.clearWatch(watchId);
} else {
console.log('Geolocation is not supported by this browser');
}

History API

Manipulate the browser history.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Navigate back
history.back();

// Navigate forward
history.forward();

// Go to a specific point in history
history.go(-2); // Back 2 pages
history.go(1); // Forward 1 page

// Add a new entry to the browser history
// This updates the URL without reloading the page
history.pushState({ pageId: 123 }, 'Page Title', '/new-url');

// Replace the current history entry
history.replaceState({ pageId: 124 }, 'New Title', '/updated-url');

// Listen for navigation events (back/forward buttons)
window.addEventListener('popstate', function(event) {
console.log('Navigation occurred:', event.state);
});

Web Storage API

Web Storage (localStorage and sessionStorage) is covered in the Browser Storage section above.

Canvas API

Create and manipulate graphics and animations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Get canvas element
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// Set canvas dimensions
canvas.width = 500;
canvas.height = 300;

// Basic drawing
ctx.fillStyle = 'blue'; // Set fill color
ctx.fillRect(10, 10, 100, 50); // Draw filled rectangle

ctx.strokeStyle = 'red'; // Set stroke color
ctx.lineWidth = 5; // Set line width
ctx.strokeRect(150, 10, 100, 50); // Draw rectangle outline

// Draw a line
ctx.beginPath();
ctx.moveTo(10, 100);
ctx.lineTo(200, 150);
ctx.stroke();

// Draw a circle
ctx.beginPath();
ctx.arc(300, 100, 30, 0, Math.PI * 2); // x, y, radius, startAngle, endAngle
ctx.fill();

// Draw text
ctx.font = '20px Arial';
ctx.fillStyle = 'black';
ctx.fillText('Hello, Canvas!', 10, 200);

// Draw image
const img = new Image();
img.onload = function() {
ctx.drawImage(img, 350, 150, 100, 100); // image, x, y, width, height
};
img.src = 'image.jpg';

// Animation
let x = 0;
function animate() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);

// Draw a moving rectangle
ctx.fillRect(x, 50, 50, 50);

// Update position
x = (x + 2) % canvas.width;

// Request next frame
requestAnimationFrame(animate);
}
animate();

Web Audio API

Process and synthesize audio.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Create audio context
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();

// Play a simple tone
function playTone(frequency = 440, duration = 1) {
// Create oscillator
const oscillator = audioCtx.createOscillator();
oscillator.type = 'sine'; // sine, square, sawtooth, triangle
oscillator.frequency.value = frequency; // frequency in Hz

// Create gain node (for volume control)
const gainNode = audioCtx.createGain();
gainNode.gain.value = 0.5; // 50% volume

// Connect the nodes
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);

// Start and stop
oscillator.start();
oscillator.stop(audioCtx.currentTime + duration);
}

// Play a 440Hz tone for 1 second when clicked
document.getElementById('playButton').addEventListener('click', () => {
playTone(440, 1);
});

// Load and play an audio file
async function playAudio(url) {
// Fetch the file
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();

// Decode the audio
const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);

// Create buffer source
const source = audioCtx.createBufferSource();
source.buffer = audioBuffer;

// Connect to destination
source.connect(audioCtx.destination);

// Play
source.start();
}

// Play audio file when clicked
document.getElementById('playSound').addEventListener('click', () => {
playAudio('sound.mp3');
});

WebRTC

Enables real-time communication in the browser.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Basic WebRTC peer connection setup
const configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
const peerConnection = new RTCPeerConnection(configuration);

// Handle ICE candidates
peerConnection.onicecandidate = event => {
if (event.candidate) {
// Send the candidate to the remote peer via your signaling server
sendToSignalingServer({ type: 'ice-candidate', candidate: event.candidate });
}
};

// Handle connection state changes
peerConnection.onconnectionstatechange = event => {
console.log('Connection state:', peerConnection.connectionState);
};

// Handle receiving streams
peerConnection.ontrack = event => {
const remoteVideo = document.getElementById('remoteVideo');
if (remoteVideo.srcObject !== event.streams[0]) {
remoteVideo.srcObject = event.streams[0];
}
};

// Get local media
async function startVideoCall() {
try {
// Get local stream
const localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});

// Display local video
const localVideo = document.getElementById('localVideo');
localVideo.srcObject = localStream;

// Add tracks to the peer connection
localStream.getTracks().forEach(track => {
peerConnection.addTrack(track, localStream);
});

// Create and send offer (if initiator)
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);

// Send the offer to the remote peer via your signaling server
sendToSignalingServer({ type: 'offer', offer });

} catch (error) {
console.error('Error starting video call:', error);
}
}

// Function to handle received offers, answers, and ICE candidates
// (You would implement this to work with your signaling server)
function handleSignalingMessage(message) {
switch(message.type) {
case 'offer':
peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
peerConnection.createAnswer()
.then(answer => peerConnection.setLocalDescription(answer))
.then(() => sendToSignalingServer({
type: 'answer',
answer: peerConnection.localDescription
}));
break;
case 'answer':
peerConnection.setRemoteDescription(new RTCSessionDescription(message.answer));
break;
case 'ice-candidate':
peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
break;
}
}

Web Workers

Run JavaScript in background threads.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Create a worker
const worker = new Worker('worker.js');

// Send message to worker
worker.postMessage({ action: 'calculate', data: [1, 2, 3, 4, 5] });

// Receive message from worker
worker.onmessage = function(event) {
console.log('Result from worker:', event.data);
};

// Handle errors
worker.onerror = function(error) {
console.error('Worker error:', error.message);
};

// Terminate worker when done
function terminateWorker() {
worker.terminate();
}

// Content of worker.js:
/*
// Listen for messages
self.onmessage = function(event) {
const { action, data } = event.data;

if (action === 'calculate') {
// Perform calculation
const result = data.reduce((sum, num) => sum + num, 0);

// Send result back
self.postMessage(result);
}
};

// Handle errors
self.onerror = function(error) {
console.error('Worker internal error:', error.message);
};
*/

Service Workers

A type of web worker that acts as a proxy server between web applications, the browser, and the network.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Register a service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}

// Check if a service worker is active
navigator.serviceWorker.ready
.then(registration => {
console.log('Service Worker is active');
});

// Send a message to the service worker
navigator.serviceWorker.controller.postMessage({
type: 'CACHE_NEW_ROUTE',
payload: '/new-route'
});

// Listen for messages from the service worker
navigator.serviceWorker.addEventListener('message', event => {
console.log('Message from Service Worker:', event.data);
});

// Content of service-worker.js:
/*
// Service Worker installation
self.addEventListener('install', event => {
// Perform install steps (like caching resources)
event.waitUntil(
caches.open('v1')
.then(cache => {
return cache.addAll([
'/',
'/index.html',
'/styles.css',
'/script.js',
'/image.jpg'
]);
})
);
});

// Service Worker activation (cleanup old caches)
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(cacheName => {
return cacheName !== 'v1';
}).map(cacheName => {
return caches.delete(cacheName);
})
);
})
);
});

// Intercept fetch requests
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// Cache hit - return response
if (response) {
return response;
}

// Clone the request
const fetchRequest = event.request.clone();

return fetch(fetchRequest).then(response => {
// Check if valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}

// Clone the response
const responseToCache = response.clone();

caches.open('v1')
.then(cache => {
cache.put(event.request, responseToCache);
});

return response;
});
})
);
});

// Handle messages from the main thread
self.addEventListener('message', event => {
console.log('Message received in SW:', event.data);
// Respond to the message
event.source.postMessage('Message received!');
});
*/

Intersection Observer

Detect when an element is visible in the viewport.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Create the observer
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Element is visible:', entry.target);

// Load images when they become visible
if (entry.target.dataset.src) {
entry.target.src = entry.target.dataset.src;
entry.target.removeAttribute('data-src');
// Stop observing the element after loading
observer.unobserve(entry.target);
}
}
});
}, {
root: null, // Use the viewport as root
rootMargin: '0px', // No margin
threshold: 0.1 // 10% of the element must be visible
});

// Observe multiple elements
document.querySelectorAll('.lazy-load-image').forEach(image => {
observer.observe(image);
});

// Lazy loading example:
/*
<img class="lazy-load-image" src="placeholder.jpg" data-src="actual-image.jpg" alt="Lazy loaded image">
*/

Mutation Observer

Watch for changes in the DOM.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Create a mutation observer
const observer = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
console.log('Child nodes added or removed:', mutation.addedNodes, mutation.removedNodes);
} else if (mutation.type === 'attributes') {
console.log(`Attribute '${mutation.attributeName}' changed:`,
mutation.target.getAttribute(mutation.attributeName));
}
});
});

// Start observing an element
const targetElement = document.getElementById('observed-element');
observer.observe(targetElement, {
childList: true, // Watch for changes to child elements
attributes: true, // Watch for attribute changes
characterData: true, // Watch for text content changes
subtree: true, // Also watch all descendants
attributeOldValue: true, // Record old attribute values
characterDataOldValue: true // Record old text content
});

// Stop observing
function stopObserving() {
observer.disconnect();
}

Web Animations API

Create and control animations in JavaScript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Get element to animate
const element = document.getElementById('animated-element');

// Create animation
const animation = element.animate([
// Keyframes
{ transform: 'translateX(0px)', opacity: 1 },
{ transform: 'translateX(100px)', opacity: 0.5, offset: 0.8 }, // 80% mark
{ transform: 'translateX(200px)', opacity: 0 }
], {
// Timing options
duration: 2000, // 2 seconds
easing: 'ease-in-out',
delay: 500, // 0.5 second delay
iterations: 3, // Play 3 times
direction: 'alternate', // Alternate direction on each iteration
fill: 'forwards' // Keep final state
});

// Animation controls
animation.pause(); // Pause
animation.play(); // Resume
animation.reverse(); // Play in reverse
animation.finish(); // Jump to end
animation.cancel(); // Stop and remove effects

// Animation events
animation.onfinish = () => {
console.log('Animation finished');
};

animation.oncancel = () => {
console.log('Animation cancelled');
};

// Get animation state
console.log('Current time:', animation.currentTime);
console.log('Playback rate:', animation.playbackRate);

// Change playback speed
animation.playbackRate = 2; // Double speed

Drag and Drop API

Enable drag and drop functionality.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Make an element draggable
const draggableElement = document.getElementById('draggable');
draggableElement.draggable = true;

// Drag events on the draggable element
draggableElement.addEventListener('dragstart', event => {
console.log('Drag started');

// Set data to be dragged
event.dataTransfer.setData('text/plain', draggableElement.id);

// Set drag image (optional)
const dragImage = new Image();
dragImage.src = 'dragicon.png';
event.dataTransfer.setDragImage(dragImage, 10, 10);

// Set drag effect
event.dataTransfer.effectAllowed = 'move'; // 'copy', 'move', 'link', 'copyMove', etc.
});

draggableElement.addEventListener('dragend', event => {
console.log('Drag ended');
});

// Set up drop target
const dropTarget = document.getElementById('drop-target');

// Prevent default to allow drop
dropTarget.addEventListener('dragover', event => {
event.preventDefault();
// Change appearance to indicate valid drop target
dropTarget.classList.add('drag-over');
});

// Handle when drag enters/leaves target
dropTarget.addEventListener('dragenter', event => {
event.preventDefault();
dropTarget.classList.add('drag-over');
});

dropTarget.addEventListener('dragleave', () => {
dropTarget.classList.remove('drag-over');
});

// Handle the drop
dropTarget.addEventListener('drop', event => {
event.preventDefault();
dropTarget.classList.remove('drag-over');

// Get the dragged data
const id = event.dataTransfer.getData('text/plain');
const draggedElement = document.getElementById(id);

// Append the element to the drop target
dropTarget.appendChild(draggedElement);

console.log('Element dropped');
});

File API

Working with files from the user’s filesystem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// File input element
const fileInput = document.getElementById('file-input');

// Handle file selection
fileInput.addEventListener('change', event => {
const files = event.target.files;

for (const file of files) {
console.log('File name:', file.name);
console.log('File type:', file.type);
console.log('File size:', file.size, 'bytes');
console.log('Last modified:', new Date(file.lastModified));

// Read file contents
readFile(file);
}
});

// Read file as text
function readFile(file) {
const reader = new FileReader();

reader.onload = event => {
const content = event.target.result;
console.log('File content:', content);
};

reader.onerror = error => {
console.error('File reading error:', error);
};

if (file.type.startsWith('text/')) {
reader.readAsText(file); // Read as text
} else if (file.type.startsWith('image/')) {
reader.readAsDataURL(file); // Read as data URL for images

// Display the image
reader.onload = event => {
const imageElement = document.createElement('img');
imageElement.src = event.target.result;
document.body.appendChild(imageElement);
};
} else {
reader.readAsArrayBuffer(file); // Read as ArrayBuffer for binary files
}
}

// Drag and drop files
const dropZone = document.getElementById('drop-zone');

dropZone.addEventListener('dragover', event => {
event.preventDefault();
dropZone.classList.add('drag-over');
});

dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('drag-over');
});

dropZone.addEventListener('drop', event => {
event.preventDefault();
dropZone.classList.remove('drag-over');

const files = event.dataTransfer.files;
console.log('Files dropped:', files.length);

for (const file of files) {
readFile(file);
}
});

Broadcast Channel API

Communicate between browsing contexts (tabs, windows, iframes).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Create a channel
const channel = new BroadcastChannel('app_channel');

// Send a message to all other contexts
function sendMessage(message) {
channel.postMessage({
type: 'notification',
text: message,
timestamp: Date.now()
});
}

// Listen for messages
channel.onmessage = event => {
console.log('Message received:', event.data);
displayNotification(event.data);
};

// Handle errors
channel.onmessageerror = error => {
console.error('Message error:', error);
};

// Close the channel when done
function closeChannel() {
channel.close();
}

// Example usage
document.getElementById('send-button').addEventListener('click', () => {
const message = document.getElementById('message-input').value;
sendMessage(message);
});

// Display notification
function displayNotification(data) {
const notification = document.createElement('div');
notification.className = 'notification';
notification.textContent = `${data.text} (${new Date(data.timestamp).toLocaleTimeString()})`;
document.body.appendChild(notification);

// Remove after a few seconds
setTimeout(() => {
notification.remove();
}, 5000);
}

Learning Resources

  • MDN Web Docs - Web APIs
  • MDN Web Docs - Document Object Model (DOM)
  • JavaScript.info - Browser: Document, Events, Interfaces
  • Google Developers - Web Fundamentals
  • Can I Use - Browser compatibility tables
  • DOM Enlightenment - Free online book
  • Web Development
  • JavaScript
  • DOM
  • Browser APIs

扫一扫,分享到微信

微信分享二维码
React Fundamentals
ES6+ Features
目录
  1. 1. Browser APIs & DOM Manipulation
    1. 1.1. The Document Object Model (DOM)
      1. 1.1.1. DOM Structure
      2. 1.1.2. Selecting DOM Elements
      3. 1.1.3. Manipulating DOM Elements
        1. 1.1.3.1. Creating Elements
        2. 1.1.3.2. Modifying the DOM
        3. 1.1.3.3. Cloning Elements
      4. 1.1.4. DOM Properties
    2. 1.2. DOM Events
      1. 1.2.1. Event Handling
      2. 1.2.2. Event Object Properties
      3. 1.2.3. Event Propagation
      4. 1.2.4. Common DOM Events
      5. 1.2.5. Custom Events
    3. 1.3. Browser Storage APIs
      1. 1.3.1. Local Storage
      2. 1.3.2. Session Storage
      3. 1.3.3. Cookies
      4. 1.3.4. IndexedDB
    4. 1.4. Network Requests
      1. 1.4.1. XMLHttpRequest (Legacy)
      2. 1.4.2. Fetch API (Modern)
    5. 1.5. Geolocation API
    6. 1.6. History API
    7. 1.7. Web Storage API
    8. 1.8. Canvas API
    9. 1.9. Web Audio API
    10. 1.10. WebRTC
    11. 1.11. Web Workers
    12. 1.12. Service Workers
    13. 1.13. Intersection Observer
    14. 1.14. Mutation Observer
    15. 1.15. Web Animations API
    16. 1.16. Drag and Drop API
    17. 1.17. File API
    18. 1.18. Broadcast Channel API
    19. 1.19. Learning Resources

150 篇 | 131.7k
次 | 人
这里自动载入天数这里自动载入时分秒
2022-2025 loong loong | 新南威尔士龙龙号