【问题标题】:Gridstack.js + Vue 3 componentsGridstack.js + Vue 3 组件
【发布时间】:2022-10-02 01:36:39
【问题描述】:

我正在尝试使用 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 组件加载到堆栈网格项中,但该组件不再是反应式的。

任何帮助将不胜感激,在此先感谢!

    标签: javascript vue.js vuejs3


    【解决方案1】:

    这可能不完全是 gridstack-creators 的想法,但是你去吧:

    <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>
    
    

    在我的例子中,带有 grid-stack-item-content-class 包装组件的缺少 div 使小部件无法移动。 我还添加了一个 add-new-widget 函数,该函数演示了如何将新的小部件添加到网格中。关键是使用reactive() 这样Vue 会重新渲染页面。重新渲染后,组件需要使用grid.makeWidget注册为网格元素。为此,我们需要组件的 Dom 元素,这是在 Vue 使用 nextTick 重新渲染后获得的。

    【讨论】:

      猜你喜欢
      • 2021-05-08
      • 2017-02-15
      • 2021-06-09
      • 1970-01-01
      • 2020-11-25
      • 2021-08-13
      • 2022-01-09
      • 2019-02-13
      • 2022-01-18
      相关资源
      最近更新 更多