【Vue 项目】使用 vuedraggable 实现拖拽效果时遇到的问题及解决方案总结(允许 el-table 行拖拽、部分元素不允许拖拽、拖拽避免影响文字复制和输入框输入文字)

由于在自己的工作和学习过程中,只查看某个大佬的教程或文章无法满足自己的学习需求和解决遇到的问题,所以自己在追赶大佬们步伐的基础上,又自己总结、整理、汇总了一些资料,方便自己理解和后续回顾,同时也希望给大家带来帮助,所以才写下该篇文章。在本文中,所有参考或引用大佬们文章内容的位置,都附上了原文章链接,您可以直接前往查阅观看。在原文章内容的基础上,若无任何补充内容,同时避免直接大段摘抄大佬们的文章,该情况下也只附上了原文章链接供大家学习。本文旨在总结归纳,并希望给大家提供帮助,未用作任何商用用途。文章内容如有错误之处,望各位大佬指出。如果涉及侵权行为,将会第一时间对文章进行删除。


👉 个人博客主页 👈
📝 一个努力学习的程序猿


其他前端组件使用和踩坑记录文章,欢迎您查看:



介绍

在最近的开发过程中,遇到了关于拖拽排序的功能需求。在这里向大家推荐使用👉 vuedraggable 👈插件。

【图片截取自 npm - vuedraggable】
在这里插入图片描述

在查看该组件的说明时,可以看到下图中的一段英文。

【图片截取自 npm - vuedraggable】
在这里插入图片描述
对这段英文,我在这里帮大家总结一下关键信息:

1、对较早期使用的 Sortable.js 相关用法的兼容;
(由于笔者没使用过 Sortable.js,所以没什么概念。不过在文中会有使用到 Sortable 用法的功能)

2、对 Vue 相关功能的支持;

3、在拖拽的各个阶段都有对应的事件处理;

4、兼容很多常用的 UI 组件库,比如常用的 ElementUI。
(这个将在文中的使用中有所体现)

关于更详细的内容,为了避免大篇幅引用,您可以直接前往以下文章👉 中文文档 👈学习使用。基础的用法是很简单的,如没有特殊需求,参照文档即可完整实现拖拽效果。本文中的重点将是使用过程中遇到的问题,基础的使用将不再赘述。


简单使用

首先,先 npm 下载:

npm install vuedraggable --save

再次说明: 下载完成之后,参照文档即可成功使用。为了避免大篇幅引用,建议您直接参考👉文档用例👈。例子、属性、事件在文档中有详细解答。在这里就仅把完整代码粘贴一下(不要忘记在组件中导入 draggable ):

<template>
  <div>
	  <div>{{drag?'拖拽中':'拖拽停止'}}</div>
	  <!--使用draggable组件-->
	  <draggable v-model="myArray" chosenClass="chosen" forceFallback="true" group="people" animation="1000" @start="onStart" @end="onEnd">
	    <transition-group>
	      <div class="item" v-for="element in myArray" :key="element.id">{{element.name}}</div>
	    </transition-group>
	  </draggable> 
  </div>
</template>
<style scoped>
   /*被拖拽对象的样式*/
   .item {
       padding: 6px;
       background-color: #fdfdfd;
       border: solid 1px #eee;
       margin-bottom: 10px;
       cursor: move;
   } 
   /*选中样式*/
   .chosen {
       border: solid 1px #3089dc !important;
   }
</style>
<script>
//导入draggable组件
import draggable from 'vuedraggable'
export default {
  //注册draggable组件
   components: {
   	 draggable
   },
   data() {
    return { 
      drag:false,
      //定义要被拖拽对象的数组
      myArray:[
        {people:'cn',id:10,name:'www.itxst.com'},
        {people:'cn',id:20,name:'www.baidu.com'},
        {people:'cn',id:30,name:'www.taobao.com'},
        {people:'us',id:40,name:'www.yahoo.com'}
      ] 
    };
  },
  methods: {
    //开始拖拽事件
    onStart(){
       this.drag=true;
    },
    //拖拽结束事件
    onEnd(e) {
       console.log(e); // 这里将会有调整前后的 index 及其他可能需要传递给接口的信息
       this.drag=false;
    }
  }
};
</script>

