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