v-drag
简介
v-drag
指令用于处理根据鼠标拖拽来变换目标元素形态、位置等的场景。
示例
拖动元素。
<template>
<article>
<div
ref="target"
v-drag:target.translate
class="target"
/>
</article>
</template>
<script>
import drag from 'veui/directives/drag'
export default {
directives: {
drag
}
}
</script>
在指定元素区域内拖动。
<template>
<article>
<div
ref="container"
class="container"
>
<div
ref="target"
v-drag:target.translate="{containment: 'container'}"
class="target"
/>
</div>
</article>
</template>
<script>
import drag from 'veui/directives/drag'
export default {
directives: {
drag
}
}
</script>
拖动多个元素。
<template>
<article>
<div
ref="target1"
v-drag:target1,target2,target3.translate
class="target"
>
主元素
</div>
<div
ref="target2"
class="target"
/>
<div
ref="target3"
class="target"
/>
</article>
</template>
<script>
import drag from 'veui/directives/drag'
export default {
directives: {
drag
}
}
</script>
限制拖动方向。
<template>
<article>
<div
ref="target1"
v-drag:target1.translate.x
class="target"
>
水平方向
</div>
<div
ref="target2"
v-drag:target2.translate.y
class="target"
>
垂直方向
</div>
</article>
</template>
<script>
import drag from 'veui/directives/drag'
export default {
directives: {
drag
}
}
</script>
水平排序。
Axis: X(v-drag.sort.x)
<template>
<article>
<section ref="itemGroup">
<h2>Axis: X(v-drag.sort.x)</h2>
<transition-group
ref="transitionGroup"
name="list"
tag="div"
class="items"
>
<div
v-for="item in items"
:key="item"
v-drag.sort.x="{
name: 'mySortableButton',
containment: 'itemGroup',
callback: handleAxisXSortCallback,
debug,
align
}"
class="item"
>
{{ item }}
</div>
</transition-group>
</section>
</article>
</template>
<script>
import drag from 'veui/directives/drag'
const items = [
'须菩提',
'菩萨亦如是',
'若作是言',
'我当灭度无量众生',
'即不名菩萨',
'🍎🍎',
'🍋',
'🍉🍉🍉',
'🍓🍓',
'何以故',
'须菩提',
'无有法名为菩萨',
'是故佛说',
'一切法无我',
'无人',
'无众生',
'无寿者'
]
export default {
directives: {
drag
},
data () {
return {
debug: false,
align: undefined,
items: items.map((item, i) => `${i}. ${item}`)
}
},
computed: {
handleAxisXSortCallback () {
return this.getTransitionSortCallback('items', 'transitionGroup')
}
},
methods: {
getTransitionSortCallback (itemsKey, transitionGroupRefKey) {
return (toIndex, fromIndex) => {
if (toIndex === fromIndex) {
return
}
let promise
if (transitionGroupRefKey) {
promise = new Promise((resolve, reject) => {
let el = this.$refs[transitionGroupRefKey].$el
let handleTransitionEnd = () => {
el.removeEventListener('transitionend', handleTransitionEnd)
resolve()
}
el.addEventListener('transitionend', handleTransitionEnd)
})
}
this.moveItem(this[itemsKey], fromIndex, toIndex)
// 动画完了再回调成功
return promise
}
},
moveItem (items, fromIndex, toIndex) {
let item = items[fromIndex]
items.splice(fromIndex, 1)
if (toIndex > fromIndex) {
toIndex--
}
items.splice(toIndex, 0, item)
}
}
}
</script>
<style lang="less" scoped>
.list-move {
// 动画曲线是 0.25, 0.1, 0.25, 1,就是 ease
transition: transform 200ms ease;
}
</style>
垂直排序。
Axis: Y(v-drag.sort.y)
- 0须菩提
- 1若菩萨作是言
- 2我当庄严佛土
- 3是不名菩萨
- 4何以故
- 5🦁
- 6🙈🙉🙊
- 7🐷🐶
- 8如来说
- 9庄严佛土者
- 10即非庄严
- 11是名庄严
- 12须菩提
- 13若菩萨通达无我法者
<template>
<article>
<section>
<h2>Axis: Y(v-drag.sort.y)</h2>
<transition-group
ref="transitionGroup2"
name="list"
tag="ol"
class="list"
>
<li
v-for="item in items2"
:key="item"
v-drag.sort.y="{
name: 'otherSortableButton',
callback: handleAxisYSortCallback,
debug,
align
}"
class="item"
>
{{ item }}
</li>
</transition-group>
</section>
</article>
</template>
<script>
import drag from 'veui/directives/drag'
const items = [
'须菩提',
'若菩萨作是言',
'我当庄严佛土',
'是不名菩萨',
'何以故',
'🦁',
'🙈🙉🙊',
'🐷🐶',
'如来说',
'庄严佛土者',
'即非庄严',
'是名庄严',
'须菩提',
'若菩萨通达无我法者'
]
export default {
directives: {
drag
},
data () {
return {
debug: false,
align: undefined,
items2: items.map((item, i) => `${i}${item}`)
}
},
computed: {
handleAxisYSortCallback () {
return this.getTransitionSortCallback('items2', 'transitionGroup2')
},
},
methods: {
getTransitionSortCallback (itemsKey, transitionGroupRefKey) {
return (toIndex, fromIndex) => {
if (toIndex === fromIndex) {
return
}
let promise
if (transitionGroupRefKey) {
promise = new Promise((resolve, reject) => {
let el = this.$refs[transitionGroupRefKey].$el
let handleTransitionEnd = () => {
el.removeEventListener('transitionend', handleTransitionEnd)
resolve()
}
el.addEventListener('transitionend', handleTransitionEnd)
})
}
this.moveItem(this[itemsKey], fromIndex, toIndex)
// 动画完了再回调成功
return promise
}
},
moveItem (items, fromIndex, toIndex) {
let item = items[fromIndex]
items.splice(fromIndex, 1)
if (toIndex > fromIndex) {
toIndex--
}
items.splice(toIndex, 0, item)
}
}
}
</script>
<style lang="less" scoped>
.list-move {
// 动画曲线是 0.25, 0.1, 0.25, 1,就是 ease
transition: transform 200ms ease;
}
</style>
API
绑定值
类型:Object
。
参数 | 类型 | 默认值 | 描述 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
targets | Array<string|Vue|HTMLElement> | [] | 该参数指定了目标元素集合,在指令所在元素上拖拽鼠标的时候,会按照指定的方式变换所有目标元素。
| ||||||||||||
type | string | - | 该参数指定变化的类型,目前内置了 translate 类型(变换目标元素位置),可以进行扩展。 | ||||||||||||
draggable | boolean | true | 是否响应鼠标拖拽操作。 | ||||||||||||
containment | string|Vue|HTMLElement|Object | - | 目标元素在变换的时候,应当始终位于 如果通过
| ||||||||||||
axis | string | - | 限制所有目标元素只能在水平或者垂直方向上做变换。取值为:x 、y 。 | ||||||||||||
dragstart | function(): Object | function() {} | 鼠标拖拽开始事件的回调函数。回调参数为 | ||||||||||||
drag | function(): Object | function() {} | 鼠标拖拽中事件的回调函数。回调参数为
| ||||||||||||
disabled | boolean | false | 该指令是否被禁用。 | ||||||||||||
dragend | function(): Object | function() {} | 鼠标拖拽结束事件的回调函数。回调参数同 drag 。 | ||||||||||||
ready | function | function() {} | 指令初始化完成的回调函数,会传出一个句柄对象参数,该对象上有一个 reset() 方法,用于将所有目标元素重置为变换之前的样子。 |
Object
类型提供的参数会覆盖通过指令参数、修饰符指定的参数。
修饰符
对应 Object
绑定值中的 type
/axis
。例如:
<!-- 沿着垂直方向做位移变换 -->
<div v-drag.translate.y></div>
参数
对应 Object
绑定值中的 targets
。值是一个用 ,
分隔的、表示一到多个 ref
的字符串。例如:
<div v-drag:box1,box2></div>
拖拽排序(v-drag.sort)
可以通过 v-drag.sort
或 v-drag="{type: 'sort', ...}"
来实现拖拽排序。
绑定值
类型:Object
。
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
name | string | - | 用来标记一组项目,在这组项目中进行排序。 |
type | string | - | 该参数指定变化的类型,拖拽排序是 sort 。 |
containment | string|Vue|HTMLElement|Object | - | 参见上面的基础描述 |
axis | string | - | 限制所有目标元素只能在水平或者垂直方向上做排序。取值为:x 、y 。 |
callback | function(toIndex: number, fromIndex: number): void | - | 排序指令仅仅通过该回调告诉用户排序的情况,即:从原来位置( 回调触发时机:当 fromIndex 元素的中心点拖动到热区(toIndex 元素尾部和 toIndex+1 元素首部之间的区域)中触发。 |
debug | boolean | false | 在开发模式(process.env.NODE_ENV === 'development')下在 DOM 上显示热区标记以方便调试。 |
扩展
可以通过继承 BaseHandler
扩展 v-drag
指令:
import BaseHandler from 'veui/directives/drag/BaseHandler'
import { registerHandler } from 'veui/directives/drag'
class RotateHandler extends BaseHandler { }
registerHandler('rotate', RotateHandler)
然后通过 type
参数使用 RotateHandler
:
<div v-drag="{ type: 'rotate' }"></div>
<!-- 或者 -->
<div v-drag.rotate></div>
type
的名称不能与已有的修饰符冲突。
BaseHandler
BaseHandler
中各成员的说明如下:
成员名 | 类型 | 描述 |
---|---|---|
options | Object | 解析出来的参数组成的对象。 |
context | Vue | 指令所在的组件。 |
isDragging | boolean | 是否处于拖拽过程中。 |
start | function(Object) | 同绑定值中的 dragstart 字段。 |
drag | function(Object) | 同绑定值中的 drag 字段。 |
end | function(Object) | 同绑定值中的 dragend 字段。 |
destroy | function() | 指令与 DOM 元素解绑的时候调用。 |
setOptions | function(options) | 设置参数。 |
reset | function() | 重置变换。 |