Giter Site home page Giter Site logo

alfred-skyblue / vue-draggable-plus Goto Github PK

View Code? Open in Web Editor NEW
2.4K 10.0 86.0 9.58 MB

Universal Drag-and-Drop Component Supporting both Vue 3 and Vue 2

Home Page: https://alfred-skyblue.github.io/vue-draggable-plus/en/

License: MIT License

JavaScript 3.00% Vue 69.23% TypeScript 27.77%
composition-api draggable typescript vue2 vue3 sortablejs vue drag drag-and-drop

vue-draggable-plus's Introduction

NPM version NPM Downloads Docs & Demos
GitHub stars

vue-draggable-plus

中文文档

Drag and drop sorting module, support Vue>=v3 or Vue>=2.7

Example of use

Describe

Since the vue3 component of Sortablejs has not been updated, it has been seriously out of touch with vue3, so this project was born. This component is based on Sortablejs, so if you want to know more about Sortablejs, you can check it out Sortablejs official website

We have encapsulated a variety of usages for this, you can use components, function, or instructions, there is always one that suits you

Solve pain points

In Sortablejs official Vue components in the past, the drag-and-drop list is implemented by using the component as a direct child element of the list. When we use some component libraries, if there is no slot for the root element of the list in the component library , it is difficult for us to implement a drag list, vue-draggable-plus perfectly solves this problem, it allows you to use a drag list on any element, we can use the selector of the specified element to get the root element of the list, and then Use the root element of the list as container of Sortablejs, for details, refer to specify target container.

Install

npm install vue-draggable-plus

Usage

Component usage

<template>
    <VueDraggable ref="el" v-model="list">
      <div v-for="item in list" :key="item.id">
        {{ item.name }}
      </div>
    </VueDraggable>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { VueDraggable } from 'vue-draggable-plus'

const list = ref([
  {
    name: 'Joao',
    id: 1
  },
  {
    name: 'Jean',
    id: 2
  },
  {
    name: 'Johanna',
    id: 3
  },
  {
    name: 'Juan',
    id: 4
  }
])
</script>

Function Usage

<template>
  <div ref="el">
    <div v-for="item in list" :key="item.id">
      {{ item.name }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useDraggable } from 'vue-draggable-plus'

const el = ref<HTMLElement | null>(null)
const list = ref([
  {
    name: 'Joao',
    id: 1
  },
  {
    name: 'Jean',
    id: 2
  },
  {
    name: 'Johanna',
    id: 3
  },
  {
    name: 'Juan',
    id: 4
  }
])
// The return value is an object, which contains some methods, such as start, destroy, pause, etc.
const draggable = useDraggable(el, list, {
  animation: 150,
  onStart() {
    console.log('start')
  },
  onUpdate() {
    console.log('update')
  }
})
</script>

Directive Usage

<template>
  <div
    v-draggable="[
        list,
        {
          animation: 150,
        }
      ]"
  >
    <div v-for="item in list" :key="item.id">
      {{ item.name }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { vDraggable } from 'vue-draggable-plus'
const list = ref([
  {
    name: 'Joao',
    id: 1
  },
  {
    name: 'Jean',
    id: 2
  },
  {
    name: 'Johanna',
    id: 3
  },
  {
    name: 'Juan',
    id: 4
  }
])

function onStart() {
  console.log('start')
}

function onUpdate() {
  console.log('update')
}
</script>

Explanation

All event functions starting with on can be passed to components using v-on. For example:

<template>
  <VueDraggable v-model="list" @start="onStart" @end="onEnd"></VueDraggable>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { VueDraggable } from 'vue-draggable-plus'
import { SortableEvent } from "sortablejs";

const list = ref([
  {
    name: 'Joao',
    id: '1'
  },
  {
    name: 'Jean',
    id: '2'
  },
  {
    name: 'Johanna',
    id: '3'
  },
  {
    name: 'Juan',
    id: '4'
  }
])

function onStart(event: SortableEvent) {
  console.log('start drag')
}

function onEnd(event: SortableEvent) {
  console.log('end drag')
}
</script>

For information on using Hooks and directives, please refer to the documentation.

Options

Options inherits all configuration items from Sortablejs. For details, please see the Sortablejs official documentation.

Types

type Easing =
  | 'steps(int, start | end)'
  | 'cubic-bezier(n, n, n, n)'
  | 'linear'
  | 'ease'
  | 'ease-in'
  | 'ease-out'
  | 'ease-in-out'
  | 'step-start'
  | 'step-end'
  | 'initial'
  | 'inherit'

type PullResult = ReadonlyArray<string> | boolean | 'clone';
type PutResult = ReadonlyArray<string> | boolean;

interface GroupOptions {
  /**
   * Group name.
   */
  name: string;
  /**
   * The ability to move from the list. Clone - copy the item instead of moving it.
   */
  pull?: PullResult | ((to: Sortable, from: Sortable, dragEl: HTMLElement, event: SortableEvent) => PullResult) | undefined;
  /**
   * Whether elements can be added from other lists, or an array of group names from which elements can be obtained.
   */
  put?: PutResult | ((to: Sortable, from: Sortable, dragEl: HTMLElement, event: SortableEvent) => PutResult) | undefined;
  /**
   * After moving to another list, the cloned element is restored to its initial position.
   */
  revertClone?: boolean | undefined;
}

type Group = string | GroupOptions | undefined;

type ScrollFn = ((
        this: Sortable,
        offsetX: number,
        offsetY: number,
        originalEvent: Event,
        touchEvt: TouchEvent,
        hoverTargetEl: HTMLElement,
    ) => 'continue' | void) | undefined;

API

Parameter Description Type Default
animation Show animation while dragging Number 0
chosenClass CSS class name for chosen item String 'sortable-chosen'
delay Delay in milliseconds before drag starts Number 0
delayOnTouchOnly Delay on touch event Number 0
direction Dragging direction, 'vertical' or 'horizontal' (default auto detect) String -
disabled Disable dragging Boolean false
dragClass CSS class name for dragged item String 'sortable-drag'
draggable Selector for draggable items within element String -
emptyInsertThreshold Distance (in pixels) from empty sortable items where dragging element should be inserted. Set to 0 to disable this feature. Number 5
easing Animation easing Easing -
fallbackClass CSS class name for cloned DOM elements when using forceFallback String sortable-fallback
fallbackOnBody Append cloned DOM element to body element Boolean false
fallbackTolerance Pixels mouse must move before drag start when using forceFallback Number 0
filter Selector for items that should not be draggable String -
forceFallback Ignore HTML5 drag and drop behavior and force fallback Boolean false
ghostClass CSS class name for drop placeholder String 'sortable-ghost'
group Group items to drag between sortable lists. Both lists must have the same group value. Also define whether lists can be dragged out of, cloned, or receive elements from other lists. See TypeScript type definition above for details. Group -
handle Selector for handle to initiate drag. If not set, the target element's children are used String -
invertSwap Always use inverted swap zone if set to true Boolean false
invertedSwapThreshold Inverted swap zone threshold, defaults to swapThreshold value Number -
preventOnFilter Call event.preventDefault() on filter event Boolean true
removeCloneOnHide Remove instead of hiding cloned element when not displayed Boolean true
sort Allow list items to be sorted within container Boolean true
swapThreshold Swap zone threshold Number 1
touchStartThreshold Pixels before cancelling delay touch event Number 1
setData Pass a function where the first argument is of type DataTransfer and the second argument is of type HTMLElement Function -
scroll Enable scrolling Boolean HTMLElement
scrollFn Custom scroll function ScrollFn -
scrollSensitivity The distance in pixels the mouse must be to the edge to start scrolling Number -
scrollSpeed The scrolling speed in ms/px number -
bubbleScroll Enables automatic scrolling for all parent elements to make it easier to move items Boolean true
onChoose Triggered when an item is selected ((event: SortableEvent) => void) -
onUnchoose Triggered when an item is deselected ((event: SortableEvent) => void) -
onStart Triggered when an item is picked up for drag and drop ((event: SortableEvent) => void) -
onEnd Triggered when an item is no longer being dragged ((event: SortableEvent) => void) -
onAdd Triggered when an item is moved from one list to another ((event: SortableEvent) => void) -
onUpdate Triggered when the order of the items is updated ((event: SortableEvent) => void) -
onSort Triggered whenever any changes are made to the list ((event: SortableEvent) => void) -
onRemove Triggered when an item is removed from the list and moved to another ((event: SortableEvent) => void) -
onFilter Triggered when trying to drag a filtered item ((event: SortableEvent) => void) -
onMove Triggered while an item is being dragged ((event: MoveEvent,originalEvent: Event) => void) -
onClone Triggered when an item is cloned ((event: SortableEvent) => void) -
onChange Triggered when an item is dragged and changes position ((event: SortableEvent) => void) -

vue-draggable-plus's People

Contributors

aaron-zon avatar alfred-skyblue avatar chouchouji avatar gsmith-daed avatar heniker avatar laurens94 avatar ogios avatar pkc918 avatar seaaster avatar tangjian1891 avatar zclsx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-draggable-plus's Issues

关于自定义clone的问题

类似低代码场景,我从左侧列表拖拽组件到右侧画布中,使用自定义克隆,当添加到右侧画布时,会自动将自定义克隆中返回的对象加入到右侧画布中model-value绑定的list对象中,但是我不想这么做,因为在添加数据前,我还需要对数据做一些处理,在添加到list数据中,这个如何实现呢?

添加完成后会触发onAdd方法,其中可以拿到添加的索引,目前是可以手动根据添加的索引将元素删除,在手动处理,放在list列表中,还有其他好的方法吗?

slow scroll speed

Thank you for the wonderful library.
I'm applying it to the website I'm currently developing.
However, if when I drag an item out of the current screen,
the scrolling is too slow. Do you know how to solve this in component usage??


Oh, I can use the scroll-speed attribute the same as sortablejs. :)

