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
+ < li > < a href ="https://stackblitz.com/edit/vitejs-vite-phhdkeju " target ="_blank "> This Demo as a Vue SFC on Stackblitz</ a > </ li >
25
+ </ ul >
26
+ </ p >
27
+ < button type ="button " @click ="addNewWidget "> Add Widget</ button > {{ info }}
28
+ < div class ="grid-stack "> </ div >
29
+ </ main >
30
+ < script type ="module ">
31
+ import { createApp , ref , onMounted , onBeforeUnmount , h , render , toRefs } from "https://cdn.jsdelivr.net/npm/vue@3.0.11/dist/vue.esm-browser.js" ;
32
+
33
+ const GridItemComponent = {
34
+ props : {
35
+ itemId : {
36
+ type : [ String , Number ] ,
37
+ required : true ,
38
+ } ,
39
+ } ,
40
+ emits : [ 'remove' ] ,
41
+ setup ( props , { emit } ) {
42
+ const { itemId } = toRefs ( props )
43
+
44
+ onBeforeUnmount ( ( ) => {
45
+ console . log ( `In vue onBeforeUnmount for item ${ itemId . value } ` )
46
+ } ) ;
47
+
48
+ function handleRemove ( ) {
49
+ emit ( 'remove' )
50
+ }
51
+
52
+ return {
53
+ itemId,
54
+ handleRemove,
55
+ }
56
+ } ,
57
+ template : `
58
+ <button @click="handleRemove">X</button>
59
+ <p>
60
+ Vue Grid Item {{ itemId }}
61
+ </p>
62
+ `
63
+ }
64
+
65
+ createApp ( {
66
+ setup ( ) {
67
+ let info = ref ( "" ) ;
68
+ let grid = null ;
69
+ const items = [
70
+ { id : 1 , x : 2 , y : 1 , h : 2 } ,
71
+ { id : 2 , x : 2 , y : 4 , w : 3 } ,
72
+ { id : 3 , x : 4 , y : 2 } ,
73
+ { id : 4 , x : 3 , y : 1 , h : 2 } ,
74
+ { id : 5 , x : 0 , y : 6 , w : 2 , h : 2 } ,
75
+ ] ;
76
+ let count = ref ( items . length ) ;
77
+ const shadowDom = { }
78
+
79
+ onMounted ( ( ) => {
80
+ grid = GridStack . init ( {
81
+ float : true ,
82
+ cellHeight : "70px" ,
83
+ minRow : 1 ,
84
+ } ) ;
85
+
86
+ // Listen for remove events to clean up Vue renders
87
+ grid . on ( 'removed' , function ( event , items ) {
88
+ items . forEach ( item => {
89
+ if ( shadowDom [ item . id ] ) {
90
+ render ( null , shadowDom [ item . id ] ) ;
91
+ delete shadowDom [ item . id ] ;
92
+ }
93
+ } ) ;
94
+ } ) ;
95
+
96
+ GridStack . renderCB = function ( el , widget ) {
97
+ // el: HTMLElement div.grid-stack-item-content
98
+ // widget: GridStackWidget
99
+
100
+ const gridItemEl = el . closest ( '.grid-stack-item' ) ; // div.grid-stack-item (parent of el)
101
+
102
+ // Create Vue component for the widget content
103
+ const itemId = widget . id
104
+ const widgetNode = h ( GridItemComponent , {
105
+ itemId : itemId ,
106
+ onRemove : ( ) => { // Catch the remove event from the Vue component
107
+ grid . removeWidget ( gridItemEl ) ; // div.grid-stack-item
108
+ info . value = `Widget ${ itemId } removed` ;
109
+ }
110
+ } )
111
+ shadowDom [ itemId ] = el
112
+ render ( widgetNode , el ) // Render Vue component into the GridStack-created element
113
+ }
114
+
115
+ grid . load ( items ) ;
116
+ } ) ;
117
+
118
+ onBeforeUnmount ( ( ) => {
119
+ // Clean up Vue renders
120
+ Object . values ( shadowDom ) . forEach ( el => {
121
+ render ( null , el )
122
+ } )
123
+ } ) ;
124
+
125
+ function addNewWidget ( ) {
126
+ const node = items [ count . value ] || {
127
+ x : Math . round ( 12 * Math . random ( ) ) ,
128
+ y : Math . round ( 5 * Math . random ( ) ) ,
129
+ w : Math . round ( 1 + 3 * Math . random ( ) ) ,
130
+ h : Math . round ( 1 + 3 * Math . random ( ) ) ,
131
+ } ;
132
+ node . id = String ( count . value ++ ) ;
133
+ grid . addWidget ( node ) ;
134
+ info . value = `Widget ${ node . id } added` ;
135
+ }
136
+
137
+ return {
138
+ info,
139
+ addNewWidget,
140
+ } ;
141
+ } ,
142
+
143
+ watch : {
144
+ info : function ( newVal ) {
145
+ if ( newVal . length === 0 ) return ;
146
+
147
+ window . clearTimeout ( this . timerId ) ;
148
+ this . timerId = window . setTimeout ( ( ) => {
149
+ this . info = "" ;
150
+ } , 2000 ) ;
151
+ } ,
152
+ } ,
153
+ } ) . mount ( "#app" ) ;
154
+ </ script >
155
+ </ body >
156
+
157
+ </ html >
0 commit comments