使用vuedraggable实现首页定制化

242 阅读1分钟

1. 前言

项目开发中需要首页进行定制化,依据不同用户按照自己喜好添加模块并能够进行拖拽排序等功能,本篇是自己在项目开发前基于vuedraggable开发的一个demo。由于在vuedraggable简单的示例基础上进行修改了很多东西,在开发时踩了很多坑...太难了

20220902_152043.gif

2. 安装

1.npm install vuedraggable     //安装
2.import draggable from 'vuedraggeable'   //引入

3. 示例

1.父组件的代码

  <div class="drag_demo allContainerStyle">

    <div class="Flex">
     <draggable
        class="left"
        v-model="list1"
        group="taskbar"
        v-bind="dragOptions"
        :move="onMoveLeft"
        @start="startDragLeft"
        @end="endDragLeft"
        @unchoose="unchooseLeft"
      >
        <transition-group tag="div" class="transition_div transition_div_left">
          <div
            ref="leftComponents"
            class="drag_item drag_item_left"
            v-for="item in list1"
            :key="item.id"
            :componentIsDrag="item.isDrag"
            @mousedown="leftRemoveClass()"
          >
            <component
              :is="item.component"
              :isDrag="isDrag"
              :id="item.id"
              :title="item.title"
              position="left"
              @edit="editBtn"
              @hide="hideBtn"
            ></component>
          </div>
        </transition-group>
      </draggable>

      <draggable
        class="right"
        v-model="list2"
        group="taskbar"
        v-bind="dragOptions"
        :move="onMoveRight"
        @start="startDragRight"
        @end="endDragRight"
        @unchoose="unchooseRight"
      >
        <transition-group tag="div" class="transition_div transition_div_right">
          <div
            ref="rightComponents"
            class="drag_item drag_item_right"
            v-for="item in list2"
            :key="item.id"
            :componentIsDrag="item.isDrag"
            @mousedown="rightRemoveClass()"
          >
            <component
              :is="item.component"
              :isDrag="isDrag"
              :id="item.id"
              :title="item.title"
              position="right"
              @edit="editBtn"
              @hide="hideBtn"
            ></component>
          </div>
        </transition-group>
      </draggable>
    </div>

  </div>
</template>

<script>
import draggable from "vuedraggable";
import drag1 from "@/views/monitor/components/drag1";
import drag2 from "@/views/monitor/components/drag2";
import drag3 from "@/views/monitor/components/drag3";
import drag4 from "@/views/monitor/components/drag4";
import drag5 from "@/views/monitor/components/drag5";
import drag6 from "@/views/monitor/components/drag6";
import drag7 from "@/views/monitor/components/drag7";
import drag8 from "@/views/monitor/components/drag8";
export default {
  components: {
    draggable,
    drag1,
    drag2,
    drag3,
    drag4,
    drag5,
    drag6,
    drag7,
    drag8,
  },
  data() {
    return {
      title: "",
      dialogVisible: false,

      iSMove: false, //为false时,对于不能左右移动的,显示弹窗
      isDrag: false, //

      dragOptions: {
        animation: 120,
        scroll: true,
        group: "sortlist",
        handle: ".allDragHeader",
        ghostClass: "ghostClass", // 设置拖动元素的class的占位符的类名。
        chosenClass: "chosenClass", // 设置被选中的元素的class
        dragClass: "dragClass", //拖动元素的class。
      },
      list1: [
        {
          id: 1,
          component: "drag1",
          isDrag: true,
          title: "组件一",
        },
        {
          id: 2,
          component: "drag2",
          isDrag: false,
          title: "组件二",
        },
        {
          id: 3,
          component: "drag3",
          isDrag: true,
          title: "组件三",
        },
        {
          id: 4,
          component: "drag4",
          isDrag: true,
          title: "组件四",
        },
      ],
      list2: [
        {
          id: 6,
          component: "drag6",
          isDrag: false,
          title: "组件六",
        },
        {
          id: 7,
          component: "drag7",
          isDrag: true,
          title: "组件七",
        },
      ],
    };
  },
  methods: {
   /**
     * 左边---开始拖拽
     * 拖拽开始时,隐藏元素的内容,显示头部
     */
    startDragLeft(e) {
      this.isDrag = true;
    },
    /**
     * 左边---拖拽过程中
     * 在元素拖拽过程,存在只能在上下拖拽,无法将元素拖入右边模块
     */
    onMoveLeft(e, originalEvent) {
      this.iSMove = true;
      if (e.draggedContext.element.isDrag == true) return true;
      if (e.to.classList[1] == "transition_div_left") {
        return true;
      } else {
        this.iSMove = false;
        return false;
      }
    },
    /**
     * 左边---结束拖拽
     * 拖拽开始时,隐藏元素的内容,显示头部
     */
    endDragLeft(e) {
      if (!this.iSMove) {
        this.$message.error(e.item.innerText + "此区域无法放在右侧");
        return false;
      }
    },
    /**
     * 左边元素不选中时,将isdrag变成false,元素内容显示出来
     */
    unchooseLeft(e) {
      this.isDrag = false;
    },
    /**
     * 移除dragClass属性
     */
    leftRemoveClass() {
      this.$refs.leftComponents.forEach((item) => {
        console.log(item.className);
        item.className = item.className.split("dragClass")[0];
      });
    },


     /**
     * 以下为右边模块元素拖拽的方法
     *
     * 解释同上
     */
    startDragRight(e) {
      this.isDrag = true;
    },
    onMoveRight(e, originalEvent) {
      this.iSMove = true;
      if (e.draggedContext.element.isDrag == true) return true;
      if (e.to.classList[1] == "transition_div_right") {
        return true;
      } else {
        this.iSMove = false;
        return false;
      }
    },
    endDragRight(e) {
      if (!this.iSMove) {
        this.$message.error(e.item.innerText + "此区域无法放在左侧");
        return false;
      }
    },
    unchooseRight(e) {
      this.isDrag = false;
    },
    rightRemoveClass() {
      this.$refs.rightComponents.forEach((item) => {
        console.log(item.className);
        item.className = item.className.split("dragClass")[0];
      });
    },
  },
};
</script>