API documentation?

Hi,
I was looking at your documentation and I couldn't find a guide to the API (Props the components accepts, Emitted events)
Could you please guide me?

I want to increase the area that triggers the scroll and dont want to show the ghost ... are these things possible?

can this be used with v-data-table to move between tables in the same group?

Hello,
im trying to move between multiple v-data-tables in the same group,
is it possible to do it with vue-draggable-plus?
is there any example code of it?
i tried to do it with Vue.Draggable but didnt work
with sortable i was able to move only the HTML part, and not the actual data.
thats why im hoping vue-draggable-plus might be the solution im searching for.
thanks.

Possible Bug when after draging an element next elements creates in wrong position

When I swap two items being the one that I drag the one of the bottom, after the swap is made correclty, when I create a new Item in the list, this new item appear in the wrong place (under the item thet used to be the last, see images). The list of elements is in the right order when I log it to the console.

List inital state
Initial state

After items 3-2 swapped dragging the inial item 3 to the 2 place (check coordinates for reference)
After move

New item 4 created in the wrong place
After new item

Interestingly if you swap the items the other way araund it wokrs fine.
This is my code simplified

<div>
  <VueDraggable ref="el" v-if="matrix[index]" v-model="matrix[index].elements" :animation="150" handle=".handle"
    @update="updateList(index)"
    >
    <div v-for="(item, index) in matrix[index].elements" :key="index" 
        <p>{{ index + 1 }}.</p>
        <i class="fa-solid fa-bars handle cursor-move" style="color: #df0024"></i>
        ({{item}})
    </div>
  </VueDraggable>
</div>

Note that the matrix is an Vue Ref<Element[][]> injected in the component.

How to use with props?

In my use case, my component gets the array from a parent component in a prop. Isn't this likely more common in real-world usage than having a data array? What is the best way to use <VueDraggable> with a prop? This might be a something to document or an example to show...

All the examples use v-model, but when I tried that, I get this error:

[plugin:vite:vue] v-model cannot be used on a prop, because local prop bindings are not writable.
Use a v-bind binding combined with a v-on listener that emits update:x event instead.

Which does make sense. If I try to use v-bind instead, I get:

