Vue2 _ 实现拖拽功能

老项目重构,其中有一些拖拽功能,不过用的是两个开源 JS 拖拽文件实现的效果,版本太老了,所以需要换代了,然后就查阅了能够用 Vue 来简单快速实现拖拽的功能实现方法 :

目录

一、HTML 拖放

二、Vue.Draggable ( 强烈推荐 )

三、vue-grid-layout


一、HTML 拖放

首先我们可以使用 HTML 5 本身自带的 拖放 功能 :

官方文档 :  HTML5 拖放

Vue2 _ 实现拖拽功能_第1张图片

Vue2 _ 实现拖拽功能_第2张图片HTML 拖放实例

下列是关于拖放的简单例子:

 实例 :








它也许看上去有点复杂,不过让我们研究一下拖放事件的所有不同部分。


把元素设置为可拖放

首先:为了把一个元素设置为可拖放,请把 draggable 属性设置为 true:


拖放的内容 - ondragstart 和 setData()

然后,规定当元素被拖动时发生的事情。

在上面的例子中,ondragstart 属性调用了一个 drag(event) 函数,规定拖动什么数据。

dataTransfer.setData() 方法设置被拖动数据的数据类型和值:

function drag(ev) {
    ev.dataTransfer.setData("text", ev.target.id);
}

在本例中,数据类型是 "text",而值是这个可拖动元素的 id ("drag1")。


拖到何处 - ondragover

ondragover 事件规定被拖动的数据能够被放置到何处。

默认地,数据/元素无法被放置到其他元素中。为了实现拖放,我们必须阻止元素的这种默认的处理方式。

这个任务由 ondragover 事件的 event.preventDefault() 方法完成:

event.preventDefault()

进行放置 - ondrop

当放开被拖数据时,会发生 drop 事件。

在上面的例子中,ondrop 属性调用了一个函数,drop(event):

function drop(ev) {
    ev.preventDefault();
    var data = ev.dataTransfer.getData("text");
    ev.target.appendChild(document.getElementById(data));
}

代码解释:

  • 调用 preventDefault() 来阻止数据的浏览器默认处理方式( drop 事件的默认行为是以链接形式打开)
  • 通过 dataTransfer.getData() 方法获得被拖的数据。该方法将返回在 setData() 方法中设置为相同类型的任何数据
  • 被拖数据是被拖元素的 id ("drag1")
  • 把被拖元素追加到放置元素中

二、Vue.Draggable ( 强烈推荐 )

查阅各类网站文档后,决定试一下 Vue.Draggable

vue.draggable中文文档 :

vue.draggable中文文档 - itxst.com

Vue.Draggable 是一款基于 Sortable.js 实现的 Vue 拖拽插件。支持移动设备、拖拽和选择文本、智能滚动,可以在不同列表间拖拽、不依赖 jQuery 为基础、Vue 2 过渡动画兼容、支持撤销操作。

1.在项目中总会遇见一些需要排序的数据 , 我们可以通过 vue.draggable 进行拖动排序 。
2.Draggable 为基于 Sortable.js 的 vue 组件,用以实现拖拽功能。
3.拖顶的数据和 data 里的数据为双向绑定 ,在界面变的时候 data 中的数据也在跟着变化。

安装

npm i -S vuedraggable

使用

页面引入

import draggable from "vuedraggable"

定义组件

  components: {
     draggable
  },

定义参数 

data() {
  return {
    drag: false,
    syllable: [
      {
        title: '第 1 组'
      },
      {
        title: '第 2 组'
      },
      {
        title: '第 3 组'
      },
    ]
  }
}

