vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue draggable拖拽表单

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

作者:就要吃饱了

本文主要介绍了vue-draggable实现拖拽表单的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

draggable在项目中的实际应用

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

1. 介绍及配置项

1.1 特性

使用版本: vue.draggable.next

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

特性:

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 示例

安装

npm i -S vuedraggable@next

普通拖拽

<template>
  <div class="itxst">
    <div>
      <draggable
        :list="state.list"
        ghost-class="ghost"
        chosen-class="chosenClass"
        animation="300"
        @start="onStart"
        @end="onEnd"
      >
        <template #item="{ element }">
          <div class="item">
            {{ element.name }}
          </div>
        </template>
      </draggable>
    </div>
    <div>{{ state.list }}</div>
  </div>
</template>
<script setup>
import { ref, reactive } from "vue";
import draggable from "vuedraggable";
/*
draggable 对CSS样式没有什么要求万物皆可拖拽
:list="state.list"         //需要绑定的数组
ghost-class="ghost"        //被替换元素的样式
chosen-class="chosenClass" //选中元素的样式
animation="300"            //动画效果
@start="onStart"           //拖拽开始的事件
@end="onEnd"               //拖拽结束的事件
*/
const state = reactive({
  //需要拖拽的数据,拖拽后数据的顺序也会变化
  list: [
    { name: "www.itxst.com", id: 0 },
    { name: "www.baidu.com", id: 1 },
    { name: "www.google.com", id: 2 },
  ],
});
​
//拖拽开始的事件
const onStart = () => {
  console.log("开始拖拽");
};
​
//拖拽结束的事件
const onEnd = () => {
  console.log("结束拖拽");
};
</script>
<style scoped>
.itxst {
  width: 600px;
  display: flex;
}
.itxst > div:nth-of-type(1) {
  flex: 1;
}
.itxst > div:nth-of-type(2) {
  width: 270px;
  padding-left: 20px;
}
.item {
  border: solid 1px #eee;
  padding: 6px 10px;
  text-align: left;
}
​
.item:hover {
  cursor: move;
}
.item + .item {
  margin-top: 10px;
}
.ghost {
  border: solid 1px rgb(19, 41, 239);
}
.chosenClass {
  background-color: #f1f1f1;
}
</style>

在表格中的拖拽

<template>
  <div>
    <div class="title">鼠标放到ID列和行上试试 可以拖拽行和列</div>
    <table class="tb">
      <thead>
        <draggable
          v-model="state.headers"
          animation="200"
          tag="tr"
          :item-key="(key) => key"
        >
          <template #item="{ element: header }">
            <th class="move">
              {{ header }}
            </th>
          </template>
        </draggable>
      </thead>
      <draggable
        :list="state.list"
        handle=".move"
        animation="300"
        @start="onStart"
        @end="onEnd"
        tag="tbody"
        item-key="name"
      >
        <template #item="{ element }">
          <tr>
            <td
              class="move"
              v-for="(header, index) in state.headers"
              :key="header"
            >
              {{ element[header] }}
            </td>
          </tr>
        </template>
      </draggable>
    </table>
  </div>
</template>
<script setup>
import { ref, reactive } from "vue";
import draggable from "vuedraggable";
/*
draggable 对CSS样式没有什么要求万物皆可拖拽
:list="state.list"         //需要绑定的数组 
animation="300"            //动画效果
@start="onStart"           //拖拽开始的事件
@end="onEnd"               //拖拽结束的事件
*/
const state = reactive({
  //列的名称
  headers: ["id", "name", "intro"],
  //需要拖拽的数据,拖拽后数据的顺序也会变化
  list: [
    { name: "www.itxst.com", id: 0, intro: "慢吞吞的蜗牛" },
    { name: "www.baidu.com", id: 1, intro: "中文搜索引擎" },
    { name: "www.google.com", id: 3, intro: "安卓操作系统" },
  ],
});
​
//拖拽开始的事件
const onStart = () => {
  console.log("开始拖拽");
};
​
//拖拽结束的事件
const onEnd = () => {
  console.log("结束拖拽");
};
</script>
<style scoped>
.title {
  padding: 3px;
  font-size: 13px;
}
.itxst {
  width: 600px;
}
​
.move {
  cursor: move;
}
​
table.tb {
  color: #333;
  border: solid 1px #999;
  font-size: 13px;
  border-collapse: collapse;
  min-width: 500px;
  user-select: none;
}
table.tb th {
  background: rgb(168 173 217);
  border-width: 1px;
  padding: 8px;
  border-style: solid;
  border-color: #999;
  text-align: left;
}
table.tb th:nth-of-type(1) {
  text-align: center;
}
table.tb td {
  background: #d6c8c8;
  border-width: 1px;
  padding: 8px;
  border-style: solid;
  border-color: #999;
}
table.tb td:nth-of-type(1) {
  text-align: center;
}
</style>

2. Vue3项目应用

示例:

基础工具拖拽部分实现

image-20221207153310245