caught (in promise) DOMException: Failed to execute 'setAttribute' on 'Element': '0' is not a valid attribute name.
    at patchAttr (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:8103:10)
    at patchProp (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:8234:5)
    at mountElement (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:5786:11)
    at processElement (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:5764:7)
    at patch (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:5698:11)
    at ReactiveEffect.componentUpdateFn [as fn] (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:6128:11)
    at ReactiveEffect.run (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:405:19)
    at instance.update (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:6220:52)
    at setupRenderEffect (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:6228:5)
    at mountComponent (http://localhost:5173/node_modules/.vite/deps/chunk-3NMN3MUW.js?v=08779242:6046:5)

Which is less straight-forward to interpret.

What I've ended up doing is to have a copy of the array prop and then have watchers on both the prop and the copy to update "the other one". But it feels like a hack...

clone有问题

<div class="main">
  <a-card title="可选控件" class="main-left">
    <template v-if="leftDraggableArray.length">
      <VueDraggable
        class="draggableWrap"
        v-model="leftDraggableArray"
        ghostClass="ghost"
        :group="{ name: 'people', pull: 'clone', put: false }"
        :sort="false"
        :clone="clone"
      >
        <div
          v-for="leftItem in leftDraggableArray"
          :key="leftItem.name"
          class="leftDraggableItem"
        >
          <icon-formula />
          {{ leftItem.type }}
        </div>
      </VueDraggable>
    </template>
  </a-card>

  <a-card title="任务设计器主体" class="main-center">
    <a-form class="center-form" :model="centerForm" :size="centerForm.config.size">
      <VueDraggable
        class="draggableWrap"
        v-model="centerForm.list"
        animation="150"
        group="people"
        ghostClass="centerGhost"
      >
        <template
          v-for="(centerFormItem, index) in centerForm.list"
          :key="centerFormItem.key"
        >
          <!-- 判断是否为删格布局 start-->
          <template v-if="centerFormItem.type == 'grid'">
            <a-row
              v-if="centerFormItem && centerFormItem.key"
              :gutter="
                centerFormItem.options.gutter ? centerFormItem.options.gutter : 0
              "
              :justify="centerFormItem.options.justify"
              :align="centerFormItem.options.align"
            >
              <a-col :span="8">
                <FormItem />
                gird 布局,暂时不做
              </a-col>
            </a-row>
          </template>
          <!-- 判断是否为删格布局 end-->

          <!-- 其他类型的元素,直接渲染为表单项  start-->
          <template v-else>
            <FormItem
              v-if="centerFormItem && centerFormItem.key"
              :centerFormItem="centerFormItem"
              :index="index"
              :centerForm="centerForm"
            />
            {{ centerFormItem.key }}
          </template>
          <!-- 其他类型的元素,直接渲染为表单项  end-->
        </template>
      </VueDraggable>
    </a-form>
  </a-card>

  <a-card title="属性配置" class="main-right"> 最右边 </a-card>
</div>
这个是我的代码然后clone 方法如下:

const clone = (element: any) => {
// 为拖拽到容器的元素添加唯一 key

// 给拖拽的元素添加唯一 key
element.key = new Date().getTime().toString() + "_" + Math.ceil(Math.random() * 99999);

return element; // 返回克隆的元素
};
我想每次拖动克隆给每个都加个唯一的key,
但发现一个问题,如果我多次克隆左边的同一项到右边,会导致key全部一样,然后导致绑值也是一样的了
f5f64476bc652cdce00a7d1079f6ed6

在使用<component>标签时嵌套内容拖动后控件会直接消失, 但是数据内容是正确的

// TestView.vue
<template>
  <div class="container">
    <VueDraggable
      class="left"
      :group="{ name: 'g1', pull: 'clone', put: false }"
      :clone="clone"
      :sort="false"
      animation="150"
      v-model="data"
    >
      <p v-for="(el, index) in data" :key="el.name + index">{{ el.name }}</p>
    </VueDraggable>
    <NestedDraggable v-model="list" class="right"></NestedDraggable>
  </div>
  <button @click="console.log(list)">log</button>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { VueDraggable } from 'vue-draggable-plus';
import NestedDraggable from './NestedComponent.vue';
import { v4 as uuidv4 } from 'uuid';
import data from './data';
import type { IComponentList } from './type';

const list = ref<IComponentList[]>([]);

const clone = (element: any) => {
  console.log('clone');
  let e = {
    key: uuidv4(),
    name: element.name,
    component: element.component,
    children: element.children
  };

  if (list.value.length === 0) {
    console.log('push');
    list.value.push(e);
    return;
  }

  return e;
};
</script>

<style lang="scss">
.container {
  display: flex;
  justify-content: space-between;
  height: 80vh;

  .left {
    width: 50%;
  }

  .right {
    width: 50%;
    background: green;
  }
}
</style>
// NestedComponent.vue
<template>
  <VueDraggable class="drag-area" v-model="modelValue" group="g1">
    <div v-for="(el, index) in modelValue" :key="el.name">
      <component :is="el.component" :index="index" v-model="modelValue"></component>
    </div>
  </VueDraggable>
</template>
<script setup lang="ts">
import { VueDraggable } from 'vue-draggable-plus';
import type { IComponentList } from './type';
// import TestComponent from './TestComponent.vue';

const modelValue = defineModel<IComponentList[]>({ required: true });
</script>
<style scoped>
.drag-area {
  min-height: 50px;
  outline: 1px dashed;
}
</style>
// TestComponent.vue
<template>
  <p>{{ modelValue[index].name }}</p>
  <NestedDraggable v-model="modelValue[index].children"></NestedDraggable>
  <br />
</template>

<script setup lang="ts">
import type { IComponentList } from './type';
import NestedDraggable from './NestedComponent.vue';

defineProps<{ index: number }>();

const modelValue = defineModel<IComponentList[]>({ required: true });
</script>
// data.ts
import type { IComponentList } from './type';

import TestComponentVue from './TestComponent.vue';

const data = [
  { key: '', name: '控件1', component: TestComponentVue },
  { key: '', name: '控件2', component: TestComponentVue },
  { key: '', name: '控件3', component: TestComponentVue, children: [{ key: '', name: '控件1', component: TestComponentVue }] },
  { key: '', name: '控件4', component: TestComponentVue },
  { key: '', name: '控件5', component: TestComponentVue }
];

export default data;
// type.ts
export interface IComponentList {
  key: string;
  name: string;
  component: any;
  children: IComponentList[];
}
image 如果将`NestedComponent.vue`中的``改为``就不会出现问题,不知道是什么特性引起的

拖动有点问题

当我使用组件时候无法拖动

 <VueDraggable v-model="productImages" animation="150" handle=".product-image-header-drag">
<ul>
 <li  v-for="(item, index) in productImages" :key="index"></li>
</ul>
 </VueDraggable>


<script lang="ts" setup>
const productImages = ref<[]>([]);
</script >

当我使用指令的时候,数据无法排序,但是可以拖动,但我table tr 是正常的

<ul v-draggable="[productImages, { animation: 300, onUpdate: onUpdate, handle: '.product-image-header-drag' }]">
 <li  v-for="(item, index) in productImages" :key="index"></li>
</ul>


<script lang="ts" setup>
const productImages = ref<[]>([]);
</script >

测试发现,它无法对 ul li 元素起作用, 是我的使用方法不对吗? 还是它不支持 ul 元素

当我改成 div 结构的时候它生效了

还有一个问题,当我的数据从另外一个数组直接赋值的时候 它也是不生效

<script lang="ts" setup>
const productImages = ref<ProductModel.Image[]>([]);
const producOptions = ref<ProductModel.Options[]>([]);
const producVariants = ref<ProductModel.Variant[]>([]);

 //从服务器请求数据
  let value = await ProductService.getAsync();

  productImages.value = value.images;  //数据无法排序
  producOptions.value = value.options; //数据无法排序
  producVariants.value = value.variants; //正常 最后一个它既然正常

//该方法数据正常排序
   value.images.forEach(item => {
            productImages.value.push(item)
      })
value.options.forEach(item => {
            producOptions.value.push(item)
        })
  value.variants.forEach(item => {
            producVariants.value.push(item)
        })


</script >

这应该是vue内置机制问题,可以优化它的问题吗?

这是类

/**
 * 产品信息
 */
export namespace ProductModel {

    /**基类 */
    export class Base {

        /**
         * 产品描述
         */
        body_html: string = "";

        /**
         * 创建日期
         */
        created_at?: string;


        /**产品id */
        id: string = "";

        /**
         * 对象图片
         */
        images: Image[] = [];

        /**
         * 自定义产品属性。例如,大小、颜色和材料。每个产品最多可以有 3 个选项
         */
        options: Options[] = [];


        /**产品的分类 */
        product_type: string = "";


        /**发布时间 */
        published_at?: string;

        /**发布到销售点渠道 */
        published_scope: string = "";

        /**产品的状态  active=活跃 archived=下架 draft=草稿 */
        status: string = "active";

        /** 筛选和搜索的逗号分隔标记字符串 一个产品最多可以有 250 个标签。每个标签最多可包含 255 个字符。 */
        tags: string = "";

        /**产品名称 */
        title: string = "";

        /**修改时间 */
        updated_at?: string;

        /**多属性 */
        variants: Variant[] = [];

        /**厂商名称 */
        vendor: string = "";
    }

    /**商品图片 */
    export class Image {
        /**
         * 商品图片的唯一数字标识符。
         */
        id: string = "0";
        /**
         * 产品图像在列表中的顺序。第一个产品图片位于位置 1,是商品的“主”图片。
         */
        position: number = 0;

        /**
         * 产品图像在列表中的顺序。第一个产品图片位于位置 1,是商品的“主”图片。
         */
        product_id: string = "0";
        /**
         * 与图像关联的变体 ID 数组
         */
        variant_ids: string[] = [];
        /**
         * 图片地址
         */
        src: string = "";
        /**
         * 上传时确定的图像的宽度尺寸
         */
        width?: number;
        /**
         * 上传时确定的图像的高度尺寸
         */
        height?: number;

        /**创建时间 */
        created_at?: string;

        /**修改时间 */
        updated_at?: string;

        /**是否选中 */
        _vIsSelected?: boolean;

        /**显示操作 */
        _vShowTools?: boolean

    }

    /**SKU 属性选项值 */
    export class Options {
        /**
         * id
         */
        id: string = "0";

        /**商品ID */
        product_id: string = "0";

        /**属性选项key */
        name: string = "";

        /**排序位置 */
        position: number = 1;

        /**属性选项值 */
        values: string[] = [];

        /**验证key */
        _validateName?: boolean;


        /**验证选项值  */
        _validateValues?: number[]
    }

    /**商品属性 */
    export class Variant {


        /**id */
        id: string = "0";

        /**
         * 商品的条形码、UPC 或 ISBN 编号
         */
        barcode?: string;

        /**创建日期 */
        created_at?: string = "";

        /**
         * 调整或销售前商品的原始价格
         */
        compare_at_price: string = "";

        /**储存产品多属性的履行服务的句柄 */
        fulfillment_service: string = "manual";


        /**产品变型的重量(以克为单位) */
        grams: number = 0;

        /**
         * 产品图片的唯一数字标识符。 图片必须与多属性关联到同一商品
         */
        image_id: string = "0";

        /**清单项的唯一标识符,在清单 API 中用于查询清单信息 */
        inventory_item_id: string = "0";

        /**跟踪产品多属性的库存物料数量的履行服务。 有效值  shopify  null */
        inventory_management?: string;


        /**是否允许客户在产品多属性缺货时下订单。有效值  deny=不允许  continue=允许 */
        inventory_policy: string = "deny";

        /**所有位置的广告资源汇总。若要调整特定位置的库存 */
        inventory_quantity?: string = "";

        /**
         * 选项值 option1  
         */
        option1?: string;

        /**
         * 选项值  option2 option3
         */
        option2?: string;

        /**
         * 选项值   option3
         */
        option3?: string;

        /**多属性的呈现价格列表 */
        presentment_prices?: any = {};

        /**产品多属性的价格 */
        price: string = "0";

        /**产品ID */
        product_id: string = "0";

        /** */
        sku: string = "";

        /**销售产品变型时是否收取税费 */
        taxable: boolean = false;

        /**
         * 产品变型的标题。该字段是和字段的串联。您只能使用这些字段间接更新。
         */
        title: string = "";

        /**
         * 单位值
         */
        weight: number = 0;

        /**
         * 单位选项值 g=克 kg=千克 oz=盎司 lb=磅
         */
        weight_unit: string = "g";

    }
}


onMove生命周期中,return false无法取消拖拽

如下代码,可以直接运行,在onMove事件中,返回false,无法阻止(取消)拖拽,望修复,感谢!

<template>
    <div class="flex">
        <VueDraggable ref="el" v-model="list" animation="150" ghostClass="ghost"
            class="flex flex-col gap-2 p-4 w-300px h-300px m-auto bg-gray-500/5 rounded" :onMove="onMove">
            <div v-for="item in list" :key="item.id" class="cursor-move h-30 bg-gray-500/5 rounded p-3 cursor-move">
                {{ item.name }}
            </div>
        </VueDraggable>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { type UseDraggableReturn, VueDraggable } from 'vue-draggable-plus'
const list = ref([
    {
        name: 'Joao',
        id: 1
    },
    {
        name: 'Jean',
        id: 2
    },
    {
        name: 'Johanna',
        id: 3
    },
    {
        name: 'Juan',
        id: 4
    }
])

const onMove = () => {
    return false
}
</script>

<style scoped>
.ghost {
    opacity: 0.5;
    background: #c8ebfb;
}
</style>

Vitepress dependency outdated

I noticed when loading a page like https://alfred-skyblue.github.io/vue-draggable-plus/en/ the page does not load properly, even though that is the correct url, which can you get to by switching to English using the language switcher.

I was able to resolve the issue locally by simply upgrading vitepress to 1.0.0-rc.20 and vue to 3.3.4. However, the website seems a bit broken, the language switcher at the top right no longer exists, seemingly because the vitepress i18n api changed: https://vitepress.dev/guide/i18n#internationalization. I could not fix those because vitepress was still sort of using an older version, since @ruabick/md-demo-plugins also depends on an older vitepress version: dewfall123/ruabick#36.

`change` event triggers different from `docs`

docs for change event says Triggered when an item is dragged and changes position.
However, change event triggers when dragging without change actual position like move event.
As far as I remember correctly, change event triggers when an item is dropped to different position.

<template>
  <draggable
    v-model="list"
    :tag="tag"
    :group="group"
    :move="move"
    :fallback-tolerance="3"
    :force-fallback="true"
    :fallback-on-body="true"
    :disabled="disabled"
    @start="onStart"
    @end="onEnd"
    @change="onChange"
    @update="onUpdated"
    @move="onMove"
    @dragover.prevent
  >
    <slot></slot>
  </draggable>
</template>

<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    group: string;
    list?: Array<any>;
    tag?: string;
    option?: any;
    move?: (event: any, originEvent: any) => void;
    disabled?: boolean;
  }>(),
  {
    list: () => [],
    tag: "div",
    option: undefined,
    move: undefined,
    disabled: false,
  }
);
const { list } = toRefs(props);
const emits = defineEmits<{
  (e: "start", value: any): void;
  (e: "end", value: any): void;
  (e: "change", value: any): void;
}>();

