Gridstack.js + Vue 3个组件

xoshrz7s  于 2022-12-04  发布在  Vue.js
关注(0)|答案(2)|浏览(517)

我尝试用Vue 3创建一个gridstack.js Jmeter 板,我希望网格堆栈项目包含React性的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组件,但该组件不再是React性的。
任何帮助将不胜感激,提前感谢!

yc0p9oo0

yc0p9oo01#

这可能不是网格堆栈创建者所想的,但你可以这样做:

<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类 Package 了组件,这使得小部件无法移动。我还添加了一个add-new-widget函数,演示如何向网格添加新的小部件。关键是使用reactive(),这样Vue将重新呈现页面。重新呈现后,组件需要使用grid.makeWidget注册为网格元素。为此,我们需要组件的Dom元素,该元素是在Vue使用nextTick重新渲染后获得的。

mzmfm0qo

mzmfm0qo2#

您可以像这样在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() {
   ...
  },
  ...
}

就这样。结果可以是这样的

相关问题