WordPress定制器:Widget添加至预览器后及移除后的触发事件需求
Got it, let's break down how to solve this problem where you need to run code after a widget is fully added to (or removed from) your previewer's DOM — since the existing triggers fire too early to get an accurate count of widgets in the same sidebar.
The core issue here is that default widget add/remove hooks fire before the previewer finishes rendering the widget to the DOM. To fix this, we'll use MutationObserver to watch the sidebar container for actual DOM changes, ensuring our logic runs only when the widget is fully present (or removed).
Step 1: Target Your Previewer's Sidebar Container
First, identify the CSS selector for the container in your previewer where widgets are added. For example, if your sidebar uses the class preview-sidebar-widgets, that's our target element.
Step 2: Set Up the Mutation Observer
This observer will listen for when nodes are added to or removed from the sidebar container, then trigger our custom logic to update widget classes based on the total count.
Here's a practical code example tailored to your use case:
// Wait for the previewer DOM to load completely document.addEventListener('DOMContentLoaded', function() { // Grab the sidebar container in the previewer const sidebarContainer = document.querySelector('.preview-sidebar-widgets'); if (!sidebarContainer) return; // Exit if container doesn't exist // Configure the observer to watch for added/removed child nodes const observerOptions = { childList: true, // Track direct child additions/removals subtree: true // Watch nested elements (if widgets are wrapped in containers) }; // Callback to run when DOM mutations are detected const handleMutations = function(mutations) { mutations.forEach(mutation => { // Handle widget addition if (mutation.addedNodes.length > 0) { // Use requestAnimationFrame to ensure the widget is fully rendered requestAnimationFrame(() => updateWidgetClasses(sidebarContainer)); } // Handle widget removal if (mutation.removedNodes.length > 0) { updateWidgetClasses(sidebarContainer); } }); }; // Initialize and start the observer const domObserver = new MutationObserver(handleMutations); domObserver.observe(sidebarContainer, observerOptions); // Optional: Clean up the observer if the previewer is destroyed/reloaded // domObserver.disconnect(); }); // Custom logic: Update widget classes based on total sidebar widget count function updateWidgetClasses(container) { const allWidgets = container.querySelectorAll('.preview-widget'); const totalCount = allWidgets.length; // Update each widget's class allWidgets.forEach(widget => { // Remove old count-related classes first widget.classList.remove('single-widget', 'two-widgets', 'multiple-widgets'); // Add the appropriate class based on total count if (totalCount === 1) { widget.classList.add('single-widget'); } else if (totalCount === 2) { widget.classList.add('two-widgets'); } else { widget.classList.add('multiple-widgets'); } }); }
Key Notes for Reliability
requestAnimationFrame: We use this after detecting added nodes to ensure the widget's DOM is fully rendered before we count and update classes. This avoids race conditions where the element exists but isn't fully initialized.subtree: true: If your widgets are wrapped in nested containers (like a widget wrapper div), this ensures the observer catches mutations at all levels of the sidebar.- Cleanup: If your previewer can be destroyed or reloaded, call
domObserver.disconnect()to prevent memory leaks.
Alternative: Framework-Specific Hooks (If Applicable)
If you're working within a framework like WordPress Customizer (your use case hints at this), you can use native events that fire after the preview refreshes:
wp.customize.bind('preview-refreshed', function() { // Small delay to ensure DOM updates are complete setTimeout(() => { updateWidgetClasses(document.querySelector('.preview-sidebar-widgets')); }, 100); });
That said, the MutationObserver approach is more reliable because it targets exact DOM changes, whereas timeouts can be flaky if the preview takes longer to render.
This solution ensures your class-modification logic runs only after the widget is fully present in the previewer DOM, giving you an accurate count of all widgets in the sidebar.
内容的提问来源于stack exchange,提问作者rugbert