const onStart = (event: any) => {
  emits("start", event);
  console.log("start : ", event);
};

const onEnd = (event: any) => {
  emits("end", event);
  console.log("end : ", event);
};

const onChange = (event: any) => {
  console.log("onChange event : ", event);
  emits("change", event);
};
const onUpdated = (event: any) => {
  console.log("onUpdated event : ", event);
  // emits("change", event);
};
const onMove = (event: any, b: any, c: any) => {
  console.log("onMove event : ", event, b, c);
  // emits("change", event);
};
</script>

image

Drag-and-Drop Issue between Two List Components Using Draggable-Plus and Sortable

There are two list components, A and B. Component B is utilizing draggable-plus, and they are not part of the same group. However, there are cases where they need to process list items from each other. Items can be dragged from component A and dropped into component B, triggering the onDrop event, and it works fine. However, dragging items from component B to component A is disabled.

When replacing draggable-plus with sortable, the drag-and-drop functionality works as expected. Is this issue related to draggable-plus? If so, what is the solution to enable drag-and-drop from component B to A while using draggable-plus?

Without ID, an unusual behavior occurs when moving between lists

Without an id field in the object, transferring an entry between lists is not functional.
As a result, some entries may suddenly disappear or be deleted.

Component: https://pastebin.com/b9x1FF1Q

	<div class="row">
		<div class="col-6">
			<VueDraggable
				class="list-group"
				v-model="list1"
				animation="150"
				ghostClass="ghost"
				group="people"
			>
				<div
					v-for="item in list1"
					:key="item.no-id"
					class="list-group-item"
				>
					{{ item.name }}
				</div>
			</VueDraggable>
		</div>
		<div class="col-6">
			<VueDraggable
				class="list-group"
				v-model="list2"
				animation="150"
				group="people"
				ghostClass="ghost"
			>
				<div
					v-for="item in list2"
					:key="item.no-id"
					class="list-group-item"
				>
					{{ item.name }}
				</div>
			</VueDraggable>
		</div>
	</div>
