vue下使用drag完成简单拖拽

因为没有时间研究jquery的sortable功能(也没有文档),所以用HTML5的drag完成了简单的拖拽,这里记录下

`@dragstart` , `@dragover` , `@dragend` , `dragable`

dragable 确认可以被拖拽的元素

<ul @dragstart="onDragStart($event)" 
   @dragover="onDragOver($event)" @dragend="onDragEnd($event)" ref="box"> <li v-for="(item,index) in options" :index="index" class="item" draggable="true" :value="item.value" :key="item.value" v-show="item._checked"> {{item.label}} </li>
</ul>

script内部代码

/**
       * 拖拽开始
       */
      onDragStart(e) {
        boxHeight = Math.floor(e.target.offsetHeight/2)
        this.draging = e.target
      },

/**
       * 拖拽过程
       */
      onDragOver(e) {
//      console.log('move', e)
        this.target = e.target
        let targetTop = e.target.getBoundingClientRect().top
        let dragingTop = this.draging.getBoundingClientRect().top
//      console.log('drag move', targetTop)
        if(this.target.nodeName==='LI'&&this.target !== this.draging) {
          if(this.target&&this.target.animated) {
            return
          }
          let targetIndex = this.target.getAttribute('index')
          let dragingIndex = this.draging.getAttribute('index')
          if(targetIndex > dragingIndex) {//拖拽元素往下移动
            //target的下一个元素
            this.target.parentNode.insertBefore(this.draging, this.target.nextSibling)
          }else{
            this.target.parentNode.insertBefore(this.draging, this.target)
          }
          this._animation(targetTop, this.target)
          this._animation(dragingTop, this.draging)         
        }
      }, 

/**
       * 拖拽结束
       */
      onDragEnd(e) {
        var tOptions = JSON.parse(JSON.stringify(this.options));
        let currentArray = Array.from(this.$refs['box'].childNodes)
        let data = currentArray.map((item,i)=>{
          let obj = tOptions.find(c=>c.value===item.getAttribute('value'))
          obj.index = i
          return obj
        })
        this.options = data
        this.initOptions()        
      },

/**
       * 拖拽的动画过程
       */
      _animation(clientTop, dom) {
        let offset = clientTop - dom.getBoundingClientRect().top //元素移动后的新位置
        //console.log('target+draging', offset)
        dom.style.transition = 'none';
        dom.style.transform = `translateY(${offset}px)`
        //触发重绘
        //console.log('offsetWidth:', dom.offsetWidth)
        //offsetWidth导致了浏览器重绘(了解浏览器重排、重绘)
        dom.style.transition = 'transform 0.3s';
        dom.style.transform = '';
        
        clearTimeout(dom.animated);
        dom.animated = setTimeout(()=>{
          dom.style.transition = ''
          dom.style.transform = ''
          dom.animated=false
        },150)        
      },
          

这样简单的拖拽就完成了,在这里要着重强调 `v-for` 的情况下,key值很重要,因为key值我给的是index值,发现每次排完序之后都是没重新排序的样子,犯了低级错误

key 为每个节点提供身份标识,数据改变时会重排,所以最好绑定唯一标识。

注意:如果用index标识可能得不到想要的效果,所以我在项目中使用了每个元素的value来作为 key

原文地址:https://www.cnblogs.com/feijiediyimei/p/13397514.html