vue-draggable实现拖拽表单的示例代码

draggable在项目中的实际应用

这个功能为公司做的项目中的一个功能,要求能拖拽配置表单,并且能实现实时计算,本文讲述的是拖拽表单组件,配置出对应的算法的实现

1. 介绍及配置项

1.1 特性

使用版本: vue.draggable.next

vue.draggable.next 是一款vue3的拖拽插件,是vue.draggable升级版本。Vue.Draggable是一款基于Sortable.js实现的vue拖拽插件。

特性:

  • 支持移动设备
  • 拖拽和选择文本
  • 智能滚动
  • 可以在不同列表间拖拽
  • 不依赖jquery为基础
  • vue 2过渡动画兼容
  • 支持撤销操作

1.2 配置项

属性说明:

属性名称 说明
modelValue 传入数组到可拖动组件。通常与内部元素v-for指令引用的数组相同。
list 与modelValue类似,主要的区别是list拖动组件是使用splice方法更新的,而modelValue是不可变的。
group 如果一个页面有多个拖拽区域,通过设置group名称可以实现多个区域之间相互拖拽 或者 { name: “…”, pull: [true, false, ‘clone’, array , function], put: [true, false, array , function] }
sort 是否开启排序,如果设置为false,它所在组无法排序
delay 鼠标按下多少秒之后可以拖拽元素
touchStartThreshold 鼠标按下移动多少px才能拖动元素
disabled :disabled= “true”,是否启用拖拽组件
animation 拖动时的动画效果,如设置animation=1000表示1秒过渡动画效果
handle :handle=”.mover” 只有当鼠标在class为mover类的元素上才能触发拖到事件
filter :filter=”.unmover” 设置了unmover样式的元素不允许拖动
draggable :draggable=”.item” 样式类为item的元素才能被拖动
ghost-class :ghost-class=”ghostClass” 设置拖动元素的占位符类名,你的自定义样式可能需要加!important才能生效,并把forceFallback属性设置成true
chosen-class :ghost-class=”hostClass” 被选中目标的样式,你的自定义样式可能需要加!important才能生效,并把forceFallback属性设置成true
drag-class :drag-class=”dragClass”拖动元素的样式,你的自定义样式可能需要加!important才能生效,并把forceFallback属性设置成true
force-fallback 默认false,忽略html5的拖拽行为,因为h5里有个属性也是可以拖动,你要自定义ghostClass chosenClass dragClass样式时,建议forceFallback设置为true
fallback-class 默认false,克隆选中元素的样式到跟随鼠标的样式
fallback-on-body 默认false,克隆的元素添加到文档的body中
fallback-tolerance 按下鼠标移动多少个像素才能拖动元素,:fallback-tolerance=”8″
scroll 默认true,有滚动区域是否允许拖拽
scroll-fn 滚动回调函数
scroll-fensitivity 距离滚动区域多远时,滚动滚动条
scroll-speed 滚动速度

1.3 示例

安装

  1. npm i S vuedraggable@next

