【vue3】使用vuedraggable和grid实现自定义拖拽布局

4 篇文章 0 订阅

实现思路:使用vuedraggable实现拖拽功能,拖拽改变的是模块在list的顺序,使用gird设置动态类名,根据模块在list的位置匹配对应的gird样式。
效果图:每个模块可以拖拽,不同数量和不同位置模块宽度和高度不同(注意:模块样式width:100%,height:100%)

图1-标准布局

图2-三块布局

图3-自定义布局

<template>
  <div class="wrap">
    <div class="flex-row-start defineLayout">
      <div class="flex-row" @click="changeLayout(LayoutType.FOUR)">
        <div class="name">标准布局</div>
      </div>
      <div class="flex-row" @click="changeLayout(LayoutType.THREE)">
        <div class="name">三块布局</div>
      </div>
      <el-dropdown ref="dropdown1" trigger="contextmenu" style="margin-right: 30px">
        <div class="flex-row el-dropdown-link" @click="() => {
          if (dropdown1) dropdown1.handleOpen();
        }">
          <div class="name">自定义布局</div>
        </div>
        <template #dropdown>
          <el-checkbox-group class="flex-col-start" v-model="checkedIdList" :max="4" style="padding: 10px 0 10px 30px;">
            <el-checkbox @change="changeLayout(LayoutType.DEFINE)" v-for="(item, index) of cList" :key="index"
              :label='item.id'>{{
                item.name }}</el-checkbox>
          </el-checkbox-group>
        </template>
      </el-dropdown>
    </div>
    <div class="draggable-border">
      <draggable :list="moduleList" item-key="id" :options="{ animation: 200, ghostClass: 'ghost' }" :class="{
        gird1col: moduleList.length == 1,
        gird2col: moduleList.length == 2,
        gird3col: moduleList.length == 3,
        gird4col: moduleList.length == 4
      }">
        <template #item="{ element, index }">
          <component :ref="element.ref" :is="element.component" :name="element.name" :class="{
            [`dragItem${index}`]: true,
          }">
          </component>
        </template>
      </draggable>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { useState, useMutations } from "@/utils/useStore";
import Block1 from '@/components/block1/block1';
import Block2 from '@/components/block2/block2';
import Block3 from '@/components/block3/block3';
import Block4 from '@/components/block4/block4';
import Block5 from '@/components/block5/block5.vue';

//@ts-ignore
import draggable from "vuedraggable";
import { LayoutType } from '@/utils/enum';

//资源对象
let resource = ref<any>();
//@ts-ignore
const { moduleList } = useState(["moduleList"], "drag");
//@ts-ignore
const { setModuleList } = useMutations(["setModuleList"], "drag");

let dropdown1 = ref();
let checkedIdList = ref<number[]>([]);//自定义选择的模块

let cList: any[] = [
  {
    type: '1',
    id: 1,
    name: '块1',
    component: Block1
  }, {
    type: '1',
    id: 2,
    name: '块2',
    component: Block2
  }, {
    type: '2',
    id: 3,
    name: '块3',
    component: Block3
  }, {
    type: '2',
    id: 4,
    name: '块4',
    component: Block4
  }, {
    type: '2',
    id: 5,
    name: '块5',
    component: Block5
  },
];

onMounted(() => {
  setCompontent([1, 2, 3, 4]);
})

// 自定义当前页包含组件
const setCompontent = (idList: number[]) => {
  checkedIdList.value = idList;
  let list = cList.filter((f: any) => {
    return idList.indexOf(f.id) != -1;
  });
  setModuleList(list);
  console.log("list", list);
};

// 切换布局
const changeLayout = (type) => {
  switch (type) {
    case LayoutType.THREE:
      setCompontent([1, 2, 5]);
      break;
    case LayoutType.DEFINE:
      if (checkedIdList.value) setCompontent(checkedIdList.value);
      break;
    default:
      // 默认四宫格
      setCompontent([1, 2, 3, 4]);
      break;
  }
}
</script>
<style scoped lang="scss">
.wrap {
  height: 100vh;
  width: 100vw;
  position: relative;
  display: block;
  overflow: hidden;

  .defineLayout {
    color: #fff;
    height: 41px;
    width: 100%;
    background-color: #000;
    align-items: center;
    padding: 0 20px;

    .name {
      font-size: 12px;
      font-weight: 500;
      color: #FFFFFF;
      line-height: 17px;
      margin-left: 5px;
      margin-right: 20px;
      cursor: pointer;
    }
  }

  .draggable-border {
    background-color: #fff;
    width: 100%;
    height: calc(100vh - 41px);
  }
}

// 设置拖拽组件的样式
.draggable-border>div {
  width: 100%;
  height: 100%;
  display: grid;
  grid:
    'one two'
    'three four';
  grid-template-columns: 50% 50%;
  grid-template-rows: 50% 50%;
}

.gird4col {
  grid:
    'one two'
    'three four' !important;
  grid-template-columns: 50% 50% !important;
  grid-template-rows: 50% 50% !important;
}

.gird3col {
  grid:
    'one three'
    'two three' !important;
  grid-template-columns: 50% 50% !important;
  grid-template-rows: 50% 50% !important;
}

.gird2col {
  grid:
    'one two'
    'one two' !important;
  grid-template-columns: 50% 50% !important;
  grid-template-rows: 50% 50% !important;
}

.gird1col {
  grid:
    'one' !important;
  grid-template-columns: 100% !important;
  grid-template-rows: 100% !important;
}

.fullscreen {
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 999;
}

.dragItem0 {
  grid-area: one;
}

.dragItem1 {
  grid-area: two;
}

.dragItem2 {
  grid-area: three;
}

.dragItem3 {
  grid-area: four;
}
</style>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3中使用vuedraggable是一种在前端开发中实现拖拽功能的方法。根据引用,vuedraggable适合有1-3年工作经验的前端人员使用。如果在安装过程中出现报错"Cannot read property 'header' of undefined",可以尝试安装最新版本的vuedraggable,通过命令行执行npm i -S vuedraggable@next。这样可能可以解决该报错问题,参考引用提供的解决方案。 要在Vue3中使用vuedraggable,可以按照以下方式编写代码,参考引用提供的示例代码: ```javascript <template> <draggable v-model="myArray" group="people" @start="drag=true" @end="drag=false" item-key="id"> <template #item="{element}"> <div>{{element.name}}</div> </template> </draggable> </template> <script lang="ts"> import { defineComponent, reactive, toRefs } from 'vue' import draggable from 'vuedraggable' export default defineComponent({ components: { draggable }, setup () { const data = reactive({ drag: false, myArray: [ { id: 1, name: 'Jenny' }, { id: 2, name: 'kevin' }, { id: 3, name: 'lili' } ] }) return { ...toRefs(data) } } }) </script> ``` 以上代码中,通过import导入了vuedraggable组件,并在template中使用draggable标签来实现拖拽功能。在setup函数中,使用reactive将数据进行响应式处理,并通过v-model绑定到draggable组件上,实现了列表的拖拽功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vue3中使用vuedraggable](https://download.csdn.net/download/digital_AI/87823951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Vue3 使用 vuedraggable](https://blog.csdn.net/lhz_333/article/details/123403911)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值