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); |