普通拖拽

  1. <template>
  2.      <div class=“itxst”>
  3.      <div>
  4.      <draggable
  5.      :list=“state.list”
  6.      ghost-class=“ghost”
  7.      chosen-class=“chosenClass”
  8.      animation=“300”
  9.      @start=“onStart”
  10.      @end=“onEnd”
  11.      >
  12.      <template #item=“{ element }”>
  13.          <div class=“item”>
  14.          {{ element.name }}
  15.          </div>
  16.      </template>
  17.      </draggable>
  18.      </div>
  19.      <div>{{ state.list }}</div>
  20.      </div>
  21. </template>
  22. <script setup>
  23. import { ref, reactive } from “vue”;
  24. import draggable from “vuedraggable”;
  25. /*
  26. draggable 对css样式没有什么要求万物皆可拖拽
  27. :list=”state.list” //需要绑定的数组
  28. ghost-class=”ghost” //被替换元素的样式
  29. chosen-class=”chosenClass” //选中元素的样式
  30. animation=”300″ //动画效果
  31. @start=”onStart” //拖拽开始的事件
  32. @end=”onEnd” //拖拽结束的事件
  33. */
  34. const state = reactive({
  35.      //需要拖拽的数据,拖拽后数据的顺序也会变化
  36.      list: [
  37.      { name: “www.itxst.com”, id: 0 },
  38.      { name: “www.baidu.com”, id: 1 },
  39.      { name: “www.google.com”, id: 2 },
  40.      ],
  41. });
  42. //拖拽开始的事件
  43. const onStart = () => {
  44.      console.log(“开始拖拽”);
  45. };
  46. //拖拽结束的事件
  47. const onEnd = () => {
  48.      console.log(“结束拖拽”);
  49. };
  50. </script>
  51. <style scoped>
  52. .itxst {
  53.      width: 600px;
  54.      display: Flex;
  55. }
  56. .itxst > div:nthoftype(1) {
  57.      flex: 1;
  58. }
  59. .itxst > div:nthoftype(2) {
  60.      width: 270px;
  61.      paddingleft: 20px;
  62. }
  63. .item {
  64.      border: solid 1px #eee;
  65.      padding: 6px 10px;
  66.      textalign: left;
  67. }
  68. .item:hover {
  69.      cursor: move;
  70. }
  71. .item + .item {
  72.      margintop: 10px;
  73. }
  74. .ghost {
  75.      border: solid 1px rgb(19, 41, 239);
  76. }
  77. .chosenClass {
  78.      backgroundcolor: #f1f1f1;
  79. }
  80. </style>

在表格中的拖拽

  1. <template>
  2.      <div>
  3.      <div class=“title”>鼠标放到ID列和行上试试 可以拖拽行和列</div>
  4.      <table class=“tb”>
  5.      <thead>
  6.      <draggable
  7.          v-model=“state.headers”
  8.          animation=“200”
  9.          tag=“tr”
  10.          :item-key=“(key) => key”
  11.      >
  12.          <template #item=“{ element: header }”>
  13.          <th class=“move”>
  14.          {{ header }}
  15.          </th>
  16.          </template>
  17.      </draggable>
  18.      </thead>
  19.      <draggable
  20.      :list=“state.list”
  21.      handle=“.move”
  22.      animation=“300”
  23.      @start=“onStart”
  24.      @end=“onEnd”
  25.      tag=“tbody”
  26.      item-key=“name”
  27.      >
  28.      <template #item=“{ element }”>
  29.          <tr>
  30.          <td
  31.          class=“move”
  32.          v-for=“(header, index) in state.headers”
  33.          :key=“header”
  34.          >
  35.          {{ element[header] }}
  36.          </td>
  37.          </tr>
  38.      </template>
  39.      </draggable>
  40.      </table>
  41.      </div>
  42. </template>
  43. <script setup>
  44. import { ref, reactive } from “vue”;
  45. import draggable from “vuedraggable”;
  46. /*
  47. draggable 对CSS样式没有什么要求万物皆可拖拽
  48. :list=”state.list” //需要绑定的数组
  49. animation=”300″ //动画效果
  50. @start=”onStart” //拖拽开始的事件
  51. @end=”onEnd” //拖拽结束的事件
  52. */
  53. const state = reactive({
  54.      //列的名称
  55.      headers: [“id”, “name”, “intro”],
  56.      //需要拖拽的数据,拖拽后数据的顺序也会变化
  57.      list: [
  58.      { name: “www.itxst.com”, id: 0, intro: “慢吞吞的蜗牛” },
  59.      { name: “www.baidu.com”, id: 1, intro: “中文搜索引擎” },
  60.      { name: “www.google.com”, id: 3, intro: “安卓操作系统 },
  61.      ],
  62. });
  63. //拖拽开始的事件
  64. const onStart = () => {
  65.      console.log(“开始拖拽”);
  66. };
  67. //拖拽结束的事件
  68. const onEnd = () => {
  69.      console.log(“结束拖拽”);
  70. };
  71. </script>
  72. <style scoped>
  73. .title {
  74.      padding: 3px;
  75.      fontsize: 13px;
  76. }
  77. .itxst {
  78.      width: 600px;
  79. }
  80. .move {
  81.      cursor: move;
  82. }
  83. table.tb {
  84.      color: #333;
  85.      border: solid 1px #999;
  86.      fontsize: 13px;
  87.      bordercollapse: collapse;
  88.      minwidth: 500px;
  89.      userselect: none;
  90. }
  91. table.tb th {
  92.      background: rgb(168 173 217);
  93.      borderwidth: 1px;
  94.      padding: 8px;
  95.      borderstyle: solid;
  96.      bordercolor: #999;
  97.      textalign: left;
  98. }
  99. table.tb th:nthoftype(1) {
  100.      textalign: center;
  101. }
  102. table.tb td {
  103.      background: #d6c8c8;
  104.      borderwidth: 1px;
  105.      padding: 8px;
  106.      borderstyle: solid;
  107.      bordercolor: #999;
  108. }
  109. table.tb td:nthoftype(1) {
  110.      textalign: center;
  111. }
  112. </style>

