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