简单尝试了一下,果然好用!您也可以像我下图中这样,利用相关用法,做一些样式上的改观。

在这里插入图片描述
而在开发中,也碰到了想要实现部分元素不允许拖拽的需求,实现方式也是比较简单,为了避免大篇幅引用,您可以直接前往以下文章查阅:

【vuedraggable】实现部分元素不允许拖拽

vue.draggable filter 排除不允许拖动的元素

虽然从目前来看没什么难度,不过这将可能导致以下一系列的问题,这也是本文想主要说明的内容。


问题一、拖拽避免影响文字复制和输入框输入文字

在使用的过程中将会发现,如果我们实现了拖拽效果,那么我们将不能复制其中的文字,只要鼠标一点击就会触发拖拽。同时,如果拖拽的元素涉及到了文本输入框或者选择框等需要改变信息的操作,那么也会受到拖拽的影响。

从我在网上冲浪寻找解决办法的过程中发现,似乎没有一个比较有效的办法,实现在进行拖拽的过程中,去解决这样的一个问题。如果您有更好的办法,欢迎在评论区留言分享。

不过,虽然在使用拖拽的过程中没有办法解决,但我们可以在特定的情况下,避免使用拖拽。比如:

1、我们可以不允许包含输入框的元素进行拖拽(使用上面的部分元素不允许拖拽的方法就可以解决):

在这里插入图片描述
2、我们也可以让拖拽效果只在 点击按钮后触发 或者 在每个元素前面加一个拖动的标志,从而避免文字区域或者输入框区域无法复制的问题,比如下图中是我在每个元素前面加一个拖动的标志:
在这里插入图片描述
点击按钮后触发拖拽很简单,依然可以使用 filter 的用法,比如点击按钮后,将所有元素都包含在内,再次点击按钮将所有元素排除在外。代码简单粘贴一下:

<template>
  <div>
      <el-button @click="changeForbid">点击拖拽 / 取消</el-button>
	  <!--使用draggable组件-->
	  <draggable v-model="myArray" filter=".forbid" chosenClass="chosen" forceFallback="true" group="people" animation="1000" @start="onStart" @end="onEnd">
	    <transition-group>
	      <div v-for="element in myArray" :key="element.id">
             <span :class="{ forbid: !canDrag }">{{element.name}}</span>
	      </div>
	    </transition-group>
	  </draggable> 
  </div>
</template>
<style scoped>
   /*被拖拽对象的样式*/
   .item {
       padding: 6px;
       background-color: #fdfdfd;
       border: solid 1px #eee;
       margin-bottom: 10px;
       cursor: move;
   } 
   /*选中样式*/
   .chosen {
       border: solid 1px #3089dc !important;
   }
</style>
<script>
//导入draggable组件
import draggable from 'vuedraggable'
export default {
  //注册draggable组件
   components: {
   	 draggable
   },
   data() {
    return {
      canDrag: false,
      drag:false,
      //定义要被拖拽对象的数组
      myArray:[
        {people:'cn',id:10,name:'www.itxst.com'},
        {people:'cn',id:20,name:'www.baidu.com'},
        {people:'cn',id:30,name:'www.taobao.com'},
        {people:'us',id:40,name:'www.yahoo.com'}
      ] 
    };
  },
  methods: {
    //开始拖拽事件
    onStart(){
       this.drag=true;
    },
    //拖拽结束事件
    onEnd(e) {
       console.log(e); // 这里将会有调整前后的 index 及其他可能需要传递给接口的信息
       this.drag=false;
    },
    changeForbid() {
   	   this.canDrag = !this.canDrag;
    }
  }
};
</script>