</template>

<script setup>
import { ref } from 'vue'
import { VueDraggable } from 'vue-draggable-plus'
const list1 = ref([
	{
		"name": "test",
		"no-id": "employees.id"
	},
	{
		"name": "active",
		"no-id": "employees.active"
	},
	{
		"name": "firstname",
		"no-id": "employees.firstname"
	},
	{
		"name": "lastname",
		"no-id": "employees.lastname"
	}
])
const list2 = ref([
	{
		"name": "short",
		"no-id": "employees.short"
	},
	{
		"name": "birthday",
		"no-id": "employees.birthday"
	},
	{
		"name": "number",
		"no-id": "employees.number"
	},
	{
		"name": "fullname",
		"no-id": "employees.fullname"
	}
])
</script>

class not working

When I place the tag element the tag div is placed in the HTML

image

But i need to pass the class too and I cant figure out how to do it.

I'm trying to pass the class batatas but with no effect

Strange effect when dragging to an empty list

ezgif com-optimize

I noticed, when I have a list group and drag an item to an empty list, there is a fly back effect on the item dragged. This does not happen aways.

  1. When I drag the item slowly the issue does not occur.
  2. When both list have at least one item, the issue does not occur.

Any idea what I can do with it? Thanks

Hello, I read the source code, there are one question

file:useDraggable.ts
/**

  • Changed sorting within list
  • @param {DraggableEvent} evt
    */
    function onUpdate(evt: DraggableEvent) {
    const { from, item, oldIndex, newIndex } = evt
    removeNode(item) //146
    insertNodeAt(from, item, oldIndex!) //147
    moveArrayElement(unref(list), oldIndex!, newIndex!)
    }

update function, why do I delete the node and then insert the node, and I find that these two lines of code, when executed, move the dom of sortablejs back, the actual effective code is moveArrayElement function.

So, are these two lines of code useless?

feature Request: Make compatible with vue-virtual-scroller

I'm currently trying to combine the vue-virtual-scroller with draggablePlus. Apparently the drag items can not be obtained if they are rendered within the dynamic scrollerItem.
My current setup is as follows:

<DynamicScroller page-mode class="scroller" :items="vScrollItems"
  :min-item-size="ticketHeight" key-field="docUUID"
  v-draggable="[vScrollItems, draggableDirectiveConf]">
  <template v-slot="{ item, index, active }">
    <DynamicScrollerItem :item="item" :active="active" :data-index="index" class="ticketDrag">
      <ticket-item :key="item.docUUID"
        :ticketItemId="item.docUUID" />
    </DynamicScrollerItem>
  </template>
