拖曳你的DOM

  • 997
  • 0

使用VUE搭配HTML5拖曳DOM

基本知識

1. 要拖曳的DOM必須加上draggable屬性

2. 拖曳事件

dragstart 開始拖曳的那一刻

dragenter 拖曳標籤進入目標的那一刻

dragover 拖曳標籤在目標內移動的時候

dragleave 拖曳標籤離開目標的那一刻

drop 拖曳標籤放下的那一刻

dragend 拖曳標籤在drop觸發後觸發

3.不想要觸發拖曳事件可以在目標元素加上此css

pointer-events: none;

4.避免可拖曳標籤可以選取到裡面的子標籤

[draggable="true"] {
    /*
     To prevent user selecting inside the drag source
    */
    user-select: none;
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    opacity: 1;
   
}

範例

<template>
  <div class="col-12">
    <div class="shadow-sm d-flex bg-white px-3">
      <div class="overflow-auto table-box mb-2  w-100">
        <table
          border="1"
          class="table table-hover table-bordered table-striped my-3 w-100"
        >
          <colgroup>
            <col
              v-for="(col, key) in catsColumns"
              :key="key"
              :width="col.width"
            >
          </colgroup>
          <thead>
            <tr>
              <th
                v-for="col in catsColumns"
                :key="col.key"
              >
                <template v-if="col.key === 'multiple'">
                  全選
                  <input
                    id=""
                    type="checkbox"
                    name=""
                    :checked="multipleArray.length === catsData.length && multipleArray.length!==0 "
                    @change="multipleHandler"
                  >
                </template>
                <template v-else>
                  {{ col.title
                  }}<i
                    v-if="col.sort"
                    class="fas fa-sort ml-1"
                    @click="sortHandler(col)"
                  />
                </template>
              </th>
            </tr>
          </thead>
          <tbody v-if="catsData.length">
            <template
              v-for="(row,index) in catsData"
            >
              <tr
                :key="row.id"
                class="drag-area"
                :class="{'cursor-pointer':candrag}"
                :draggable="candrag"
                @dragstart="handleDragStart($event, row)"
                @dragenter="handleDragEnter($event, row)"
                @dragover.prevent="dragOver($event, row)"
                @dragleave="handleDragLeave($event, row)"
                @drop="handleDrop($event, row,index)"
                @dragend="handleDragEnd($event, row)"
              >
                <td
                  v-for="(col) in catsColumns"
                  :key="col.col"
                  :class="[
                    { 'input-table': col.type == 'input' },
                    { 'text-left': col.tdAlign == 'left' },
                  ]"
                >
                  <template v-if="col.key === 'options'">
                    <div
                      v-if="!candrag"
                      class="d-flex justify-content-center align-items-center"
                    >
                      <i
                        class="fas fa-edit btn-sm btn btn-outline-primary"
                        @click="editHandler(row)"
                      />
                    </div>
                    <div
                      v-if="candrag"
                      class="d-flex justify-content-center align-items-center   pointer-event-none"
                    >
                      <i
                        class="fas fa-expand-arrows-alt text-primary cursor-pointer pointer-event-none"
                      />
                    </div>
                  </template>
                  <template v-else-if="col.key === 'index'">
                    {{ index + 1 }}
                  </template>
                  <template
                    v-else-if="col.key === 'multiple'"
                  >
                    <input
                      id=""
                      v-model="multipleArray"
                      :value="row"
                      type="checkbox"
                      name=""
                    >
                  </template>
                  <template v-else-if="col.key === 'enabledPro'">
                    {{ row[col.key] ? 'Yes' : 'No' }}
                  </template>
                  <template v-else-if="col.key === 'enabledPlm'">
                    {{ row[col.key] ? 'Yes' : 'No' }}
                  </template>
                  <template v-else>
                    <span>
                      {{
                        row[col.key] != null && row[col.key] != ""
                          ? row[col.key]
                          : isNullStr
                            ? isNullStr
                            : ""
                      }}</span>
                  </template>
                </td>
              </tr>
            </template>
          </tbody>
          <tbody v-else>
            <tr draggable="true">
              <td
                :colspan="catsColumns.length"
                class="text-center"
              >
                <template v-if="isloading">
                  <div class="spinner-grow spinner-grow-sm text-primary" />
                  <div class="spinner-grow spinner-grow-sm text-primary mx-2" />
                  <div class="spinner-grow spinner-grow-sm text-primary" />
                </template>
                <template v-else>
                  <span class="font-weight-bold text-danger"> 查無資料 </span>
                </template>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      catsData: [{},{},{}],
      originCatsData: [],
      catsColumns: [
        {
          title: '功能',
          key: 'options',
          width: '80px'
        },
        {
          title: 'multiple',
          key: 'multiple',
          width: '80px'
        },
        {
          title: '序號',
          key: 'index',
          width: '100px'
        },
        {
          title: '名稱',
          key: 'catName'
        },
        {
          title: '有效否(PLM)',
          key: 'enabledPlm',
          width: '150px'
        },
        {
          title: '有效否(產品)',
          key: 'enabledPro',
          width: '150px'
        }
      ],
      candrag: false,
      dragging: null
    }
  },
  methods: {
    saveSortHandler () {
      const putData = this.catsData.map(cat => {
        return { id: cat.id, catSequence: cat.catSequence }
      })
      apiPutPlmSpecCatesList({
        items: putData
      }).then(res => {
        const { status } = res
        if (status === 200 || status === 204) {
          this.candrag = false
          this.getDataHandler(this.productGroup.productGroup)
        }
      }).catch(err => {
        this.$refs.confirm.show(err.response.data.error.message, '確定')
      })
    },
    cancelSortHandler () {
      this.candrag = false
      this.catsData = this.originCatsData
    },
    // 離開目標 e目標
    handleDragLeave (e) {
      if (!this.candrag) return
      if (e.target.parentNode.classList.contains('drag-area')) {
        e.target.parentNode.classList.remove('enter')
      }
    },
    // 元素開始被拖動 e元素
    handleDragStart (e, item) {
      if (!this.candrag) return
      this.dragging = item
    },
    // 進入目標 e目標
    handleDragEnter (e, data) {
      console.log(e.target.parentNode)
      if (!this.candrag) return
      if (data === this.dragging) return
      if (e.target.parentNode.classList.contains('drag-area')) {
        e.target.parentNode.classList.add('enter')
      }
    },
    // 元素在目標中被拖動 e目標
    dragOver (e, data) {
      if (!this.candrag) return
      // console.log(e.target)
      // 設定指標樣式
      e.dataTransfer.dropEffect = 'move'
    },
    // 放置目標 e目標
    handleDrop (e, item) {
      if (!this.candrag) return
      if (e.target.parentNode.classList.contains('drag-area')) {
        e.target.parentNode.classList.remove('enter')
      }
      if (item === this.dragging) {
        return
      }
      const newItems = [...this.catsData]
      const from = newItems.indexOf(this.dragging)
      const to = newItems.indexOf(item)
      const originCatSequence = newItems[from].catSequence
      newItems[from].catSequence = newItems[to].catSequence
      newItems[to].catSequence = originCatSequence
      newItems[from] = item
      newItems[to] = this.dragging
      newItems.forEach((row, index) => {
        row.catSequence = index + 1
      })
      this.catsData = newItems
    },
    // 放置目標後 e元素
    handleDragEnd () {
      this.dragging = null
    }
  }
}
</script>