1. 程式人生 > 其它 >vue 後管專案實現跨目錄拖拽功能

vue 後管專案實現跨目錄拖拽功能

我使用的是vuedraggable外掛。參考文件:https://www.itxst.com/vue-draggable/fueijmfy.html

安裝:npm i -S vuedraggable

引入:importdraggablefrom'vuedraggable'

<template>
  <div class="classification_configuration">
    <a-card>
      <div class="content" v-for="(items, indexs) in classificationList" :key="indexs">
        <div class="content_title">
          <h4 v-show="items.moduleTypeShow">{{items.moduleType}}</h4>
          <div v-show="!items.moduleTypeShow" class="content_edit">
            <a-input v-model="dataTitle" placeholder="請輸入內容" />
          </div>
          <img v-show="items.moduleTypeShow" @click="clickEdit(items, indexs)" class="image_edit" src="../../assets/img/edit.png" />
          <img v-show="items.moduleTypeShow && items.menuSubList.length === 0 " @click="clickDelete(indexs)" src="../../assets/img/delete.png" />
          <span v-show="!items.moduleTypeShow" @click="clickSave(indexs)" style="margin-left: 16px; margin-right: 8px;">儲存</span>
          <span v-show="!items.moduleTypeShow" @click="clickSaveCancel(indexs)">取消</span>
        </div>
        <draggable v-model="items.menuSubList" group="site"  animation="300" dragClass="dragClass"  ghostClass="ghostClass" chosenClass="chosenClass" @start="onStart" @end="onEnd">
          <transition-group class="content_con">
            <div class="content_card" v-for="item in items.menuSubList" :key="item.id"><img class="content_image" :src="item.imgUrl" :alt="item.appName">{{item.appName}}</div>
          </transition-group>
        </draggable>
        <!-- <div class="content_title">
          <h4 v-show="items.moduleTypeShow">{{items.moduleType}}</h4>
          <div v-show="!items.moduleTypeShow" class="content_edit"><a-input :value="dataTitle" placeholder="請輸入內容" /></div>
          <img v-show="items.moduleTypeShow" @click="clickEdit(items, indexs)" class="image_edit" src="../../assets/img/edit.png" />
          <img v-show="items.moduleTypeShow && items.menuSubList.length === 0 " @click="clickDelete(indexs)" src="../../assets/img/delete.png" />
          <span v-show="!items.moduleTypeShow" @click="clickSave(indexs)" style="margin-left: 16px; margin-right: 8px;">儲存</span>
          <span v-show="!items.moduleTypeShow" @click="clickSaveCancel(indexs)">取消</span>
        </div>
        <div class="content_con">
          <div class="content_card" v-for="(item, index) in items.menuSubList" :key="index" :draggable="true" @dragstart="dragStart(items, item)" @dragenter="dragEnter(items, item,$event)" @dragend="dragEnd(items, item, $event)" @dragover="dragOver($event)">
            <img class="content_image" :src="item.imgUrl" :alt="item.appName">
            {{item.appName}}
          </div>
        </div> -->
      </div>
      <div class="add_list" @click="clickAddList()"><img src="../../assets/img/add.png" />新增應用分類</div>
    </a-card>
    <div class="content_bottom">
      <div></div>
      <div>
        <a-button @click="clickCancel()">取消</a-button>
        <a-button @click="clickPreview()" class="button_class">預覽</a-button>
        <a-button @click="clickRelease()" class="button_class" type="primary">釋出</a-button>
      </div>
    </div>
    <div class="messge" v-show="showPreview">
      <div class="messge_con test">
        <div class="card">
          <div v-for="(elements, indexs) in classificationList" :key="indexs">
            <h4>{{elements.moduleType}}<span class="card_shadow"></span></h4>
            <div class="content">
              <div class="content_card" v-for="(element, index) in elements.menuSubList" :key="index">
                <img :src="element.imgUrl" />
                <div>{{element.appName}}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="messge_but" @click="showPreview = false"><img class="que" src="../../assets/img/close.png" /></div>
    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex';
import draggable from 'vuedraggable'
import { buttonPermission } from '../../util/util';