</DynamicScroller>
const vScrollItems = [
  {
    docUUID:'77d8f970-bace-4d34-bcc0-6c932242e0ae'
  },
  {
    docUUID: '76d8f970-bace-4d34-bcc0-6c932242e0ae'
  },
  {
    docUUID: '77d8f970-bace-4d34-bcc0-9c932242e0ae'
  }
];
const ticketDrag = {
  name: 'ticketSort',
  pull: ['ticketSort'],
  put: ['ticketSort']
};
const draggableDirectiveConf = {
  animation: 150,
  target: '.ticketDrag',
  group: ticketDrag,
  handle: ".v-card-item__prepend"
}

whilst the ticket-item is a seperate component containing a vuetify card.
No Matter if I use target or el or place the class on the ticketItem or the scrollerItem, it always selects all items within the dynamicScroller for dragging, not each individually. Or am I doing something wrong here?

Regards

View not updated

When I package the latest version with "^", the data is successfully updated after dragging, but the view is not updated.

Usage with multiple lists (group, dynamic refs)

Hello @Alfred-Skyblue,

I just tested your version of 'vue-draggable', which looks promising due to recent bugs I found with alternatives.

It works fine for a single list (with hooks fashion), as with 2 "connected" lists manually. But I can't make it work for dynamic lists (or nested v-for), eg. a first v-for for say 2 columns, the second one for the items in each column.

Using recommended methods for "dynamic refs" won't work :

https://vuejs.org/guide/essentials/template-refs.html#refs-inside-v-for
https://vuejs.org/guide/essentials/template-refs.html#function-refs

Any idea about this use case? Is that even possible with current state of library?

PS: I got these 2 errors :

[vue-draggable-plus]: Root element not found
Uncaught Sortable: `el` must be an HTMLElement, not [object Undefined]

没有类型提示

vue-demi模块在devDependencies中,而生成的component.d.ts中import('vue-demi'),导致最终VueDraggable的类型是any

Dynamically imported components blink when moving them between lists

Hi, thanks for working on this library! I like it a lot.

Here's one issue that I've noticed. I can't provide a reproduction right now, I'll deliver it later, for now I'm putting it here so that I won't forget.

While any component imported the stardard way behaves just fine using vue-draggable-plus:

import SomeComponent from 'SomeComponent.vue'

If the same component is imported dynamically with defineAsyncComponent, it will blink when moving from one list to another.

const SomeComponent = defineAsyncComponent(() => import(`${someComponentName}.vue`))

Every instance of such a component on a changed list will blink, no matter if Sortable's animation is used or not, and regardless of TransitionGroup.
If a normally imported component contains dynamically imported one, only the child will blink.

Such blinking doesn't happen when changing order in the same list.

Breaks after modifying the list later (e.g. async fetching)

I installed the latest version from npm into my vue 3 vuetify project, tried to use the directive method just like in the docs and while it all works perfect when doing just some statically defined data like in the docs, trying to do anything a little more advanced such as fetching the list items asynchronously (or just modifying the list value) breaks the draggable element and while you can still drag, it goes back to the original form once you release the item.

Example:

const list = ref([])
setTimeout(function() {
  list.value = [
    { id: 1, title: 'Item 1'},
    { id: 2, title: 'Item 2' },
    { id: 3, title: 'Item 3'},
  ]
}, 100)
<VList
    v-draggable="[list, { }]"
  >
    <VListItem
      v-for="item in list"
      :key="item.id"
      :title="item.title"
    />
  </VList>

Drag any element and let it go, the list will still be in the same order.
One workaround is to delay rendering of the VList component using v-if="list.length" but what in case I want to update the existing list?

Target and Item - how to?

Hi all,
I've been looking everywhere but it seems not possible to get info regarding the item being dragged, the source and the destination at the same time.
I have a situation like this:

<script setup lang="ts">
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue";
import { Head, router } from "@inertiajs/vue3";
import { ref } from "vue";
import { VueDraggable } from "vue-draggable-plus";
const props = defineProps<{
    orders: App.Models.Order[];
    statuses: App.Models.Status[];
}>();
const statusOrders = ref([] as App.Models.Order[][]);
props.statuses.forEach((status) =>
    statusOrders.value.push(
        props.orders.filter((order) => order.status_id == status.id)
    )
);

defineOptions({ layout: AuthenticatedLayout });

function handleDrag(item: App.Models.Order) {
    statusOrders.value.forEach((el, index) => {
        if (el.map((e) => e.id).indexOf(item.id) >= 0) {
            item.status_id = props.statuses[index].id;
            router.patch(`/order/${item.id}`, item as Record<string, any>);
        }
    });
}
</script>

<template>
            <div
                class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg flex"
            >
                <div v-for="(status, index) in statuses">
                    {{ status.name }}
                    <VueDraggable
                        class="flex flex-col gap-2 p-4 w-300px h-300px m-auto bg-gray-500/5 rounded overflow-auto"
                        v-model="statusOrders[index]"
                        :animation="150"
                        ghostClass="ghost"
                        group="people"
                        :key="status.id"
                        :id="'status' + index"
                        tag="div"
                    >
                        <div
                            v-for="item in statusOrders[index]"
                            :key="item.id"
                            class="cursor-move h-30 bg-gray-500/5 rounded p-3"
                            @dragend="handleDrag(item)"
                        >
                            {{ item.code }}
                        </div>
                    </VueDraggable>
                </div>
            </div>

</template>

As you can see, I need to update the order status depending on where I drag the item. If I had the target div ID, I would be able to immediately retrieve the corresponding status. However, currently, the only way is to loop through the array and check for the dragged item. Additionally, the only way I can obtain the item is by using the 'ondragend' event on the dragged item.

Do you have any suggestions? Am I doing something wrong?

Thanks

Multi Drag

Does multidrag plugin from sortablejs works with this draggable-plus?

嵌套的Draggable的内部无法触发拖动

我的代码如下,外部的触发函数changeGroupDrag没问题。我拖动外部的分组卡片时是可以触发的。但是分组卡片内部也是用的VueDraggable,其触发函数changeListDrag就一直不触发。

(Small) bugs in stackblitz.com example

Hi,

The example on the front page points to https://stackblitz.com/edit/vue-rpa7f8?file=src%2FApp.vue.

