自己封装的拖拽的盒子组件

42 阅读1分钟

image.png

先上效果图,里面的球都可以拖动,也可以添加,都会有对应的函数,都是用原生js做的.其实我更推荐使用

<template>
  <div class="bluebox" :style="{ width: `${(row + 1) * 35}px`, height: `${(cols + 1) * 34}px` }">
    <div :style="{ marginLeft: '32px', width: `${(row + 1) * 34}px` }">
      <div class="topnum" v-for="item in row" :key="item">
        {{ item }}
      </div>
    </div>
    <div style="display: flex">
      <div>
        <div class="leftnum" v-for="item in cols" :key="item">
          {{ item }}
        </div>
      </div>
      <div>
        <div v-for="ai in cols" :key="ai" style="height: 32px; margin-bottom: 1px; display: flex">
          <div @drop="end" class="sonbox" v-for="item in row" :key="item" @dragenter="(event) => event.preventDefault()"
            @dragover="(event) => event.preventDefault()">
            <div @click="rollShow(data[(ai - 1) * row + item - 1])" :draggable="draggable" @drop="drop"
              @dragstart="handleDragStart($event, items)" class="sphere dragbox"
              v-show="data[(ai - 1) * row + item - 1]?.isshow" :style="{
                backgroundColor: data[(ai - 1) * row + item - 1]?.strainIndex >= 0 ? '#d7d7d7' : '',
              }">
              <span style="font-size: 0">{{ data[(ai - 1) * row + item - 1]?.text }}</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, defineEmits, watch, defineExpose } from 'vue';
const emit = defineEmits(['endDraggable', 'rollShow']);
const data = ref([]);
const props = defineProps({
  row: { type: Number, default: 10 },
  cols: { type: Number, default: 10 },
  list: {
    type: Array,
    default: [],
  },
  //true是允许  false是禁止
  draggable: { type: Boolean, default: false },
});
for (let index = 0; index < 100; index++) {
  data.value.push({
    text: index,
    isshow: false,
  });
}
const rest = () => {
  data.value = []
  for (let index = 0; index < 100; index++) {
    data.value.push({
      text: index,
      isshow: false,
    });
  }
};
const drop = (e) => {
  e.preventDefault();
};
const updata = () => {
  rest();
  props.list.forEach((item) => {
    item.text = item.sortIndex;
    item.isshow = true;
    data.value[item.sortIndex] = item;
  });
  let num = data.value.findIndex((item) => item == undefined);
};
watch(
  () => props.list.length,
  (val, prevVal) => {
    updata();
  },
);
//获取点击蓝色球的数据
const rollShow = (data) => {
  // 把数据在多少行返回出去
  emit(
    'rollShow',
    props.list.findIndex((item) => item.id == data.id),
  );
};
let dragging = reactive();
const handleDragStart = (e, items) => {
  if (!props.draggable || data.value[e.target.lastChild.textContent]?.strainIndex >= 0) return;
  dragging = e.target.lastChild.textContent; //开始拖动时,暂时保存当前拖动的数据。
};

const end = (e) => {
  if (!props.draggable || !dragging || data.value[e.target.lastChild.textContent]?.strainIndex >= 0) return (dragging = null);
  const text = Number(e.target.lastChild.textContent);
  dragging = Number(dragging);
  if (text == dragging) return;
  let change = { ...data.value[text] };
  data.value[text] = data.value[dragging];
  data.value[text].text = text;
  data.value[dragging] = change;
  data.value[dragging].text = dragging;
  emit('endDraggable', [dragging, text]);
  dragging = '';
};
</script>
<style lang="less" scoped>
.bluebox {
  border: 1px solid skyblue;

  .topnum {
    height: 30px;
    width: 30px;
    display: inline-block;
    text-align: center;
    margin: 0 3px 3px 0;
    line-height: 30px;
  }

  .leftnum {
    height: 32px;
    width: 30px;
    text-align: center;
    margin: 0 0 1px 0;
    line-height: 30px;
  }

  .sonbox {
    height: 30px;
    width: 30px;
    display: inline-block;
    background-color: #efefef;
    margin: 0 3px 0 0;

    .sphere {
      height: 30px;
      width: 30px;
      border-radius: 15px;
      background-color: skyblue;
    }
  }
}

.dragbox[dragging] {
  height: 30px;
  width: 30px;
  border-radius: 15px;
  background-color: skyblue;
}

.dropbox[over] {
  display: none;
}
</style>

数组里面的对象需要有sortIndex,这个是用来定位的