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