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