3.8 KiB
Executable File
3.8 KiB
Executable File
morphdom.js
A fast and lightweight DOM diffing/patching library for efficiently updating the DOM with minimal changes.
Basic Usage
morphdom(fromNode, toNode, options) // Transform fromNode to match toNode
Returns the morphed node (may be a new node if root element changes). Instead of replacing entire DOM trees, morphdom intelligently compares and patches only the differences:
const container = document.getElementById('container');
const newHTML = '<div><p>Updated content</p></div>';
// Efficiently update DOM - only changed parts are modified
morphdom(container, newHTML);
Options
morphdom(fromNode, toNode, {
childrenOnly: true, // Only morph children, not root element
getNodeKey: node => node.id, // Custom key function for matching nodes
onBeforeNodeAdded: node => true, // Called before adding new nodes
onNodeAdded: node => {}, // Called after nodes are added
onBeforeElUpdated: (from, to) => true, // Called before updating elements
onElUpdated: node => {}, // Called after elements are updated
onBeforeNodeDiscarded: node => true, // Called before removing nodes
onNodeDiscarded: node => {}, // Called after nodes are removed
onBeforeElChildrenUpdated: (from, to) => true, // Called before updating children
skipFromChildren: (from, to) => false, // Skip children comparison
addChild: (parent, child) => parent.appendChild(child) // Custom child addition
});
Key Matching
Use getNodeKey for efficient list updates:
// HTML with keyed elements
const html = `
<ul>
<li id="item-1">Item 1</li>
<li id="item-2">Item 2</li>
<li id="item-3">Item 3</li>
</ul>
`;
morphdom(list, html, {
getNodeKey: node => node.getAttribute('id')
});
Event Handlers
morphdom(container, newHTML, {
onBeforeElUpdated: (fromEl, toEl) => {
// Preserve event listeners
if (fromEl.hasEventListeners) {
return false; // Skip this element
}
return true;
},
onNodeAdded: (node) => {
// Initialize new components
if (node.classList?.contains('widget')) {
initializeWidget(node);
}
}
});
Form Element Handling
Morphdom has special handling for form elements:
- INPUT: Preserves checked, disabled, and value properties
- TEXTAREA: Syncs value and text content
- SELECT: Maintains selectedIndex and option states
- OPTION: Handles selected state in select boxes
Common Patterns
Template Updates
function updateTemplate(container, data) {
const template = `<div class="user">${data.name}</div>`;
morphdom(container, template);
}
List Management
function updateList(listEl, items) {
const html = items.map(item =>
`<li id="item-${item.id}">${item.name}</li>`
).join('');
morphdom(listEl, `<ul>${html}</ul>`, {
childrenOnly: true,
getNodeKey: node => node.id
});
}
Component Preservation
morphdom(container, newHTML, {
onBeforeElUpdated: (from, to) => {
// Preserve components that haven't changed
if (from.dataset.component === to.dataset.component) {
return false; // Skip update
}
return true;
}
});
Integration with uquery.js
This library is used by uquery's html() method when differential updates are enabled:
$.options.alwaysDoDifferentialUpdate = true;
$('#container').html(newContent); // Uses morphdom internally
Browser Support
- Modern browsers with DOM Level 2+ support
- Automatic fallbacks for older browsers
- Template element support detection
- Range API support detection