簡體   English   中英

Gridstack.js + Vue 3 組件

[英]Gridstack.js + Vue 3 components

我正在嘗試使用 Vue 3 創建一個 gridstack.js 儀表板,我希望網格堆棧項目包含反應性 vue 3 組件。

問題是這些網格堆棧項只能傳遞 HTML。文檔指出您應該能夠將 Vue 組件添加為內容,但示例是針對 Vue 2 的,我正在努力在 Vue 3 中實現它。

我有以下代碼:

<template>
    <div class="p-6 h-full flex flex-col">

        <header class="flex flex-row items-center justify-between mb-6">
            <div>
                <h1 class="text-3xl font-bold">
                    Workbench
                </h1>
                <p class="leading-6 text-gray-600 text-sm mt-2">
                    {{ info }}
                </p>
            </div>
            <div class="flex flex-row items-center">
                <button type="button" @click="addPanel()">Add Panel</button>
            </div>
        </header>

        <div class="flex-1">
            <section class="grid-stack"></section>
        </div>

    </div>
</template>

<script setup>

    import { ref, onMounted, defineComponent, createApp } from "vue"

    import TestPanel from "./../components/panels/TestPanel.vue"

    let grid = null;

    const items = [
        { x: 0, y: 0, h: 4, w: 6 },
        { x: 7, y: 0, h: 4, w: 6 },
        { x: 0, y: 5, h: 4, w: 4 },
        { x: 4, y: 5, h: 4, w: 4 },
        { x: 8, y: 5, h: 4, w: 4 },
    ];

    onMounted(() => {

        grid = GridStack.init({
            // float: true,
            cellHeight: "70px",
            minRow: 1,
        });

        grid.load(items)

    });

    function addPanel() {

        const div = document.createElement("div")
        div.id = Math.random().toString(24).substring(8)

        const componentInstance = defineComponent({
            extends: TestPanel, data() {
                return {
                    test: "this is a test"
                }
            }
        })

        const app = createApp(componentInstance)

        app.mount(div)

        let widget = grid.addWidget({
            x: 0,
            y: 0,
            w: 6,
            h: 3,
            content: div.outerHTML,
        })

        app.mount(div.id)
    }

</script>

<style>
    .grid-stack-item-content {
        background-color: #18BC9C;
    }
</style>

這會將 vue 組件加載到堆棧網格項中,但該組件不再是反應式的。

任何幫助將不勝感激,在此先感謝!

這可能不是 gridstack-creators 所想的,但這里是 go:

<template>
  <button @click="addNewWidget()">Add Widget</button> {{ info }}

  <section class="grid-stack">
    <div 
      v-for="(component, key, index) in components" 
      :key="'component'+index" 
      :gs-id="key" 
      class="grid-stack-item"
      :gs-x="component.gridPos.x" 
      :gs-y="component.gridPos.y" 
      :gs-h="component.gridPos.h" 
      :gs-w="component.gridPos.w"
      gs-auto-position="true"
    >
      <div class="grid-stack-item-content">
        <component :is="component.name" v-bind="component.props" />
      </div>
    </div>
  </section>
</template>

<script>
import { ref, onMounted, reactive, nextTick } from 'vue';
import 'gridstack/dist/gridstack.min.css';
import { GridStack } from 'gridstack';
import YourRandomComponent1 from '../YourRandomComponent1.vue';
import YourRandomComponent2 from '../YourRandomComponent2.vue';
import YourRandomComponent3 from '../YourRandomComponent3.vue';

export default {
  name: "WidgetGrid",
  setup() {
    let info = ref("");
    let grid = null;

    let components = reactive({
      yourRandomComponent1: {
        name: "YourRandomComponent1", props: {}, gridPos: { x: 0, y: 1, w: 4, h: 5 }
      },
      yourRandomComponent2: {
        name: "YourRandomComponent2", props: {}, gridPos: { x: 0, y: 1, w: 2, h: 5 }
      },
    });

    onMounted(() => {
      grid = GridStack.init({
        float: true,
        cellHeight: "70px",
        minRow: 1,
      });

      grid.on("dragstop", (event, element) => {
        console.log("move event!", event, element);
        const node = element.gridstackNode;
        info.value = `you just dragged node #${node.id} to ${node.x},${node.y} – good job!`;
      });
    });

    // this will of course only work once because of the object-key
    function addNewWidget() {
      components.yourRandomComponent3= {
        name: "YourRandomComponent3", props: {}, gridPos: { x: 0, y: 1, w: 2, h: 5 }
      };
      // we have to wait for vue to update v-for, 
      // until then the querySelector wont find the element
      nextTick(() => {
        console.log(grid);
        let compEl = document.querySelector('[gs-id="yourRandomComponent3"]');
        console.log(compEl);
        grid.makeWidget(compEl);
      });
      console.warn("i will only work once, fix my inputs to reuse me");
    }

    return {
      info,
      components,
    };
  },
  components: {
    // eslint-disable-next-line vue/no-unused-components
    YourRandomComponent1,
    // eslint-disable-next-line vue/no-unused-components
    YourRandomComponent2,
  },
}
</script>

<style>
.grid-stack {
  background-color: #FAFAFF;
  border-style: dashed;
}

.grid-stack-item {
  color: #2c3e50;
  text-align: center;
  border-style: solid;
  overflow: auto;
  z-index: 50;
}
</style>

在我的例子中,一個缺少的 div 與grid-stack-item-content -class 包裝組件使小部件無法移動。 我還添加了一個 add-new-widget function 來演示如何向網格添加新的小部件。 關鍵是使用reactive()以便 Vue 重新渲染頁面。 重新渲染后,需要使用grid.makeWidget將組件注冊為網格元素。 為此,我們需要組件的 Dom 元素,這是在 Vue 使用nextTick重新渲染后獲得的。

你可以像這樣在 Vue3 中使用自己的組件

<div class="grid-stack" :style="{ 'background-color': hex }"  >
    <widget v-for="widget in widgets" :widget="widget" :key="widget" />
</div>

導入你的組件

import Widget from "src/components/GridStackComponent.vue";

添加要導出的組件

export default {
  name: 'GridStack',
  components: {
    Widget
  },
  data() {
   ...
  },
  ...
}

就這樣。 結果看起來像這樣

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM