|
Line 0
Link Here
|
|
|
1 |
import { createApp, Component, App } from "vue"; |
| 2 |
|
| 3 |
/** |
| 4 |
* A registry for Vue components. |
| 5 |
* @type {Map<string, Component>} |
| 6 |
*/ |
| 7 |
export const componentRegistry: Map<string, Component> = new Map< |
| 8 |
string, |
| 9 |
Component |
| 10 |
>(); |
| 11 |
|
| 12 |
/** |
| 13 |
* Registers a Vue component with a name. |
| 14 |
* @param {string} name - The name of the component. |
| 15 |
* @param {Component} component - The Vue component to register. |
| 16 |
* @returns {void} |
| 17 |
*/ |
| 18 |
export function registerComponent(name: string, component: Component): void { |
| 19 |
componentRegistry.set(name, component); |
| 20 |
} |
| 21 |
|
| 22 |
/** |
| 23 |
* Mounts Vue components to DOM elements based on the `data-component` attribute. |
| 24 |
* Components are created with props parsed from the `data-props` attribute. |
| 25 |
* Watches for changes in props and updates the component accordingly. |
| 26 |
* @returns {void} |
| 27 |
*/ |
| 28 |
export function mountComponents(): void { |
| 29 |
console.log("Mounting components"); |
| 30 |
|
| 31 |
const elements: NodeListOf<Element> = |
| 32 |
document.querySelectorAll("[data-component]"); |
| 33 |
elements.forEach((element: Element) => { |
| 34 |
const componentName: string | null = |
| 35 |
element.getAttribute("data-component"); |
| 36 |
if (!componentName) { |
| 37 |
console.warn("No data-component attribute found."); |
| 38 |
return; |
| 39 |
} |
| 40 |
|
| 41 |
const component: Component | undefined = |
| 42 |
componentRegistry.get(componentName); |
| 43 |
if (!component) { |
| 44 |
console.warn(`Component ${componentName} not found.`); |
| 45 |
return; |
| 46 |
} |
| 47 |
|
| 48 |
const props: string | null = element.getAttribute("data-props"); |
| 49 |
const parsedProps: Record<string, any> = props ? JSON.parse(props) : {}; |
| 50 |
|
| 51 |
// Create and mount the Vue component |
| 52 |
const app: App = createApp(component, parsedProps); |
| 53 |
app.mount(element); |
| 54 |
|
| 55 |
// Watch for updates to props |
| 56 |
watchProps(element, app, component); |
| 57 |
}); |
| 58 |
} |
| 59 |
|
| 60 |
/** |
| 61 |
* Watches for changes in props and updates the component accordingly. |
| 62 |
* @param {Element} element - The DOM element where the component is mounted. |
| 63 |
* @param {App} app - The Vue application instance. |
| 64 |
* @param {Component} component - The Vue component. |
| 65 |
* @returns {void} |
| 66 |
*/ |
| 67 |
function watchProps(element: Element, app: App, component: Component): void { |
| 68 |
const propsAttr: string | null = element.getAttribute("data-props"); |
| 69 |
let prevProps: Record<string, any> = propsAttr ? JSON.parse(propsAttr) : {}; |
| 70 |
|
| 71 |
const observer = new MutationObserver(() => { |
| 72 |
const newPropsAttr: string | null = element.getAttribute("data-props"); |
| 73 |
if (newPropsAttr) { |
| 74 |
const newProps: Record<string, any> = JSON.parse(newPropsAttr); |
| 75 |
if (JSON.stringify(newProps) !== JSON.stringify(prevProps)) { |
| 76 |
prevProps = newProps; |
| 77 |
app.unmount(); // Unmount existing component |
| 78 |
createApp(component, newProps).mount(element); // Mount with new props |
| 79 |
} |
| 80 |
} |
| 81 |
}); |
| 82 |
|
| 83 |
observer.observe(element, { |
| 84 |
attributes: true, |
| 85 |
attributeFilter: ["data-props"], |
| 86 |
}); |
| 87 |
} |
| 88 |
|
| 89 |
import HelloIslands from "../components/HelloIslands.vue"; |
| 90 |
registerComponent("HelloIslands", HelloIslands); |
| 91 |
|
| 92 |
// Automatically mount components when the DOM is fully loaded |
| 93 |
document.addEventListener("DOMContentLoaded", mountComponents); |