2. Vue3项目应用

示例:

基础工具拖拽部分实现

-1

  1. <template>
  2.      <div class=“list-title”><span>基础工具</span></div>
  3.      <draggable
  4.          :list=“componentsList.base”
  5.          :group=“{ name: ‘people’, pull: ‘clone’, put: false }”
  6.          :sort=“false” // 不排序
  7.          :clone=“cloneElement” // 克隆事件
  8.          :move=“onMove” // 移动事件
  9.          item-key=“id”
  10.          class=“draggable-list”
  11.          :forceFallback=“true”
  12.          >
  13.      <template #item=“{ element }”>
  14.          <div
  15.              class=“list-group-item”
  16.              @click=“onChooseComponent(element)”
  17.              :class=“{ ‘active-element’: currentSelectElement.id === element.id }”
  18.              >
  19.          <i :class=“[‘iconfont’, element.icon]”></i>{{ element.name }}
  20.          </div>
  21.      </template>
  22.      </draggable>
  23. </template>
  24. <script setup>
  25.      /**
  26.      * 复制元素
  27.      * @param {Object} param0
  28.      */
  29. let cloneId = 
  30. const cloneElement = ({ id, type, name }) => {
  31.      let ele = createNewElement(type)
  32.      cloneId = ele.id
  33.      console.log(ele)
  34.      return ele
  35. }
  36. /**
  37.      * 组件移动时,判断移动位置是否为最外层
  38.      */
  39. const onMove = (evt, originalEvent) => {
  40.      if (
  41.      (evt.draggedContext.element.type === 1 || evt.draggedContext.element.type === 2) &&
  42.      props.computeUnitList.findIndex((item) => item.type === evt.draggedContext.element.type) === 1
  43.      ) {
  44.      // 外部数据或公共数据拖向最外层
  45.      emit(‘handleListChange’)
  46.      return true
  47.      }
  48.      if (
  49.      (evt.draggedContext.element.type === 1 || evt.draggedContext.element.type === 2) &&
  50.      evt.to.className.indexOf(‘dragUnitArea’) === 1
  51.      ) {
  52.      // 外部数据或公共数据不是拖向最外层
  53.      return false
  54.      }
  55.      console.log(evt)
  56.      if (
  57.      evt.to.className.indexOf(‘dragUnitArea’) != 1 ||
  58.      (evt.to.className.indexOf(‘table-draggable’) != 1 && evt.draggedContext.element.type === 6) ||
  59.      (evt.to.className.indexOf(‘table-draggable’) != 1 &&
  60.      evt.draggedContext.element.type === ‘energy_table’)
  61.      ) {
  62.      // 拖向最外层,类型为外部数据或者公共数据,或者将表格组件拖到表格内
  63.      return false
  64.      }
  65. }
  66. </script>

中间部分拖拽组件主要实现

