Skip to content

Commit d3f5634

Browse files
committed
new demo - Vue3 render functions with GridStack.renderCB
1 parent 2e31661 commit d3f5634

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vue3 Gridstack: Gridstack DOM with Vue Rendering</title>
8+
<link rel="stylesheet" href="demo.css" />
9+
<script src="../dist/gridstack-all.js"></script>
10+
</head>
11+
12+
<body>
13+
<main id="app">
14+
<a href="./index.html">Back to All Demos</a>
15+
<h1>Vue3: Gridstack Controls Vue Rendering Grid Items</h1>
16+
<p>
17+
<strong>Use Vue3 render functions with GridStack.renderCB</strong><br />
18+
GridStack handles widget creation and Vue handles rendering the content using the modern (since V11) GridStack.renderCB.
19+
</p>
20+
<p>
21+
Helpful Resources:
22+
<ul>
23+
<li><a href="https://vuejs.org/guide/extras/render-function.html#render-functions-jsx" target="_blank">Vue Render Functions</a></li>
24+
</ul>
25+
</p>
26+
<button type="button" @click="addNewWidget">Add Widget</button> {{ info }}
27+
<div class="grid-stack"></div>
28+
</main>
29+
<script type="module">
30+
import { createApp, ref, onMounted, onBeforeUnmount, h, render, toRefs } from "https://cdn.jsdelivr.net/npm/vue@3.0.11/dist/vue.esm-browser.js";
31+
32+
const GridItemComponent = {
33+
props: {
34+
itemId: {
35+
type: [String, Number],
36+
required: true,
37+
},
38+
},
39+
emits: ['remove'],
40+
setup(props, { emit }) {
41+
const { itemId } = toRefs(props)
42+
43+
onBeforeUnmount(() => {
44+
console.log(`In vue onBeforeUnmount for item ${itemId.value}`)
45+
});
46+
47+
function handleRemove() {
48+
emit('remove')
49+
}
50+
51+
return {
52+
itemId,
53+
handleRemove,
54+
}
55+
},
56+
template: `
57+
<button @click="handleRemove">X</button>
58+
<p>
59+
Vue Grid Item {{ itemId }}
60+
</p>
61+
`
62+
}
63+
64+
createApp({
65+
setup() {
66+
let info = ref("");
67+
let grid = null;
68+
const items = [
69+
{ id: 1, x: 2, y: 1, h: 2 },
70+
{ id: 2, x: 2, y: 4, w: 3 },
71+
{ id: 3, x: 4, y: 2 },
72+
{ id: 4, x: 3, y: 1, h: 2 },
73+
{ id: 5, x: 0, y: 6, w: 2, h: 2 },
74+
];
75+
let count = ref(items.length);
76+
const shadowDom = {}
77+
78+
onMounted(() => {
79+
grid = GridStack.init({
80+
float: true,
81+
cellHeight: "70px",
82+
minRow: 1,
83+
});
84+
85+
// Listen for remove events to clean up Vue renders
86+
grid.on('removed', function (event, items) {
87+
items.forEach(item => {
88+
if (shadowDom[item.id]) {
89+
render(null, shadowDom[item.id]);
90+
delete shadowDom[item.id];
91+
}
92+
});
93+
});
94+
95+
GridStack.renderCB = function (el, widget) {
96+
// el: HTMLElement div.grid-stack-item-content
97+
// widget: GridStackWidget
98+
99+
const gridItemEl = el.closest('.grid-stack-item'); // div.grid-stack-item (parent of el)
100+
101+
// Create Vue component for the widget content
102+
const itemId = widget.id
103+
const widgetNode = h(GridItemComponent, {
104+
itemId: itemId,
105+
onRemove: () => { // Catch the remove event from the Vue component
106+
grid.removeWidget(gridItemEl); // div.grid-stack-item
107+
info.value = `Widget ${itemId} removed`;
108+
}
109+
})
110+
shadowDom[itemId] = el
111+
render(widgetNode, el) // Render Vue component into the GridStack-created element
112+
}
113+
114+
grid.load(items);
115+
});
116+
117+
onBeforeUnmount(() => {
118+
// Clean up Vue renders
119+
Object.values(shadowDom).forEach(el => {
120+
render(null, el)
121+
})
122+
});
123+
124+
function addNewWidget() {
125+
const node = items[count.value] || {
126+
x: Math.round(12 * Math.random()),
127+
y: Math.round(5 * Math.random()),
128+
w: Math.round(1 + 3 * Math.random()),
129+
h: Math.round(1 + 3 * Math.random()),
130+
};
131+
node.id = String(count.value++);
132+
grid.addWidget(node);
133+
info.value = `Widget ${node.id} added`;
134+
}
135+
136+
return {
137+
info,
138+
addNewWidget,
139+
};
140+
},
141+
142+
watch: {
143+
info: function (newVal) {
144+
if (newVal.length === 0) return;
145+
146+
window.clearTimeout(this.timerId);
147+
this.timerId = window.setTimeout(() => {
148+
this.info = "";
149+
}, 2000);
150+
},
151+
},
152+
}).mount("#app");
153+
</script>
154+
</body>
155+
156+
</html>

0 commit comments

Comments
 (0)