同理地,加一个拖拽的标志,从而让拖拽只在拖动这个标志的时候,才进行拖拽,也可以使用 filter 来实现。代码简单粘贴一下(更详细地可以在问题二中查看):

 <draggable v-model="myArray" filter=".forbid" chosen-class="chosen" force-fallback="true" group="people" animation="1000" @start="onStart" @end="onEnd">
     <transition-group>
         <div 
          	v-for="element in myArray" 
          	:key="element.id"
         >
           <span>拖拽按钮</span>
           <span class="forbid">{{element.name}}</span>
       </div>
     </transition-group>
 </draggable>

如果您有更好的办法,欢迎在评论区留言分享。


问题二、ElementUI 的 el-table 进行行拖拽

之前有提到 vuedraggable 也将会支持相关组件库,即通常的 ElementUI 组件也可以使用 vuedraggable (一些普通的组件:比如 el-tag、el-card 等等。当然也会有一些自带排序功能的组件,比如 el-tree)。但是,一多半的 ElementUI 组件都是内部再次封装,如果想要对它们内部的元素进行排序,用之前的用法就无法实现了。比如接下来要说的 el-table,如果用 draggable 标签包裹,那么排序的只是表格本身。如果我想排序 el-table 里面的 行 / 列 该怎么办?这时候就可以使用 Sortable.js 。

注意:看了一些文章,它们提到如果 npm vuedraggable 之后,就也可以使用 sortablejs 。因为 vuedraggable 内部包含了 sortablejs。但是由于自己的项目里下载过 sortablejs,所以为了省点事,也没有选择卸载去进行尝试。所以如果各位无法直接使用 sortablejs 那就再 npm 一下。

npm install sortablejs --save

在这里插入图片描述

相关代码(由于考虑到对行直接进行拖拽,会导致表格文字无法复制以及输入框问题,所以采用的是通过按住拖拽按钮才进行拖拽的方式。如果不想用这个方式,做一下调整就行 => handle 去掉):

<el-table
  :data="data"
  row-key="id"
>
  <el-table-column
    label="拖拽排序"
    width="80"
    align="center"
  >
    <template slot-scope="{row}">
      <i class="el-icon-rank allowDrag" style="cursor:pointer" />
    </template>
  </el-table-column>
  <el-table-column
    label="标题"
    align="center"
  >
    <template slot-scope="{row}">
      <el-input v-model="row.title" />
    </template>
  </el-table-column>
</el-table>
created() {
  // 业务场景描述行拖拽
  const tbody = document.querySelector('.el-table__body-wrapper tbody');
  const _this = this;
  Sortable.create(tbody, {
    handle: '.allowDrag',
    onEnd({ newIndex, oldIndex }) {
      console.log(newIndex, oldIndex);
    }
  })
}

参考文章如下:

Sortablejs ElementUI

实现表格列拖拽的方法 以el-table为例

如果想要了解更多用法,就需要参考相关文档了:SortableJS 中文网


以上就可以满足目前开发中,我遇到的相关需求。希望能够给您提供帮助。


由于在自己的工作和学习过程中,只查看某个大佬的教程或文章无法满足自己的学习需求和解决遇到的问题,所以自己在追赶大佬们步伐的基础上,又自己总结、整理、汇总了一些资料,方便自己理解和后续回顾,同时也希望给大家带来帮助,所以才写下该篇文章。在本文中,所有参考或引用大佬们文章内容的位置,都附上了原文章链接,您可以直接前往查阅观看。在原文章内容的基础上,若无任何补充内容,同时避免直接大段摘抄大佬们的文章,该情况下也只附上了原文章链接供大家学习。本文旨在总结归纳,并希望给大家提供帮助,未用作任何商用用途。文章内容如有错误之处,望各位大佬指出。如果涉及侵权行为,将会第一时间对文章进行删除。


👉 个人博客主页 👈
📝 一个努力学习的程序猿


其他前端组件使用和踩坑记录文章,欢迎您查看:

  • 29
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只爭朝夕不負韶華

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值