Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bb64f90

Browse files
committed
Demos for Vue3 Dynamic Rendering using Gridstack
1 parent 914e372 commit bb64f90

File tree

3 files changed

+332
-1
lines changed

3 files changed

+332
-1
lines changed

demo/index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ <h1>Demos</h1>
3232
<li><a href="vue2js.html">Vue2.js</a></li>
3333
<li><a href="vue3js.html">Vue3.js</a></li>
3434
<li><a href="vue3js_v-for.html">Vue3 with v-for</a></li>
35+
<li><a href="vue3js_dynamic-render_grid-item.html">Vue3: Gridstack Controls Vue Rendering Grid Item</a></li>
36+
<li><a href="vue3js_dynamic-render_grid-item-content.html">Vue3: Gridstack Controls Vue Rendering Grid Item Content</a></li>
3537
<li><a href="web-comp.html">Web Component</a></li>
3638
<li><a href="web1.html">Website demo 1</a></li>
3739
<li><a href="web2.html">Website demo 2</a></li>
@@ -55,4 +57,4 @@ <h1>Old v5.1.1 Jquery Demos</h1>
5557
</ul>
5658
</body>
5759

58-
</html>
60+
</html>
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Vue3 Gridstack: Gridstack DOM with Vue Rendering</title>
7+
<link rel="stylesheet" href="demo.css"/>
8+
<script src="../dist/gridstack-all.js"></script>
9+
</head>
10+
<body>
11+
<main id="app">
12+
<a href="./index.html">Back to All Demos</a>
13+
<h1>Vue3: Gridstack Controls Vue Rendering Grid Item Content</h1>
14+
<p>
15+
<strong>Use Vue3 render functions to dynamically render only the grid item content.</strong><br />
16+
GridStack is handles when items are added/removed, rendering grid item element, and Vue handles rendering <i>only</i> the item content.
17+
</p>
18+
<p>
19+
Helpful Resources:
20+
<ul>
21+
<li><a href="https://vuejs.org/guide/extras/render-function.html#render-functions-jsx" target="_blank">Vue Render Functions</a></li>
22+
</ul>
23+
</p>
24+
<p>
25+
Notes:
26+
<ul>
27+
<li>This implementation currently does not support nested grid</li>
28+
</ul>
29+
</p>
30+
<button type="button" @click="addNewWidget()">Add Widget</button> {{ info }}
31+
<div class="grid-stack"></div>
32+
</main>
33+
<script type="module">
34+
import { createApp, ref, onMounted, onBeforeUnmount, h, render, toRefs } from "https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.esm-browser.js";
35+
36+
const GridContentComponent = {
37+
props: {
38+
itemId: {
39+
type: [String, Number],
40+
required: true,
41+
},
42+
},
43+
emits: ['remove'],
44+
setup(props, { emit }) {
45+
const { itemId } = toRefs(props)
46+
47+
onBeforeUnmount(() => {
48+
console.log(`In vue onBeforeUnmount for item ${itemId.value}`)
49+
});
50+
51+
function handleRemove() {
52+
emit('remove', itemId.value)
53+
}
54+
55+
return {
56+
itemId,
57+
handleRemove,
58+
}
59+
},
60+
template: `
61+
<div class="my-custom-grid-item-content">
62+
<button @click=handleRemove>X</button>
63+
<p>
64+
Vue Grid Item Content {{ itemId }}
65+
</p>
66+
</div>
67+
`
68+
}
69+
70+
createApp({
71+
setup() {
72+
let info = ref("");
73+
let grid = null; // DO NOT use ref(null) as proxies GS will break all logic when comparing structures... see https://github.com/gridstack/gridstack.js/issues/2115
74+
const items = [
75+
{ id: 1, x: 2, y: 1, h: 2 },
76+
{ id: 2, x: 2, y: 4, w: 3 },
77+
{ id: 3, x: 4, y: 2 },
78+
{ id: 4, x: 3, y: 1, h: 2 },
79+
{ id: 5, x: 0, y: 6, w: 2, h: 2 },
80+
];
81+
let count = ref(items.length);
82+
83+
onMounted(() => {
84+
grid = GridStack.init({ // DO NOT user grid.value = GridStack.init(), see above
85+
float: true,
86+
cellHeight: "70px",
87+
minRow: 1,
88+
});
89+
90+
grid.on('added', function(event, items) {
91+
for (const item of items) {
92+
const itemEl = item.el
93+
const itemElContent = itemEl.querySelector('.grid-stack-item-content')
94+
95+
const itemId = item.id
96+
97+
// Use Vue's render function to create the content
98+
// See https://vuejs.org/guide/extras/render-function.html#render-functions-jsx
99+
// Supports: emit, slots, props, attrs, see onRemove event below
100+
const itemContentVNode = h(
101+
GridContentComponent,
102+
{
103+
itemId: itemId,
104+
onRemove: (itemId) => {
105+
grid.removeWidget(itemEl)
106+
}
107+
}
108+
)
109+
110+
// Render the vue node into the item element
111+
render(itemContentVNode, itemElContent)
112+
}
113+
});
114+
115+
grid.on('removed', function(event, items) {
116+
for (const item of items) {
117+
const itemEl = item.el
118+
const itemElContent = itemEl.querySelector('.grid-stack-item-content')
119+
// Unmount the vue node from the item element
120+
// Calling render with null will allow vue to clean up the DOM, and trigger lifecycle hooks
121+
render(null, itemElContent)
122+
}
123+
});
124+
125+
grid.load(items);
126+
});
127+
128+
function addNewWidget() {
129+
const node = items[count.value] || {
130+
x: Math.round(12 * Math.random()),
131+
y: Math.round(5 * Math.random()),
132+
w: Math.round(1 + 3 * Math.random()),
133+
h: Math.round(1 + 3 * Math.random()),
134+
};
135+
node.id = String(count.value++);
136+
grid.addWidget(node);
137+
}
138+
139+
return {
140+
info,
141+
addNewWidget,
142+
};
143+
},
144+
145+
watch: {
146+
/**
147+
* Clear the info text after a two second timeout. Clears previous timeout first.
148+
*/
149+
info: function (newVal) {
150+
if (newVal.length === 0) return;
151+
152+
window.clearTimeout(this.timerId);
153+
this.timerId = window.setTimeout(() => {
154+
this.info = "";
155+
}, 2000);
156+
},
157+
},
158+
}).mount("#app");
159+
</script>
160+
</body>
161+
</html>
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Vue3 Gridstack: Gridstack DOM with Vue Rendering</title>
7+
<link rel="stylesheet" href="demo.css"/>
8+
<script src="../dist/gridstack-all.js"></script>
9+
</head>
10+
<body>
11+
<main id="app">
12+
<a href="./index.html">Back to All Demos</a>
13+
<h1>Vue3: Gridstack Controls Vue Rendering Grid Item</h1>
14+
<p>
15+
<strong>Use Vue3 render functions to dynamically render the entire Gridstack item (wrapper and contents)</strong><br />
16+
GridStack is handles when items are added/removed, and Vue handles rendering of the entire item in <code>GridStack.addRemoveCB</code>.
17+
</p>
18+
<p>
19+
Helpful Resources:
20+
<ul>
21+
<li><a href="https://vuejs.org/guide/extras/render-function.html#render-functions-jsx" target="_blank">Vue Render Functions</a></li>
22+
</ul>
23+
</p>
24+
<p>
25+
Notes:
26+
<ul>
27+
<li>This implementation currently does not support nested grid</li>
28+
</ul>
29+
</p>
30+
<button type="button" @click="addNewWidget()">Add Widget</button> {{ info }}
31+
<div class="grid-stack"></div>
32+
</main>
33+
<script type="module">
34+
import { createApp, ref, onMounted, onBeforeUnmount, h, render, toRefs } from "https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.esm-browser.js";
35+
36+
const GridItemComponent = {
37+
props: {
38+
itemId: {
39+
type: [String, Number],
40+
required: true,
41+
},
42+
},
43+
emits: ['remove'],
44+
setup(props, { emit }) {
45+
const root = ref(null)
46+
const { itemId } = toRefs(props)
47+
48+
onBeforeUnmount(() => {
49+
console.log(`In vue onBeforeUnmount for item ${itemId.value}`)
50+
});
51+
52+
function handleRemove() {
53+
emit('remove', root.value)
54+
}
55+
56+
return {
57+
root,
58+
itemId,
59+
handleRemove,
60+
}
61+
},
62+
template: `
63+
<div ref="root" class="grid-stack-item my-custom-grid-item-component">
64+
<div class="grid-stack-item-content">
65+
<button @click=handleRemove>X</button>
66+
<p>
67+
Vue Grid Item {{ itemId }}
68+
</p>
69+
</div>
70+
</div>
71+
`
72+
}
73+
74+
createApp({
75+
setup() {
76+
let info = ref("");
77+
let grid = null; // DO NOT use ref(null) as proxies GS will break all logic when comparing structures... see https://github.com/gridstack/gridstack.js/issues/2115
78+
const items = [
79+
{ id: 1, x: 2, y: 1, h: 2 },
80+
{ id: 2, x: 2, y: 4, w: 3 },
81+
{ id: 3, x: 4, y: 2 },
82+
{ id: 4, x: 3, y: 1, h: 2 },
83+
{ id: 5, x: 0, y: 6, w: 2, h: 2 },
84+
];
85+
let count = ref(items.length);
86+
const shadowDom = {}
87+
88+
onMounted(() => {
89+
grid = GridStack.init({ // DO NOT user grid.value = GridStack.init(), see above
90+
float: true,
91+
cellHeight: "70px",
92+
minRow: 1,
93+
});
94+
95+
GridStack.addRemoveCB = gsAddRemoveVueComponents;
96+
97+
grid.load(items);
98+
});
99+
100+
function gsAddRemoveVueComponents(host, item, add, isGrid) {
101+
if (!host) {
102+
return
103+
}
104+
105+
// Not supported yet
106+
if (isGrid) {
107+
return;
108+
}
109+
110+
if (add) {
111+
const itemId = item.id
112+
113+
// Use Vue's render function to create the content
114+
// See https://vuejs.org/guide/extras/render-function.html#render-functions-jsx
115+
// Supports: emit, slots, props, attrs, see onRemove event below
116+
const itemVNode = h(
117+
GridItemComponent,
118+
{
119+
itemId: itemId,
120+
onRemove: (itemEl) => {
121+
grid.removeWidget(itemEl)
122+
}
123+
}
124+
)
125+
shadowDom[itemId] = document.createElement('div')
126+
render(itemVNode, shadowDom[itemId])
127+
return itemVNode.el
128+
} else {
129+
const itemId = item.id
130+
render(null, shadowDom[itemId])
131+
return;
132+
}
133+
}
134+
135+
function addNewWidget() {
136+
const node = items[count.value] || {
137+
x: Math.round(12 * Math.random()),
138+
y: Math.round(5 * Math.random()),
139+
w: Math.round(1 + 3 * Math.random()),
140+
h: Math.round(1 + 3 * Math.random()),
141+
};
142+
node.id = String(count.value++);
143+
grid.addWidget(node);
144+
}
145+
146+
return {
147+
info,
148+
addNewWidget,
149+
};
150+
},
151+
152+
watch: {
153+
/**
154+
* Clear the info text after a two second timeout. Clears previous timeout first.
155+
*/
156+
info: function (newVal) {
157+
if (newVal.length === 0) return;
158+
159+
window.clearTimeout(this.timerId);
160+
this.timerId = window.setTimeout(() => {
161+
this.info = "";
162+
}, 2000);
163+
},
164+
},
165+
}).mount("#app");
166+
</script>
167+
</body>
168+
</html>

0 commit comments

Comments
 (0)