vue实现拖拽的组件

<1>

安装

通过NPM安装

$ npm install awe-dnd --save

插件应用

在main.js中,通过Vue.use导入插件

import VueDND from 'awe-dnd'

Vue.use(VueDND)

在你的vue文件中这样引用

<script>
export default {
  data () {
    return {
        colors: [{
            text: "Aquamarine"
        }, {
            text: "Hotpink"
        }, {
            text: "Gold"
        }, {
            text: "Crimson"
        }, {
            text: "Blueviolet"
        }, {
            text: "Lightblue"
        }, {
            text: "Cornflowerblue"
        }, {
            text: "Skyblue"
        }, {
            text: "Burlywood"
        }]
    }
  }
}
</script>

<template>
  <div class="color-list">
      <div 
          class="color-item" 
          v-for="color in colors" v-dragging="{ item: color, list: colors, group: 'color' }"
          :key="color.text"
      >{{color.text}}</div>
  </div>
</template>

vue2.0的使用方式

<div class="color-list">
    <div 
        class="color-item" 
        v-for="color in colors" v-dragging="{ item: color, list: colors, group: 'color' }"
        :key="color.text"
    >{{color.text}}</div>
</div>

vue1.0的使用方式

<div class="color-list">
    <div 
        class="color-item" 
        v-for="color in colors" v-dragging="{ item: color, list: colors, group: 'color', key: color.text }"
        track-by="text"
    >{{color.text}}</div>
</div>

添加事件

<div class="color-list">
    <div 
        class="color-item" 
        v-for="color in colors" v-dragging="{ item: color, list: colors, group: 'color', otherData: otherData }"
        :key="color.text"
    >{{color.text}}</div>
</div>
export default {
  mounted () {
    this.$dragging.$on('dragged', ({ value }) => {
      console.log(value.item)
      console.log(value.list)
      console.log(value.otherData)
    })
    this.$dragging.$on('dragend', () => {
        
    })
  }
}

组件参数

名称类型默认值说明

itemObject-每一个可拖拽的对象
listArray-可拖拽对象的数组
groupString-这是一个dragging list的unique key

 

<2>vue 组件排列顺序

安装

npm install awe-dnd --save
  •  

main.js

import VueDND from 'awe-dnd'

Vue.use(VueDND)
  •  

sortable.vue

  •  

  排序完后的操作挺重要的,因为我们一般排序完要重新提交排序后的数据给后台保存,以便下一次安装我们所需要的顺序显示,这里的list就可以帮我们做到这一点,但是我们需要给数据添加一个uniqueId标志。然后在排序完后或者列表对应的顺序和uniqueId提交给后台,我也不知道我说的你们能理解吗,反正你们也可以打印出来看看。

效果
这里写图片描述

<3>

https://blog.csdn.net/u011384023/article/details/79762299

 

<4>

一个基于 Sortable.js 的vue拖拽插件 支持触屏操作 自动适应 draggable组件的v-model属性实现双向绑定。 如果要多个盒子互相拖拽,需定义options,将其group属性定义为同一个值即可 源码如下:

 

一个基于Sortable.js的vue拖拽插件
支持触屏操作
自动适应




draggable组件的v-model属性实现双向绑定。

如果要多个盒子互相拖拽,需定义options,将其group属性定义为同一个值即可

源码如下:
 

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Document</title>

<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>

<script src="http://cdn.jsdelivr.net/npm/sortablejs@1.7.0/Sortable.min.js"></script>

 

<script src="http://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.15.0/vuedraggable.min.js"></script>

</head>

<body>

<div id="tuozhuai_view">

<!--  -->

<draggable  v-model="fruit" :options="{group:'people'}">

  <div v-for="element in fruit">{{element}}</div>

</draggable>

{{fruit}}

<br>

<br>

<draggable  v-model="girl" :options="{group:'people'}">

  <div v-for="element in girl">{{element}}</div>

</draggable>

{{girl}}

</div>

 

<script type="text/javascript">

new Vue({

el:'#tuozhuai_view',

data:{

fruit:['apple','banana','orage'],

girl:['linzhil','cjk','bdyjy'],

}

})

</script>

</body>

</html>

<5>https://blog.csdn.net/qq_40882724/article/details/80798135

:翻看vue文档发现可以注册全局指令,用于DOM元素的底层处理,这个挺靠谱。

Vue.directive( 指令名,{ 钩子函数 } )

3.思路:很简单:首先记录整个对话框距离文档边界的左边距和上边距(当然你监听右边距也oK的,但是别监听下边距,因为我们一般是设置上边距,饿了么也是如此。正如我们调整高度时,会说往下拉一点,或者往上去一点)。鼠标按下的时候监听mousedown事件,记录鼠标距离对话框边界的距离(左边距LEFT,上边距TOP).然后监听document的mousemove事件,因为我们不可能确保我们的鼠标一直都在框中拖拽,因为我们速度有慢有快,在mousemove中保证鼠标与对话框的位置跟mousedown时一致。鼠标mouseup时移除mousemove和mouseup的监听,下次对话框打开时再把它的位置还原如初