export default {
  components: {
    draggable,
  },
  // computed: {
  //   ...mapGetters(['classificationList']),
  // },
  data() {
    return {
      drag: false,
      classificationList: [],
      moduleTypeShow: true,
      dataTitle: '',
      // oldData: null,
      // newData: null,
      oldData: {
        module: null,
        menuSubList: [],
      },
      newData: {
        module: null,
        menuSubList: [],
      },
      dataList: [
        { id:1,appName:'測試一號' },
        { id:2,appName:'測試二號' },
        { id:3,appName:'測試三號' },
        { id:4,appName:'測試四號' },
      ],
      showPreview: false,
    };
  },
  created() {
    this.$store.commit('SET_MENU', '/classification');
    this.init();
  },
  methods: {
    init() {
      this.$store.dispatch('getClassificationListAction').then(res => {
        this.classificationList = res.data.menuList.map(({
          module,
          moduleType,
          menuSubList,
        }) => {
          return {
            module,
            moduleType,
            menuSubList,
            moduleTypeShow: true,
          }
        });
      }).catch(err => {
        console.error(err);
      });
    },
    //開始拖拽事件
    onStart() {
      this.drag = true;
    },
    //拖拽結束事件
    onEnd() {
      this.drag = false;
    },
    clickEdit(items, indexs) {
      this.dataTitle = items.moduleType;
      this.classificationList[indexs].moduleTypeShow = false;
    },
    clickDelete(indexs) {
      this.classificationList.splice(indexs, 1);
    },
    clickSave(indexs) {
      this.classificationList[indexs].moduleType = this.dataTitle;
      this.classificationList[indexs].moduleTypeShow = true;
    },
    clickSaveCancel(indexs) {
      if (this.dataTitle === '') {
        this.classificationList.splice(indexs, 1);
      } else {
        this.classificationList[indexs].moduleTypeShow = true;
        this.dataTitle = '';
      }
    },
    dragStart(items, value) {
      // this.oldData = value;
      this.oldData.module = items.module;
      this.oldData.menuSubList[0] = value;
    },
    dragEnter(items, value, e) {
      // this.newData = value;
      this.newData.module = items.module;
      this.newData.menuSubList[0] = value;
      e.preventDefault();
    },
    dragEnd(items, item, e) {
      if (this.oldData !== this.newData) {
        // let oldIndex = this.dataList.indexOf(this.oldData);
        // let newIndex = this.dataList.indexOf(this.newData);
        // let newItems = [...this.dataList];
        // // 刪除老的節點
        // newItems.splice(oldIndex, 1);
        // // 在列表中目標位置增加新的節點
        // newItems.splice(newIndex, 0, this.oldData);
        // this.dataList = [...newItems];
        this.classificationList = [...newItems];
      }
    },
    dragOver(e) {
      e.preventDefault();
    },
    clickAddList() {
      this.dataTitle = '';
      this.classificationList.push({
        moduleType: '',
        menuSubList: [],
        moduleTypeShow: false,
      });
    },
    clickCancel() {
      const that = this;
      this.$confirm({
        title: '確認取消嗎?',
        okText: '確認',
        cancelText: '取消',
        onOk() {
          that.init();
        },
      });
    },
    clickPreview() {
      this.showPreview = true;
    },
    clickRelease() {
      let dataMessage = '';
      this.classificationList.forEach(item => {
        if (!item.moduleTypeShow) {
          dataMessage = '您還未儲存更改名稱!'
        }
      })
      if (dataMessage === '') {
        this.$store.dispatch('giveReleaseAction', { menuList: this.classificationList }).then(res => {
          if (res.resultCode === '1') {
            this.$message.success('釋出成功!');
          } else {
            this.$message.error(res.message);
          }
        }).catch(err => {
          console.error(err);
        })
      } else {
        debugger
        this.$message.error(dataMessage);
      }
    },
  },
};
</script>

