vue使用动态组件+拖拽+grid布局实现页面不同组件显示、切换布局、拖拽排序

913 阅读1分钟

遇到这么一个需求,如下图所示有很多图表组件,要能通过右上角按钮切换一行显示几个图表,图表块还要能拖拽、排序,一番摸索后记录一下实现思路。

image.png

1、首先,布局切换打算使用grid布局来实现,[具体可以看我另一篇文章](使用grid布局实现页面布局切换 - 掘金 (juejin.cn))
2、拖拽元素,选择之前使用过的 vuedraggable 插件实现,拖拽后数据对象排序也实时变化。
    vue.draggable.nextvue.draggablevue3版本,使用文档如下
    [中文文档](https://www.itxst.com/vue-draggable-next/tutorial.html)
    [gihub](https://github.com/SortableJS/vue.draggable.next)
3、因为要记录拖拽排序的顺序,所以组件不可能一个个写在模板里,得配合 第2 里的拖拽插件,根据数据来动态渲染显示那个组件,所以就用到了vue中的动态组件
<component :is="currentTab"></component>

image.png 通过数据记录组件的名称,通过vuedraggable渲染动态组件,并实现拖动

代码如下
<template>
  <div class="test">
    <!-- 顶部按钮 -->
    <div class="button-block">
      <el-radio-group v-model="radio" size="large">
        <el-radio-button label="1">
          <span class="iconfont icon-shuang"></span
        ></el-radio-button>
        <el-radio-button label="2">
          <span class="iconfont icon-san"></span
        ></el-radio-button>
      </el-radio-group>
    </div>
    <!-- 可拖拽插件 通过class控制grid属性,切换布局 -->
    <draggable
      v-model="myArray"
      item-key="id"
      @end="onEnd"
      class="content"
      :class="{ grid2: radio == '1', grid4: radio == '2' }"
    >
      <!-- is匹配到的组件名,即会渲染该组件 -->
      <template #item="{ element }">
        <component :is="element.comp"></component>
      </template>
    </draggable>
  </div>
</template>
<script>
import draggable from "vuedraggable";

// 引入组件
import Comp1 from "./comp/comp1.vue";
import Comp2 from "./comp/comp2.vue";
import Comp3 from "./comp/comp3.vue";
export default {
  components: {
    draggable,
    // 注册组件
    Comp1,
    Comp2,
    Comp3,
  },
  data() {
    return {
      radio: "1",
      // 保存了组件名的数据
      myArray: [
        { name: "11", id: 0, comp: "comp1" },
        { name: "22", id: 1, comp: "comp3" },
        { name: "33", id: 2, comp: "comp2" },
        { name: "44", id: 3, comp: "comp2" },
        { name: "55", id: 4, comp: "comp1" },
        { name: "66", id: 5, comp: "comp3" },
        { name: "66", id: 6, comp: "comp2" },
      ],
    };
  },
  watch: {
    radio(val) {
      console.log(val);
    },
  },
  methods: {
    // vuedraggable 拖拽结束事件处罚方法
    onEnd() {
      console.log(this.myArray);
    },
  },
};
</script>
<style lang="scss" scoped>
.test {
  .button-block {
    text-align: center;
  }
  .content {
    margin-top: 20px;
    display: grid;
    grid-gap: 16px;
  }
}
// 不同布局样式
.grid2 {
  grid-template-columns: repeat(2, 1fr);
}
.grid4 {
  grid-template-columns: repeat(4, 1fr);
}
</style>

组件内
// 组件1
<template>
  <div class="comp1">comp1</div>
</template>
<style lang="scss" scoped>
.comp1 {
  height: 100px;
  background-color: #f82a42;
  border-radius: 8px;
}
</style>

实现效果

一行2个布局

image.png 一行4个布局

image.png 拖拽前数组排序

image.png 拖拽后数组排序

image.png

4、最后
  在上述基础上,最开始的需求中,将按钮绑定的值保存在vuex(或pinia中),在各个组件中监听值的变化,布局切换后,
  组件中使用echarts.resize()重新渲染图表即完成。