页面使用

  
            
              
  • {{item.title}}
  • 事件

    // evt 里面有两个值,一个 evt.added 和 evt.removed
    // 可以分别知道移动元素的 ID 和 删除元素的 ID
        change(evt) {
          console.log(evt , 'change...')
        },
        // start , end , add , update , sort , remove 得到的都差不多
        start(evt) {
          this.drag = true
          console.log(evt , 'start...')
        },
        end(evt) {
          console.log(evt , 'end....')
          this.drag = true
          evt.item  // 可以知道拖动的本身
          evt.to    // 可以知道拖动的目标列表
          evt.from  // 可以知道之前的列表
          evt.oldIndex  // 可以知道拖动前的位置
          evt.newIndex  // 可以知道拖动后的位置
        },
        move(evt, originalEvent) {
          console.log(evt , 'move')
          console.log(originalEvent) // 鼠标位置
        }

    Vue2 _ 实现拖拽功能_第3张图片

    文章 强烈 推荐  =>

    记录Vue.Draggable拖拽组件的使用历程

    https://blog.csdn.net/weixin_58099 


    三、vue-grid-layout

    ( 二 )最近在完成 web 端在线绘图功能时,需要开发一个从左侧拖拽一种图标到画布中。调研了非常多种现在做拖拽布局的组件,调研的地址是:

    Drag - Vue.js Examples

    经过比较,选择了一款优秀的可拖拽框架,vue-grid-layout 。

    npm 安装

    npm install vue-grid-layout --save

    Vue2 _ 实现拖拽功能_第4张图片

    使用 demo

        
    
            
                {{item.i}}
            
        
    data() {
      return {
        layout: [
    	    {"x":0,"y":0,"w":2,"h":2,"i":"0"},
    	    {"x":2,"y":0,"w":2,"h":4,"i":"1"},
    	    {"x":4,"y":0,"w":2,"h":5,"i":"2"},
    	    {"x":6,"y":0,"w":2,"h":3,"i":"3"},
    	    {"x":8,"y":0,"w":2,"h":3,"i":"4"},
    	    {"x":10,"y":0,"w":2,"h":3,"i":"5"},
    	    {"x":0,"y":5,"w":2,"h":5,"i":"6"},
    	    {"x":2,"y":5,"w":2,"h":5,"i":"7"},
    	    {"x":4,"y":5,"w":2,"h":5,"i":"8"},
    	    {"x":6,"y":3,"w":2,"h":4,"i":"9"},
    	    {"x":8,"y":4,"w":2,"h":4,"i":"10"},
    	    {"x":10,"y":4,"w":2,"h":4,"i":"11"},
    	    {"x":0,"y":10,"w":2,"h":5,"i":"12"},
    	    {"x":2,"y":10,"w":2,"h":5,"i":"13"},
    	    {"x":4,"y":8,"w":2,"h":4,"i":"14"},
    	    {"x":6,"y":8,"w":2,"h":4,"i":"15"},
    	    {"x":8,"y":10,"w":2,"h":5,"i":"16"},
    	    {"x":10,"y":4,"w":2,"h":2,"i":"17"},
    	    {"x":0,"y":9,"w":2,"h":3,"i":"18"},
    	    {"x":2,"y":6,"w":2,"h":2,"i":"19"}
    	];
      }
    }

    文档

    属性参数说明

    Vue2 _ 实现拖拽功能_第5张图片

    GridLayout

    • layout

      • type: Array
      • required: true

      数据源。值必须为 Array,其数据项为 Object。 每条数据项必须有 ixyw 和 h 属性。 请参考下面的 GridItem

    • responsiveLayouts

      • type: Object
      • required: false
      • default: {}

      如果 responsive 设置为 true,该配置将作为栅格中每个断点的初始布局。键值是断点名称,每项的值都是类似 layout 属性定义的数据结构,值必须为 Array,其数据项为 Object。例如: {lg: [layout items], md: [layout items]}。需要注意的是,在创建栅格布局后设置该属性无效。

    • colNum

      • type: Number
      • required: false
      • default: 12

      定义栅格系统的列数,其值需为自然数。

    • rowHeight

      • type: Number
      • required: false
      • default: 150

      每行的高度,单位像素。

    • maxRows

      • type: Number
      • required: false
      • default: Infinity

      定义最大行数。

    • margin

      • type: Array
      • required: false
      • default: [10, 10]

      定义栅格中的元素边距。

      值必须是包含两个 Number的数组,数组中第一个元素表示水平边距,第二个表示垂直边距,单位为像素。

    • isDraggable

      • type: Boolean
      • required: false
      • default: true

      标识栅格中的元素是否可拖拽。

    • isResizable

      • type: Boolean
      • required: false
      • default: true

      标识栅格中的元素是否可调整大小。

    • isMirrored

      • type: Boolean
      • required: false
      • default: false

      标识栅格中的元素是否可镜像反转。

    • autoSize

      • type: Boolean
      • required: false
      • default: true

      标识容器是否自动调整大小。

    • verticalCompact

      • type: Boolean
      • required: false
      • default: true

      标识布局是否垂直压缩。

    • useCssTransforms

      • type: Boolean
      • required: false
      • default: true

      标识是否使用CSS属性 transition-property: transform;

    • responsive

      • type: Boolean
      • required: false
      • default: false

      标识布局是否为响应式。

    • breakpoints

      • type: Object
      • required: false
      • default: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }

      为响应式布局设置断点,其中参数代表不同设备的宽度:lg(large),md(medium),sm(small),xs(extra small)。

    • cols

      • type: Object
      • required: false
      • default: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }

      设置每个断点对应的列数。

    • useStyleCursor

      • type: Boolean
      • required: false
      • default: true

      标识是否使用动态鼠标指针样式。当拖动出现卡顿时,将此值设为 false也许可以缓解布局问题。

    • preventCollision

      • type: Boolean
      • default: false

      值设置为ture时,栅格只能拖动至空白处。

    GridItem

    • i

      • type: String
      • required: true

      栅格中元素的ID。

    • x

      • type: Number
      • required: true

      标识栅格元素位于第几列,需为自然数。

    • y

      • type: Number
      • required: true

      标识栅格元素位于第几行,需为自然数。

    • w

      • type: Number
      • required: true

      标识栅格元素的初始宽度,值为colWidth的倍数。

    • h

      • type: Number
      • required: true

      标识栅格元素的初始高度,值为rowHeight的倍数。

    • minW

      • type: Number
      • required: false
      • default: 1

      栅格元素的最小宽度,值为colWidth的倍数。

      如果w小于minW,则minW的值会被w覆盖。

    • minH

      • type: Number
      • required: false
      • default: 1

      栅格元素的最小高度,值为rowHeight的倍数。

      如果h小于minH,则minH的值会被h覆盖。

    • maxW

      • type: Number
      • required: false
      • default: Infinity

      栅格元素的最大宽度,值为colWidth的倍数。

      如果w大于maxW,则maxW的值会被w覆盖。

    • maxH

      • type: Number
      • required: false
      • default: Infinity

      栅格元素的最大高度,值为rowHeight的倍数。

      如果h大于maxH,则maxH的值会被h覆盖。

    • isDraggable

      • type: Boolean
      • required: false
      • default: null

      标识栅格元素是否可拖拽。如果值为null则取决于父容器。

    • isResizable

      • type: Boolean
      • required: false
      • default: null

      标识栅格元素是否可调整大小。如果值为null则取决于父容器。

    • static

      • type: Boolean
      • required: false
      • default: false

      标识栅格元素是否为静态的(无法拖拽、调整大小或被其他元素移动)。

    • dragIgnoreFrom

      • type: String
      • required: false
      • default: 'a, button'

      标识栅格元素中哪些子元素无法触发拖拽事件,值为css-like选择器。

      请参考 interact.js docs中的ignoreFrom

    • dragAllowFrom

      • type: String
      • required: false
      • default: null

      标识栅格元素中哪些子元素可以触发拖拽事件,值为css-like选择器。

      如果值为null则表示所有子元素(dragIgnoreFrom的除外)。

      请参考 interact.js docs中的allowFrom

    • resizeIgnoreFrom

      • type: String
      • required: false
      • default: 'a, button'

      标识栅格元素中哪些子元素无法触发调整大小的事件,值为css-like选择器。

      请参考 interact.js docs中的ignoreFrom

    Vue2 _ 实现拖拽功能_第6张图片


    限制可拖拽区域

    如果我们希望可拖拽的组件中,内部是可以单独点击的,那么需要就拖拽的区域分隔。这里官方提供了参数,可以指定哪些区域是可以拖拽的,哪些区域会被忽略,从而被忽略的区域可以单独进行点击。

     
                    
    {{item.i}}

    Vue2 _ 实现拖拽功能_第7张图片


    从外部拖拽组件到画布中

    在我们的应用中希望,组件能够从左侧拖到画布中,而再进行拖拽,所以我们在右侧需要先写一个区域是用来被拖拽的。在备选拖拽区域用两个方法来进行触发。

    Vue2 _ 实现拖拽功能_第8张图片 其他更多的官方说明,请参考

    Installation | Vue Grid Layout - ️A grid layout system for Vue.js


    
    
    
    
    

    【注意 : 其中两个方法应该是会有 bug 】


    事件

    每一个栅格元素grid-item上都可以添加监听器,用于监听移动和调整大小事件,这样父级Vue对象就可以收到通知。

    示例

        
    
            
                {{item.i}}
            
        
    • layoutCreatedEvent

      对应Vue生命周期的created

        layoutCreatedEvent: function(newLayout){
          console.log("Created layout: ", newLayout)
        }
    • layoutBeforeMountEvent

      对应Vue生命周期的beforeMount

        layoutBeforeMountEvent: function(newLayout){
          console.log("beforeMount layout: ", newLayout)
        }
    • layoutMountedEvent

      对应Vue生命周期的mounted

        layoutMountedEvent: function(newLayout){
          console.log("Mounted layout: ", newLayout)
        }
    • layoutReadyEvent

      当完成mount中的所有操作时生成的事件

        layoutReadyEvent: function(newLayout){
          console.log("Ready layout: ", newLayout)
        }
    • layoutUpdatedEvent

      更新事件(布局更新或栅格元素的位置重新计算)

        layoutUpdatedEvent: function(newLayout){
          console.log("Updated layout: ", newLayout)
        }
    • moveEvent

      移动时的事件

        moveEvent: function(i, newX, newY){
            console.log("MOVE i=" + i + ", X=" + newX + ", Y=" + newY);
        },
    • resizeEvent

      调整大小时的事件

        resizeEvent: function(i, newH, newW, newHPx, newWPx){
            console.log("RESIZE i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
        },
    • movedEvent

      移动后的事件

        movedEvent: function(i, newX, newY){
            console.log("MOVED i=" + i + ", X=" + newX + ", Y=" + newY);
        },
    • resizedEvent

      调整大小后的事件

        /**
         *
         * @param i the item id/index
         * @param newH new height in grid rows
         * @param newW new width in grid columns
         * @param newHPx new height in pixels
         * @param newWPx new width in pixels
         *
         */
        resizedEvent: function(i, newH, newW, newHPx, newWPx){
            console.log("RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
        },
    

    你可能感兴趣的:(前端,Vue,前端)