dom-advanced-examples.js
JavaScript/modules/module3-advanced/code-examples/lesson4/dom-advanced-examples.js
// Lesson 4: Advanced DOM Manipulation Examples
// Note: These examples simulate DOM behavior for Node.js
// In a real browser, you would use actual DOM methods
console.log("=== Advanced DOM Manipulation Examples ===");
console.log("Note: These examples simulate DOM behavior for Node.js");
console.log("In a real browser, you would use actual DOM methods");
// Enhanced mock element with advanced capabilities
class AdvancedMockElement {
constructor(tagName, id = null, className = null) {
this.tagName = tagName.toLowerCase();
this.id = id;
this.className = className || '';
this.innerText = '';
this.innerHTML = '';
this.style = {};
this.children = [];
this.parentNode = null;
this.attributes = {};
this.dataset = {};
this.eventListeners = {};
}
setAttribute(name, value) {
this.attributes[name] = value;
if (name.startsWith('data-')) {
this.dataset[name.substring(5)] = value;
}
}
getAttribute(name) {
return this.attributes[name];
}
removeAttribute(name) {
delete this.attributes[name];
if (name.startsWith('data-')) {
delete this.dataset[name.substring(5)];
}
}
hasAttribute(name) {
return name in this.attributes;
}
addEventListener(event, handler) {
if (!this.eventListeners[event]) {
this.eventListeners[event] = [];
}
this.eventListeners[event].push(handler);
}
removeEventListener(event, handler) {
if (this.eventListeners[event]) {
const index = this.eventListeners[event].indexOf(handler);
if (index > -1) {
this.eventListeners[event].splice(index, 1);
}
}
}
dispatchEvent(event, data = {}) {
if (this.eventListeners[event]) {
this.eventListeners[event].forEach(handler => {
handler({ target: this, ...data });
});
}
}
appendChild(child) {
this.children.push(child);
child.parentNode = this;
}
removeChild(child) {
const index = this.children.indexOf(child);
if (index > -1) {
this.children.splice(index, 1);
child.parentNode = null;
}
}
insertBefore(newChild, referenceChild) {
const index = this.children.indexOf(referenceChild);
if (index > -1) {
this.children.splice(index, 0, newChild);
newChild.parentNode = this;
} else {
this.appendChild(newChild);
}
}
replaceChild(newChild, oldChild) {
const index = this.children.indexOf(oldChild);
if (index > -1) {
this.children[index] = newChild;
newChild.parentNode = this;
oldChild.parentNode = null;
}
}
cloneNode(deep = false) {
const clone = new AdvancedMockElement(this.tagName, this.id, this.className);
clone.innerText = this.innerText;
clone.innerHTML = this.innerHTML;
clone.dataset = { ...this.dataset };
clone.attributes = { ...this.attributes };
if (deep) {
this.children.forEach(child => {
clone.appendChild(child.cloneNode(true));
});
}
return clone;
}
addClass(className) {
if (!this.className.includes(className)) {
this.className += (this.className ? ' ' : '') + className;
}
}
removeClass(className) {
this.className = this.className.replace(new RegExp(`\\b${className}\\b`, 'g'), '').trim();
}
toggleClass(className) {
if (this.className.includes(className)) {
this.removeClass(className);
} else {
this.addClass(className);
}
}
hasClass(className) {
return this.className.includes(className);
}
querySelector(selector) {
// Simple selector matching
if (selector.startsWith('#')) {
return this.children.find(child => child.id === selector.substring(1));
}
if (selector.startsWith('.')) {
return this.children.find(child => child.hasClass(selector.substring(1)));
}
return this.children.find(child => child.tagName === selector);
}
querySelectorAll(selector) {
// Simple selector matching
if (selector.startsWith('#')) {
return this.children.filter(child => child.id === selector.substring(1));
}
if (selector.startsWith('.')) {
return this.children.filter(child => child.hasClass(selector.substring(1)));
}
return this.children.filter(child => child.tagName === selector);
}
}
// Mock document with advanced features
const mockDocument = {
createElement: (tagName) => new AdvancedMockElement(tagName),
createDocumentFragment: () => new DocumentFragment(),
getElementById: (id) => new AdvancedMockElement('div', id),
querySelector: (selector) => new AdvancedMockElement('div'),
querySelectorAll: (selector) => [new AdvancedMockElement('div'), new AdvancedMockElement('div')]
};
// Document Fragment class
class DocumentFragment {
constructor() {
this.children = [];
}
appendChild(child) {
this.children.push(child);
}
removeChild(child) {
const index = this.children.indexOf(child);
if (index > -1) {
this.children.splice(index, 1);
}
}
get length() {
return this.children.length;
}
}
// Example 1: Dynamic Element Creation
console.log("\n=== Example 1: Dynamic Element Creation ===");
function createDynamicElement(tagName, options = {}) {
const element = mockDocument.createElement(tagName);
if (options.id) element.id = options.id;
if (options.className) element.className = options.className;
if (options.innerText) element.innerText = options.innerText;
if (options.innerHTML) element.innerHTML = options.innerHTML;
if (options.attributes) {
Object.keys(options.attributes).forEach(key => {
element.setAttribute(key, options.attributes[key]);
});
}
if (options.style) {
Object.assign(element.style, options.style);
}
return element;
}
// Create various elements
const button = createDynamicElement('button', {
id: 'my-button',
className: 'btn btn-primary',
innerText: 'Click me',
attributes: { 'data-action': 'submit' },
style: { backgroundColor: 'blue', color: 'white' }
});
const input = createDynamicElement('input', {
id: 'my-input',
className: 'form-control',
attributes: { type: 'text', placeholder: 'Enter text' }
});
const div = createDynamicElement('div', {
id: 'my-div',
className: 'container',
innerText: 'Dynamic content'
});
console.log('Created button:', button);
console.log('Created input:', input);
console.log('Created div:', div);
// Example 2: Document Fragments for Performance
console.log("\n=== Example 2: Document Fragments ===");
function createListWithFragment(itemCount) {
const fragment = mockDocument.createDocumentFragment();
for (let i = 0; i < itemCount; i++) {
const li = createDynamicElement('li', {
className: 'list-item',
innerText: `Item ${i + 1}`,
attributes: { 'data-index': i }
});
fragment.appendChild(li);
}
console.log(`Created fragment with ${fragment.length} items`);
return fragment;
}
const listFragment = createListWithFragment(5);
console.log('Fragment children:', listFragment.children.length);
// Example 3: Advanced Element Manipulation
console.log("\n=== Example 3: Advanced Element Manipulation ===");
function manipulateElement(element) {
// Add multiple classes
element.addClass('active');
element.addClass('highlighted');
console.log('Added classes:', element.className);
// Toggle class
element.toggleClass('active');
console.log('After toggle:', element.className);
// Set multiple attributes
element.setAttribute('data-id', '123');
element.setAttribute('data-type', 'button');
element.setAttribute('aria-label', 'Submit button');
// Set dataset properties
element.dataset.userId = '456';
element.dataset.action = 'submit';
console.log('Attributes:', element.attributes);
console.log('Dataset:', element.dataset);
// Style manipulation
element.style.padding = '10px';
element.style.margin = '5px';
element.style.borderRadius = '4px';
console.log('Styles:', element.style);
return element;
}
const manipulatedButton = manipulateElement(button);
// Example 4: Element Cloning and Replacement
console.log("\n=== Example 4: Element Cloning and Replacement ===");
function cloneAndReplaceElement(originalElement) {
// Shallow clone
const shallowClone = originalElement.cloneNode(false);
console.log('Shallow clone:', shallowClone);
// Deep clone
const deepClone = originalElement.cloneNode(true);
console.log('Deep clone:', deepClone);
// Replace element
const newElement = createDynamicElement('span', {
innerText: 'Replaced element',
className: 'replaced'
});
if (originalElement.parentNode) {
originalElement.parentNode.replaceChild(newElement, originalElement);
console.log('Element replaced');
}
return { shallowClone, deepClone, newElement };
}
const cloneResults = cloneAndReplaceElement(manipulatedButton);
// Example 5: Dynamic List Management
console.log("\n=== Example 5: Dynamic List Management ===");
class DynamicList {
constructor(containerId) {
this.container = createDynamicElement('ul', { id: containerId, className: 'dynamic-list' });
this.items = [];
}
addItem(text, options = {}) {
const item = createDynamicElement('li', {
className: 'list-item',
innerText: text,
attributes: { 'data-id': Date.now() }
});
if (options.className) item.addClass(options.className);
if (options.attributes) {
Object.keys(options.attributes).forEach(key => {
item.setAttribute(key, options.attributes[key]);
});
}
this.container.appendChild(item);
this.items.push(item);
console.log(`Added item: ${text}`);
return item;
}
removeItem(index) {
if (index >= 0 && index < this.items.length) {
const item = this.items[index];
this.container.removeChild(item);
this.items.splice(index, 1);
console.log(`Removed item at index ${index}`);
return true;
}
return false;
}
updateItem(index, newText) {
if (index >= 0 && index < this.items.length) {
this.items[index].innerText = newText;
console.log(`Updated item at index ${index}: ${newText}`);
return true;
}
return false;
}
clear() {
this.items.forEach(item => this.container.removeChild(item));
this.items = [];
console.log('List cleared');
}
getItemCount() {
return this.items.length;
}
render() {
console.log(`List with ${this.items.length} items:`);
this.items.forEach((item, index) => {
console.log(` ${index}: ${item.innerText}`);
});
}
}
const dynamicList = new DynamicList('my-list');
dynamicList.addItem('First item');
dynamicList.addItem('Second item', { className: 'highlighted' });
dynamicList.addItem('Third item', { attributes: { 'data-priority': 'high' } });
dynamicList.render();
dynamicList.updateItem(1, 'Updated second item');
dynamicList.removeItem(0);
dynamicList.render();
// Example 6: Template System
console.log("\n=== Example 6: Template System ===");
class TemplateRenderer {
constructor() {
this.templates = new Map();
}
registerTemplate(name, templateFunction) {
this.templates.set(name, templateFunction);
console.log(`Template '${name}' registered`);
}
render(templateName, data) {
const template = this.templates.get(templateName);
if (!template) {
throw new Error(`Template '${templateName}' not found`);
}
return template(data);
}
renderList(templateName, dataArray) {
const fragment = mockDocument.createDocumentFragment();
dataArray.forEach(data => {
const element = this.render(templateName, data);
fragment.appendChild(element);
});
console.log(`Rendered ${dataArray.length} items with template '${templateName}'`);
return fragment;
}
}
const templateRenderer = new TemplateRenderer();
// Register templates
templateRenderer.registerTemplate('user-card', (user) => {
return createDynamicElement('div', {
className: 'user-card',
innerHTML: `
<h3>${user.name}</h3>
<p>Email: ${user.email}</p>
<p>Age: ${user.age}</p>
`,
attributes: { 'data-user-id': user.id }
});
});
templateRenderer.registerTemplate('product-item', (product) => {
return createDynamicElement('div', {
className: 'product-item',
innerHTML: `
<h4>${product.name}</h4>
<p>Price: $${product.price}</p>
<p>Stock: ${product.stock}</p>
`,
attributes: { 'data-product-id': product.id }
});
});
// Test template rendering
const users = [
{ id: 1, name: 'Alice', email: 'alice@example.com', age: 30 },
{ id: 2, name: 'Bob', email: 'bob@example.com', age: 25 }
];
const products = [
{ id: 1, name: 'Laptop', price: 999.99, stock: 10 },
{ id: 2, name: 'Phone', price: 699.99, stock: 25 }
];
const userCards = templateRenderer.renderList('user-card', users);
const productItems = templateRenderer.renderList('product-item', products);
console.log('User cards fragment:', userCards.length);
console.log('Product items fragment:', productItems.length);
// Example 7: Event Delegation
console.log("\n=== Example 7: Event Delegation ===");
class EventDelegator {
constructor(container) {
this.container = container;
this.delegatedEvents = new Map();
}
delegate(eventType, selector, handler) {
if (!this.delegatedEvents.has(eventType)) {
this.delegatedEvents.set(eventType, []);
}
this.delegatedEvents.get(eventType).push({ selector, handler });
// Add event listener to container
this.container.addEventListener(eventType, (event) => {
const target = event.target;
// Check if target matches any delegated selectors
for (const { selector: sel, handler: h } of this.delegatedEvents.get(eventType)) {
if (this.matchesSelector(target, sel)) {
h(event);
break;
}
}
});
console.log(`Delegated ${eventType} event for selector '${selector}'`);
}
matchesSelector(element, selector) {
if (selector.startsWith('.')) {
return element.hasClass(selector.substring(1));
}
if (selector.startsWith('#')) {
return element.id === selector.substring(1);
}
return element.tagName === selector;
}
}
const container = createDynamicElement('div', { id: 'event-container' });
const delegator = new EventDelegator(container);
// Add some elements to container
const button1 = createDynamicElement('button', { className: 'btn', innerText: 'Button 1' });
const button2 = createDynamicElement('button', { className: 'btn', innerText: 'Button 2' });
const link = createDynamicElement('a', { innerText: 'Link', attributes: { href: '#' } });
container.appendChild(button1);
container.appendChild(button2);
container.appendChild(link);
// Delegate events
delegator.delegate('click', '.btn', (event) => {
console.log(`Button clicked: ${event.target.innerText}`);
});
delegator.delegate('click', 'a', (event) => {
console.log(`Link clicked: ${event.target.innerText}`);
});
// Test event delegation
button1.dispatchEvent('click');
button2.dispatchEvent('click');
link.dispatchEvent('click');
console.log("\n=== Advanced DOM Manipulation Summary ===");
console.log("✓ Dynamic element creation and configuration");
console.log("✓ Document fragments for performance optimization");
console.log("✓ Advanced element manipulation (classes, attributes, styles)");
console.log("✓ Element cloning and replacement");
console.log("✓ Dynamic list management with CRUD operations");
console.log("✓ Template system for reusable components");
console.log("✓ Event delegation for efficient event handling");
console.log("✓ Advanced DOM traversal and manipulation");
console.log("✓ Performance optimization techniques");
console.log("✓ Real-world DOM manipulation patterns");
Articles liés
exercise1.js
exercise1.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise1.js).
Lire l'article →exercise2.js
exercise2.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise2.js).
Lire l'article →exercise3.js
exercise3.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise3.js).
Lire l'article →hello.js
hello.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/hello.js).
Lire l'article →exercise1.js
exercise1.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson2/exercise1.js).
Lire l'article →exercise2.js
exercise2.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson2/exercise2.js).
Lire l'article →