-2

  1. <template>
  2.      <div>
  3.      <draggable
  4.      class=“dragArea”
  5.      tag=“div”
  6.      :list=“components”
  7.      :group=“{ name: ‘g1’, put: true }”
  8.      item-key=“id”
  9.      :move=“onMove”
  10.      :animation=“200”
  11.      ghost-class=“ghost”
  12.      :forceFallback=“true”
  13.      >
  14.      <template #item=“{ element }”>
  15.      <div
  16.          :class=“{ ‘list-group-item’: true, ‘active-area’: activeArea?.id === element.id }”
  17.          :style={
  18.          width: !element.ratio
  19.          ? element.type === 6
  20.          ? ‘100% !important’
  21.          : ‘50% !important’
  22.          : element.ratio + ‘% !important’
  23.          }
  24.          v-if=“element.type != 0”
  25.          @click.stop=“onChooseArea(element)”
  26.      >
  27.          <!– <CSingleText
  28.          v-if=”element.type === ‘single_text'”
  29.          :activeArea=”activeArea”
  30.          :elementData=”element”
  31.          ></CSingleText> –>
  32.          <component
  33.          :is=“componentNameList[element.type]”
  34.          :activeArea=“activeArea”
  35.          :elementData=“element”
  36.          @onCopyElement=$emit(‘onCopyElement’)
  37.          @onDelElement=$emit(‘onDelElement’)
  38.          @onChooseArea=“onChooseArea”
  39.          >
  40.          <div class=“base-title”>
  41.          <div class=“mask”></div>
  42.          <el-icon
  43.          v-if=
  44.              element.defaultValueType === 1 &&
  45.              element.dataLinkages[0]?.associationRules &&
  46.              element.dataLinkages[0].associationRules[0]?.targetField
  47.          “
  48.          >
  49.          <Link />
  50.          </el-icon>
  51.          <i v-if=“element.isRequired”>*</i>
  52.          {{ element.name }}
  53.          </div>
  54.          </component>
  55.          <p class=“operate” v-if=“activeArea?.id === element.id”>
  56.          <i class=“iconfont iconcopy” @click.stop=“$emit(‘onCopyElement’)”></i>
  57.          <i class=“iconfont icondel” @click.stop=“$emit(‘onDelElement’)”></i>
  58.          </p>
  59.      </div>
  60.      <template v-else>
  61.          <ComputeUnit
  62.          @onCopyElement=$emit(‘onCopyElement’)
  63.          @onDelElement=$emit(‘onDelElement’)
  64.          @addBrotherUnit=“$emit(‘addBrotherUnit’)”
  65.          @addChildUnit=“$emit(‘addChildUnit’)”
  66.          @onShowAlCenter=$emit(‘onShowAlCenter’)
  67.          class=“drag-children”
  68.          :activeArea=“activeArea”
  69.          :computeUnit=“element”
  70.          @onChooseArea=“onChooseArea”
  71.          ></ComputeUnit>
  72.      </template>
  73.      </template>
  74.      <template #footer>
  75.      <slot></slot>
  76.      </template>
  77.      </draggable>
  78.      </div>
  79. </template>
  80. <script setup>
  81. import draggable from ‘vuedraggable’
  82. import ComputeUnit from ‘../ComputeUnit/ComputeUnit.vue’
  83. import { componentNameList } from ‘../../utils/element’
  84. import { Link } from ‘@element-plus/icons-vue’
  85. const props = defineProps({
  86.      components: {
  87.      required: true,
  88.      type: Array
  89.      },
  90.      activeArea: {
  91.      type: Object,
  92.      default() {
  93.      return {
  94.      id: ‘-1’
  95.      }
  96.      }
  97.      }
  98. })
  99. const emits = defineEmits([
  100.      ‘addBrotherUnit’,
  101.      ‘addChildUnit’,
  102.      ‘onChooseArea’,
  103.      ‘onCopyElement’,
  104.      ‘onDelElement’,
  105.      ‘onShowAlCenter’
  106. ])
  107. const onChooseArea = (ele) => {
  108.      emits(‘onChooseArea’, ele)
  109. }
  110. /**
  111.      * 组件移动时,判断移动位置是否正确
  112.      */
  113. const onMove = (evt, originalEvent) => {
  114.      if (
  115.      (evt.to.className === ‘dragUnitArea’ && evt.draggedContext.element.type != 0) ||
  116.      evt.to.className.indexOf(‘table-draggable’) != 1
  117.      ) {
  118.      return false
  119.      }
  120. }
  121. </script>

到此这篇关于vue-draggable实现拖拽表单的示例代码的文章就介绍到这了,更多相关vue draggable拖拽表单内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

标签

发表评论