<style lang="less" scoped>
.classification_configuration {
  font-size: 14px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  color: rgba(0, 0, 0, 0.85);
  line-height: 14px;
  .content {
    .content_title{
      font-size: 16px;
      font-family: PingFangSC-Medium, PingFang SC;
      font-weight: 500;
      line-height: 16px;
      display: flex;
      align-items: center;
      .content_edit{
        width: 120px;
        display: inline-block;
      }
      img{
        width: 18px;
        height: 18px;
        cursor: pointer;
      }
      .image_edit{
        margin-left: 15px;
        margin-right: 12px;
      }
      span{
        cursor: pointer;
        font-size: 14px;
        font-family: PingFangSC-Regular, PingFang SC;
        font-weight: 400;
        color: #1890FF;
        line-height: 24px;
      }
    }
    .content_con{
      margin: 8px 0 28px 0;
      display: flex;
      flex-wrap: wrap;
      .content_card{
        cursor: pointer;
        width: 23.45%; //254px
        height: 50px;
        background: #F8F8F8;
        border-radius: 2px;
        line-height: 50px;
        padding-left: 8px;
        display: flex;
        align-items: center;
        margin-right: 24px;
        margin-top: 12px;
        .content_image{
          width: 24px;
          height: 23px;
          margin-right: 9px;
        }
      }
    }
  }
  .add_list{
    cursor: pointer;
    height: 32px;
    // line-height: 2;
    border: 1px dashed #e8e8e8;
    // text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
    img{
      width: 12px;
      margin-right: 7px;
    }
  }
  .content_bottom {
    height: 56px;
    width: calc(~"100% - 250px");
    width: -moz-calc(~"100% - 250px");
    width: -webkit-calc(~"100% - 250px");
    background: #ffffff;
    position: fixed;
    bottom: 0;
    box-shadow: 0px -1px 2px 0px rgba(0, 0, 0, 0.03);
    filter: blur(0px);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px 0 48px;
    .ant-btn-link {
      color: rgba(0, 0, 0, 0.45);
    }
    .button_class {
      margin-left: 8px;
    }
  }
  .messge{
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
    width: -webkit-fill-available;
    height: -webkit-fill-available;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
    -webkit-transition: .2s;
    transition: .2s;
    background-color: rgba(36, 36, 36, 0.5);
    z-index: 999;
    color: #2B333F;
    line-height: 16px;
    .messge_con{
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate3d(-50%, -50%, 0);
      width: 87%;
      background-color: #FFFFFF;
      border-radius: 4px;
      // width: 30%;
      // height: 90%;
      width: 391px;
      height: 667px;
      overflow: auto;
      .card{
        padding: 16px 15px 26px 18px;
        h4{
          font-size: 16px;
          font-family: PingFangSC-Medium, PingFang SC;
          font-weight: bold;
          color: #333333;
          line-height: 22px;
        }
        .card_shadow{
          display: inline-block;
          width: 36px;
          height: 16px;
          background: linear-gradient(180deg, #FECF00 0%, #F9BD0A 100%);
          box-shadow: 0px 4px 8px 0px rgba(253, 202, 4, 0.45);
          border-radius: 8px;
          opacity: 0.25;
          position: relative;
          top: 10px;
          left: -20px;
        }
        .content{
          margin-left: 7px;
          display: flex;
          flex-wrap: wrap;
          margin-top: 16px;
          margin-bottom: 24px;
          .content_card{
            width: 22.1%;
            margin-right: 10px;
            margin-bottom: 8px;
            text-align: center;
          }
          img{
            width: 36px;
            height: 36px;
          }
        }
      }
    }
    .test::-webkit-scrollbar {/*滾動條整體樣式*/
      width: 6px;
      height: 50px;
      background: #595959;
      // border-radius: 3px;
      // opacity: 0.64;
    }
    .test::-webkit-scrollbar-thumb {/*滾動條整體樣式*/
      // width: 6px;
      // height: 10px;
      background: #595959;
      border-radius: 3px;
    }
    .test::-webkit-scrollbar-track {/*滾動條裡面軌道*/
      background: #FFFFFF;
      border-radius: 4px;
    }
    .messge_but{
      cursor: pointer;
      position: fixed;
      top: 88%;
      left: 50%;
      .que{
        width: 36px;
      }
    }
  }
}
</style>

  效果: