forked from gridstack/gridstack.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvue3js_dynamic-render_grid-item.html
168 lines (152 loc) · 5.18 KB
/
vue3js_dynamic-render_grid-item.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
162
163
164
165
166
167
168
<!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</h1>
<p>
<strong>Use Vue3 render functions to dynamically render the entire Gridstack item (wrapper and contents)</strong><br />
GridStack is handles when items are added/removed, and Vue handles rendering of the entire item in <code>GridStack.addRemoveCB</code>.
</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 GridItemComponent = {
props: {
itemId: {
type: [String, Number],
required: true,
},
},
emits: ['remove'],
setup(props, { emit }) {
const root = ref(null)
const { itemId } = toRefs(props)
onBeforeUnmount(() => {
console.log(`In vue onBeforeUnmount for item ${itemId.value}`)
});
function handleRemove() {
emit('remove', root.value)
}
return {
root,
itemId,
handleRemove,
}
},
template: `
<div ref="root" class="grid-stack-item my-custom-grid-item-component">
<div class="grid-stack-item-content">
<button @click=handleRemove>X</button>
<p>
Vue Grid Item {{ itemId }}
</p>
</div>
</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);
const shadowDom = {}
onMounted(() => {
grid = GridStack.init({ // DO NOT user grid.value = GridStack.init(), see above
float: true,
cellHeight: "70px",
minRow: 1,
});
GridStack.addRemoveCB = gsAddRemoveVueComponents;
grid.load(items);
});
function gsAddRemoveVueComponents(host, item, add, isGrid) {
if (!host) {
return
}
// Not supported yet
if (isGrid) {
return;
}
if (add) {
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 itemVNode = h(
GridItemComponent,
{
itemId: itemId,
onRemove: (itemEl) => {
grid.removeWidget(itemEl)
}
}
)
shadowDom[itemId] = document.createElement('div')
render(itemVNode, shadowDom[itemId])
return itemVNode.el
} else {
const itemId = item.id
render(null, shadowDom[itemId])
return;
}
}
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>