This has a couple of bugs:

  • On lines 9 and 10 there are two open <div> tags. Only one of them is closed (on line 19)
  • There is an unused src/components/Draggable.vue file with (almost?) the same contents as App.vue.
  • If one attempts to download the example and run it locally:
    • npm install shows many deprecated packages and 19 high-severity vulnerabilities (see below)
    • npm run serve fails (see below)
    • I guess this is because the Vue template for stackblitz.com is very bad/old (see newly created stackblitz#2504 bug), but it is still a problem for this example.

npm install output

$ npm install
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@achrinza/[email protected]',
npm WARN EBADENGINE   required: { node: '8 || 10 || 12 || 14 || 16 || 17' },
npm WARN EBADENGINE   current: { node: 'v18.13.0', npm: '9.2.0' }
npm WARN EBADENGINE }
npm WARN deprecated [email protected]: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
npm WARN deprecated [email protected]: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated [email protected]: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated [email protected]: this library is no longer supported
npm WARN deprecated [email protected]: This loader has been deprecated. Please use eslint-webpack-plugin
npm WARN deprecated [email protected]: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated [email protected]: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated [email protected]: Please use @jridgewell/sourcemap-codec instead
npm WARN deprecated [email protected]: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
npm WARN deprecated [email protected]: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
npm WARN deprecated [email protected]: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated [email protected]: 3.x is no longer supported
npm WARN deprecated [email protected]: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.
npm WARN deprecated @hapi/[email protected]: Moved to 'npm install @sideway/address'
npm WARN deprecated [email protected]: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated [email protected]: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/[email protected]: Switch to 'npm install joi'
npm WARN deprecated [email protected]: This SVGO version is no longer supported. Upgrade to v2.x.x.

added 1389 packages, and audited 1390 packages in 46s

118 packages are looking for funding
  run `npm fund` for details

30 vulnerabilities (1 low, 5 moderate, 19 high, 5 critical)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

npm run serve output

$ npm run serve

> [email protected] serve
> vue-cli-service serve

 INFO  Starting development server...
10% building 2/5 modules 3 active ...ef--14-0!/home/pmorch/work/ost/src/main.jsError: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:71:19)
    at Object.createHash (node:crypto:133:10)
    at module.exports (/home/pmorch/work/ost/node_modules/webpack/lib/util/createHash.js:135:53)
    at NormalModule._initBuildHash (/home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:417:16)
    at handleParseError (/home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:471:10)
    at /home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:503:5
    at /home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:358:12
    at /home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:373:3
    at iterateNormalLoaders (/home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:214:10)
    at iterateNormalLoaders (/home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:221:10)
    at /home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:236:3
    at runSyncOrAsync (/home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:130:11)
    at iterateNormalLoaders (/home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:232:2)
    at Array.<anonymous> (/home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:205:4)
    at Storage.finished (/home/pmorch/work/ost/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:55:16)
    at /home/pmorch/work/ost/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:91:9
node:internal/crypto/hash:71
  this[kHandle] = new _Hash(algorithm, xofLen);
                  ^

Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:71:19)
    at Object.createHash (node:crypto:133:10)
    at module.exports (/home/pmorch/work/ost/node_modules/webpack/lib/util/createHash.js:135:53)
    at NormalModule._initBuildHash (/home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:417:16)
    at handleParseError (/home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:471:10)
    at /home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:503:5
    at /home/pmorch/work/ost/node_modules/webpack/lib/NormalModule.js:358:12
    at /home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:373:3
    at iterateNormalLoaders (/home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:214:10)
    at Array.<anonymous> (/home/pmorch/work/ost/node_modules/loader-runner/lib/LoaderRunner.js:205:4)
    at Storage.finished (/home/pmorch/work/ost/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:55:16)
    at /home/pmorch/work/ost/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:91:9
    at /home/pmorch/work/ost/node_modules/graceful-fs/graceful-fs.js:123:16
    at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3) {
  opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
  library: 'digital envelope routines',
  reason: 'unsupported',
  code: 'ERR_OSSL_EVP_UNSUPPORTED'
}

Node.js v18.13.0

swiper+draggable

image

disabled如何根据icons[index]遍历出来的item内的属性来判断是否可以拖拽?

el-upload无法使用,

如题,element plus没法使用,我用的hook方式,只能整合列表拖动,没办法拖动子项

Weird Display issue and scrollSensitivity Now Working

I checked the API and tried To use the scrollsensitivity, but it didn't work

<VueDraggable
    v-model="formStructure[sectionIndex]"
    animation="150"
    ghostClass="ghost"
    chosenClass="ghost"
    dragClass="drag"
    handle=".handle"
    group="questions"
    @choose="sorting = true"
    @unchoose="sorting = false"
    :sort="true"
    :scrollSensitivity="75"
  >

I also tried

<VueDraggable
    ...
    scrollSensitivity="75"
  >

But neither seemed to have an effect

Another Issue I'm having is...

if I drag the last item and place it anywhere above, and then add a new item to the list, then the new item will be displayed at the second last position even though in the array, it's at the last position.

Example : http://feedme.bhaviljain.co.in, you'll need to login,
user : [email protected]
pass : Pa$$w0rd!

on the side drawer, click survey builder

[Bug Report]双向列表拖拽+指定目标容器时(容器为组件时),最后一个元素拖拽不消失