<template>
    <div class="list-title"><span>基础工具</span></div>
    <draggable
               :list="componentsList.base"
               :group="{ name: 'people', pull: 'clone', put: false }"
               :sort="false" // 不排序
               :clone="cloneElement" // 克隆事件
               :move="onMove"   // 移动事件
               item-key="id"
               class="draggable-list"
               :forceFallback="true"
               >
        <template #item="{ element }">
            <div
                 class="list-group-item"
                 @click="onChooseComponent(element)"
                 :class="{ 'active-element': currentSelectElement.id === element.id }"
                 >
                <i :class="['iconfont', element.icon]"></i>{{ element.name }}
            </div>
        </template>
    </draggable>
</template>
​
<script setup>
 /**
 * 复制元素
 * @param {Object} param0
 */
let cloneId = ''
const cloneElement = ({ id, type, name }) => {
  let ele = createNewElement(type)
  cloneId = ele.id
  console.log(ele)
  return ele
}
​
​
/**
 * 组件移动时,判断移动位置是否为最外层
 */
const onMove = (evt, originalEvent) => {
  if (
    (evt.draggedContext.element.type === 1 || evt.draggedContext.element.type === 2) &&
    props.computeUnitList.findIndex((item) => item.type === evt.draggedContext.element.type) === -1
  ) {
    // 外部数据或公共数据拖向最外层
    emit('handleListChange')
    return true
  }
​
  if (
    (evt.draggedContext.element.type === 1 || evt.draggedContext.element.type === 2) &&
    evt.to.className.indexOf('dragUnitArea') === -1
  ) {
    // 外部数据或公共数据不是拖向最外层
    return false
  }
  console.log(evt)
  if (
    evt.to.className.indexOf('dragUnitArea') != -1 ||
    (evt.to.className.indexOf('table-draggable') != -1 && evt.draggedContext.element.type === 6) ||
    (evt.to.className.indexOf('table-draggable') != -1 &&
      evt.draggedContext.element.type === 'energy_table')
  ) {
    // 拖向最外层,类型为外部数据或者公共数据,或者将表格组件拖到表格内
    return false
  }
}
</script>

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

image-20221207153339046

<template>
  <div>
    <draggable
      class="dragArea"
      tag="div"
      :list="components"
      :group="{ name: 'g1', put: true }"
      item-key="id"
      :move="onMove"
      :animation="200"
      ghost-class="ghost"
      :forceFallback="true"
    >
      <template #item="{ element }">
        <div
          :class="{ 'list-group-item': true, 'active-area': activeArea?.id === element.id }"
          :style="{
            width: !element.ratio
              ? element.type === 6
                ? '100% !important'
                : '50% !important'
              : element.ratio + '% !important'
          }"
          v-if="element.type != 0"
          @click.stop="onChooseArea(element)"
        >
          <!-- <CSingleText
            v-if="element.type === 'single_text'"
            :activeArea="activeArea"
            :elementData="element"
          ></CSingleText> -->
          <component
            :is="componentNameList[element.type]"
            :activeArea="activeArea"
            :elementData="element"
            @onCopyElement="$emit('onCopyElement')"
            @onDelElement="$emit('onDelElement')"
            @onChooseArea="onChooseArea"
          >
            <div class="base-title">
              <div class="mask"></div>
              <el-icon
                v-if="
                  element.defaultValueType === 1 &&
                  element.dataLinkages[0]?.associationRules &&
                  element.dataLinkages[0].associationRules[0]?.targetField
                "
              >
                <Link />
              </el-icon>
              <i v-if="element.isRequired">*</i>
              {{ element.name }}
            </div>
          </component>
          <p class="operate" v-if="activeArea?.id === element.id">
            <i class="iconfont iconcopy" @click.stop="$emit('onCopyElement')"></i>
            <i class="iconfont icondel" @click.stop="$emit('onDelElement')"></i>
          </p>
        </div>
        <template v-else>
          <ComputeUnit
            @onCopyElement="$emit('onCopyElement')"
            @onDelElement="$emit('onDelElement')"
            @addBrotherUnit="$emit('addBrotherUnit')"
            @addChildUnit="$emit('addChildUnit')"
            @onShowAlCenter="$emit('onShowAlCenter')"
            class="drag-children"
            :activeArea="activeArea"
            :computeUnit="element"
            @onChooseArea="onChooseArea"
          ></ComputeUnit>
        </template>
      </template>
      <template #footer>
        <slot></slot>
      </template>
    </draggable>
  </div>
</template>
<script setup>
import draggable from 'vuedraggable'
import ComputeUnit from '../ComputeUnit/ComputeUnit.vue'
import { componentNameList } from '../../utils/element'
import { Link } from '@element-plus/icons-vue'
​
const props = defineProps({
  components: {
    required: true,
    type: Array
  },
  activeArea: {
    type: Object,
    default() {
      return {
        id: '-1'
      }
    }
  }
})
const emits = defineEmits([
  'addBrotherUnit',
  'addChildUnit',
  'onChooseArea',
  'onCopyElement',
  'onDelElement',
  'onShowAlCenter'
])
​
const onChooseArea = (ele) => {
  emits('onChooseArea', ele)
}
​
/**
 * 组件移动时,判断移动位置是否正确
 */
const onMove = (evt, originalEvent) => {
  if (
    (evt.to.className === 'dragUnitArea' && evt.draggedContext.element.type != 0) ||
    evt.to.className.indexOf('table-draggable') != -1
  ) {
    return false
  }
}
</script>

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

您可能感兴趣的文章:
阅读全文