<style lang="scss">
  .drag_demo {
    padding-top: 30px;
    overflow-y: auto;
  }

  .left {
    width: 60%;
    padding-right: 10px;
  }

  .right {
    width: 40%;
    padding-left: 10px;
  }

  .transition_div {
    width: 100%;
    min-height: 700px;
  }

  .drag_item {
    .allDragHeader {
      cursor: move;
    }
  }

  .dragClass {
    .allDragHeader {
      background: transparent;

      .allDragHeaderTitle {
        color: transparent;
      }
    }

    .allDragContent,
    .allDragOperation {
      display: none;
    }
  }

  .chosenClass {}

  .ghostClass {
    background: red !important;
    border-radius: 6px;
    margin-bottom: 20px;

    .allDragHeader {
      background: transparent;
    }

    .allDragOperation {
      display: none;
    }
  }



  .allDragContainer {
    margin-bottom: 20px;
    overflow: hidden;
    border-radius: 6px;
    position: relative;

    .allDragHeader {
      border-top-left-radius: 6px;
      border-top-right-radius: 6px;
      padding: 0 20px;
      line-height: 42px;
      background: #308FFC;

      .allDragHeaderTitle {
        font-size: 16px !important;
        font-weight: bold;
        color: #fff;
      }
    }
  }

  .allDragContent {
    border-bottom-left-radius: 6px;
    border-bottom-right-radius: 6px;
    background-color: #fff;
  }
  }
</style>

2.在父组件中引入的子组件以drag1.vue为示例

  <div class="allDragContainer qqqq">
    <div class="allDragHeader">
      <span class="allDragHeaderTitle">{{ title }}</span>
    </div>

    <div class="allDragContent" v-show="!isDrag">
      <div id="ageDistribution" style="width: 100%; height: 280px"></div>
    </div>
  </div>
</template>

<script>
export default {
  name: "drag1",
  props: {
    //控制元素内容的显隐
    isDrag: {
      type: Boolean,
    },

    //元素的id
    id: {
      type: Number,
    },

    //元素的在父组件中的位置,左边or右边
    position: {
      type: String,
    },

    //元素的title
    title: {
      type: String,
    },
  },
  data() {
    return {};
  },

  methods: {
    edit() {
      this.$emit("edit", { id: this.id, position: this.position });
    },
    hide() {
      this.$emit("hide", { id: this.id, position: this.position });
    },
  },
};
</script>

4. 解决问题

1.当两个模块中存在一个为空的情况时,很难将元素拖入其中,后来又去扒文档,发现需要给transition-group设置高度即可解决此问题。

<style>
 .transition_div {
  width: 100%;
  min-height: 700px;
}
</style>

2.在自定义元素拖拽过程中,多次反复拖拽鼠标松开后,又出现因dragClass属性导致,元素无法显示的状况,如图所示。

image.png

通过ref将元素里面在控制台打印出来,通过mousedown方法在for循环中移除该属性(不知道为什么会这些这种情况...)

//for循环移除
this.$refs.rightComponents.forEach((item) => {
  console.log(item.className);
  item.className = item.className.split("dragClass")[0];
});

1662098338464_E3BCAD99-78E5-4254-A63D-E630B9A8729F.png