4.思考过程:

 

  1. 使用哪些钩子?  因为我们要记录初始位置,并保存记录,采用inserted钩子,可以保证我们能正确地访问到相关样式属性,在componentUpdated里当对话框打开时再把位置还原到拖拽之前的位置。
  2. computedStyle or element.style?因为有的样式写在行内有的样式写在样式表里,思考后决定统一使用getComputedstyle,然后发现有些是空字符"",有些是"auto"我嘞个去。这怎么办?问题到这里已经很清晰了,那就是根据样式来获取距离不靠谱。
  3. 计算获取marginLeft,marginTop,我们通过html的宽度与对话框的宽度之差获取对话框左边距
  4. 再通过鼠标事件里的event.clientX、event.clientY 获取鼠标到对话框的距离。并处理。
  5. componentUpdated里还原位置。
 
  1. let marginLeft = (compotedStyle(document.firstElementChild).width -computedStyle(dialogEle).width)/2

  2. //此处注意把值转换为数字格式

5.贴上代码:

 
  1. import Vue from 'vue'

  2. let LEFT;

  3. let TOP;

  4. //指令的传参形式为<dialogo v-dialogdrag=" { target:'selector',container:'.box',dialogVisible:"传入对话框的visible变量" } "></dialog>

  5. Vue.directive('dialogdrag',{

  6. inserted(el,binding){

  7. let container = el.querySelector(binding.value.container);

  8. let target = el.querySelector(binding.value.target);

  9.  
  10.  
  11. let temContainerWidth = getComputedStyle(container).width;

  12. let temHtmlWidth = getComputedStyle(document.firstElementChild).width;

  13. if(temContainerWidth.indexOf('%') != -1){

  14. //百分值

  15. LEFT = (

  16. parseFloat(temHtmlWidth) -

  17. parseFloat(temHtmlWidth) * temContainerWidth.substring(0,temContainerWidth.length-1)/100

  18. )/2;

  19. }else if(temContainerWidth.indexOf('px') != -1){

  20. //像素值

  21. LEFT = (

  22. parseFloat(temHtmlWidth) -

  23. parseFloat(temContainerWidth)

  24. )/2;

  25. }else{

  26. //其他值

  27. throw ('对话框容器宽度只能为像素或百分比!')

  28. }

  29. console.log(temContainerWidth);

  30. console.log(temHtmlWidth);

  31. //

  32. let temMarginTop = getComputedStyle(container).marginTop;

  33. if(temMarginTop && temMarginTop.indexOf('px') != -1){

  34. //不为空并且以像素为单位

  35. TOP = parseFloat(temMarginTop);

  36. }else{

  37. throw ('请设置对话框容器上边距margin-top并以像素为单位!')

  38. }

  39. console.log(LEFT)

  40. //删除对话容器的行内样式(marginleft,margintop,marginbottom,marginrigth);

  41. delete container.style.marginTop;

  42. delete container.style.marginLeft;

  43. delete container.style.marginRight;

  44. delete container.style.marginBottom;

  45. delete container.style.margin;

  46. //赋值给marginTop;marginLeft;

  47. container.style.marginTop = TOP+'px';

  48. container.style.marginLeft = LEFT+'px';

  49.  
  50. //事件监听

  51. target.addEventListener('mousedown',function(event){

  52. //获取鼠标距离对话框容器的左上边距

  53. let leftValue = event.clientX - parseFloat(getComputedStyle(container).marginLeft);

  54. let topValue = event.clientY - parseFloat(getComputedStyle(container).marginTop);

  55. document.addEventListener('mousemove',moveFn,true)

  56. document.addEventListener('mouseup',upFn,true)

  57. function moveFn(event){

  58. console.log('还在移动')

  59. target.style.cursor = 'move';

  60. container.style.marginLeft = (event.clientX-leftValue)+'px';

  61. container.style.marginTop = (event.clientY-topValue)+'px';

  62.  
  63. }

  64. function upFn(event){

  65. target.style.cursor = 'default';

  66. document.removeEventListener('mousemove',moveFn,true);

  67. //document.removeEventListener('mouseup',upFn);

  68. }

  69. })

  70. },

  71. componentUpdated(el,binding){

  72. if(binding.value.dialogVisible){

  73. //打开时还原对话框位置

  74. el.querySelector(binding.value.container).style.marginTop = TOP+'px';

  75.  
  76. el.querySelector(binding.value.container).style.marginLeft = LEFT+'px';

  77.  
  78. }

  79. }

  80. })

 

  • 10
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值