https://element-plus.run/#eyJBcHAudnVlIjoiPHRlbXBsYXRlPlxuICA8ZGl2IGNsYXNzPVwiZmxleFwiIHN0eWxlPVwiZGlzcGxheTogZmxleFwiPlxuICAgIDxWdWVEcmFnZ2FibGVcbiAgICAgIGNsYXNzPVwiZmxleCBmbGV4LWNvbCBnYXAtMiBwLTQgdy0zMDBweCBoLTMwMHB4IG0tYXV0byBiZy1ncmF5LTUwMC81IHJvdW5kZWQgb3ZlcmZsb3ctYXV0b1wiXG4gICAgICB2LW1vZGVsPVwibGlzdDFcIlxuICAgICAgYW5pbWF0aW9uPVwiMTUwXCJcbiAgICAgIGdob3N0Q2xhc3M9XCJnaG9zdFwiXG4gICAgICBncm91cD1cInBlb3BsZVwiXG4gICAgICBAdXBkYXRlPVwib25VcGRhdGVcIlxuICAgICAgQGFkZD1cIm9uQWRkXCJcbiAgICAgIEByZW1vdmU9XCJyZW1vdmVcIlxuICAgICAgc3R5bGU9XCJtYXJnaW4tcmlnaHQ6IDUwcHhcIlxuICAgICAgdGFyZ2V0PVwiLndyYXBcIlxuICAgID5cbiAgICAgIDxlbC1yb3cgY2xhc3M9XCJ3cmFwXCI+XG4gICAgICAgIDxlbC1jb2wgdi1mb3I9XCJpdGVtIGluIGxpc3QxXCIgOmtleT1cIml0ZW0uaWRcIiBjbGFzcz1cImN1cnNvci1tb3ZlIGgtMzAgYmctZ3JheS01MDAvNSByb3VuZGVkIHAtM1wiPlxuICAgICAgICAgIHt7IGl0ZW0ubmFtZSB9fVxuICAgICAgICA8L2VsLWNvbD5cbiAgICAgIDwvZWwtcm93PlxuICAgIDwvVnVlRHJhZ2dhYmxlPlxuICAgIDxWdWVEcmFnZ2FibGVcbiAgICAgIGNsYXNzPVwiZmxleCBmbGV4LWNvbCBnYXAtMiBwLTQgdy0zMDBweCBoLTMwMHB4IG0tYXV0byBiZy1ncmF5LTUwMC81IHJvdW5kZWQgb3ZlcmZsb3ctYXV0b1wiXG4gICAgICB2LW1vZGVsPVwibGlzdDJcIlxuICAgICAgYW5pbWF0aW9uPVwiMTUwXCJcbiAgICAgIGdyb3VwPVwicGVvcGxlXCJcbiAgICAgIGdob3N0Q2xhc3M9XCJnaG9zdFwiXG4gICAgICBAdXBkYXRlPVwib25VcGRhdGVcIlxuICAgICAgQGFkZD1cIm9uQWRkXCJcbiAgICAgIEByZW1vdmU9XCJyZW1vdmVcIlxuICAgICAgdGFyZ2V0PVwiLnF3ZXJcIlxuICAgID5cbiAgICAgIDxkaXYgY2xhc3M9XCJxd2VyXCI+XG4gICAgICAgIDxkaXYgdi1mb3I9XCJpdGVtIGluIGxpc3QyXCIgOmtleT1cIml0ZW0uaWRcIiBjbGFzcz1cImN1cnNvci1tb3ZlIGgtMzAgYmctZ3JheS01MDAvNSByb3VuZGVkIHAtM1wiPlxuICAgICAgICAgIHt7IGl0ZW0ubmFtZSB9fVxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvVnVlRHJhZ2dhYmxlPlxuICA8L2Rpdj5cbjwvdGVtcGxhdGU+XG5cbjxzY3JpcHQgc2V0dXA+XG5pbXBvcnQgeyByZWYgfSBmcm9tIFwidnVlXCI7XG5pbXBvcnQgeyBWdWVEcmFnZ2FibGUgfSBmcm9tIFwidnVlLWRyYWdnYWJsZS1wbHVzXCI7XG5pbXBvcnQge0VsUm93LEVsQ29sfSBmcm9tIFwiZWxlbWVudC1wbHVzXCJcbmNvbnN0IGxpc3QxID0gcmVmKFtcbiAge1xuICAgIG5hbWU6IFwiSm9hb1wiLFxuICAgIGlkOiBcIjFcIixcbiAgfSxcbiAge1xuICAgIG5hbWU6IFwiSmVhblwiLFxuICAgIGlkOiBcIjJcIixcbiAgfSxcbiAge1xuICAgIG5hbWU6IFwiSm9oYW5uYVwiLFxuICAgIGlkOiBcIjNcIixcbiAgfSxcbiAge1xuICAgIG5hbWU6IFwiSnVhblwiLFxuICAgIGlkOiBcIjRcIixcbiAgfSxcbl0pO1xuY29uc3QgbGlzdDIgPSByZWYoXG4gIGxpc3QxLnZhbHVlLm1hcCgoaXRlbSkgPT4gKHtcbiAgICBuYW1lOiBgJHtpdGVtLm5hbWV9LTJgLFxuICAgIGlkOiBgJHtpdGVtLmlkfS0yYCxcbiAgfSkpXG4pO1xuZnVuY3Rpb24gb25VcGRhdGUoKSB7XG4gIGNvbnNvbGUubG9nKFwidXBkYXRlXCIpO1xufVxuZnVuY3Rpb24gb25BZGQoKSB7XG4gIGNvbnNvbGUubG9nKFwiYWRkXCIpO1xufVxuZnVuY3Rpb24gcmVtb3ZlKCkge1xuICBjb25zb2xlLmxvZyhcInJlbW92ZVwiKTtcbn1cbjwvc2NyaXB0PlxuPHN0eWxlPjwvc3R5bGU+XG4iLCJpbXBvcnRfbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWUtZHJhZ2dhYmxlLXBsdXNcIjogXCJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL3Z1ZS1kcmFnZ2FibGUtcGx1c0AwLjEuNS9kaXN0L3Z1ZS1kcmFnZ2FibGUtcGx1cy5qc1wiXG4gIH1cbn0iLCJfbyI6e319

在线案例,如下图
image

Is it possible to validate whether or not you can drag?

Is there a way for me to validate in a method whether or not an element can be dragged to another parent component?
In summary my use case is:
I have 2 lists and some specific list items can be dragged to another list and some not

Example:

if (event.clone.className === "fixed" && event.to.id === "availableFields") {

would be equivalent to prop :move="function" of vuedraggable

How to specify sub-draggable item

I have the following scenario:
image

Items 1 and 2 are the draggable targets, within the same group.
Item 3 is the actual child that I want to drag from target container 2 to 1.
Notice that in container 2 I add a different background as well as the name of the child, but I don't want those to be dragged. I want only item 3 to be dragged.

Today, the entire child goes dragged and dropped, like this:
image

When I finish dropping the element (mouse up), everything goes ok, because the object being transported is correct. The problem is just visual during dragging and dropping.

Is there any way to do that today?

v-model variable updated *after* @update event is sent

If I have:

    <VueDraggable
      v-model="list"
      @update="listUpdate"
    >

I expect to see the updated list in my listUpdate method. But list gets updated after listUpdate is called, forcing me to use a setTimeout(func, 0) or Vue.nextTick(func) hack to see the updated variable. It would be better if the new updated variable was available when @update fires.

So I expect this to show what is now the first element, but in fact it will show the first element before i sorted them:

  methods: {
    listUpdate() {
      this.firstElementInUpdate = this.list[0]
    }
  },

And this will show the new first element as I expect:

  methods: {
    listUpdate() {
      nextTick(() => {
        this.firstElementInUpdate = this.list[0]
      })
    }
  },

See https://vue-pys8h3.stackblitz.io for a full reproduction.

Some other way to get the new value of list from listUpdate would also be good. The sortable doc says to access it as evt.to, but then I get the updated DOM node, where I want the Vue model variable.

This reproduces in 0.1.3 and 0.1.5. 0.1.4 didn't work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.