279 lines
6.4 KiB
Vue
279 lines
6.4 KiB
Vue
<template>
|
||
<view
|
||
class="tn-drag-class tn-drag"
|
||
:style="{
|
||
height: wrapHeight + 'rpx'
|
||
}"
|
||
:list="listData"
|
||
:basedata="baseData"
|
||
:change:list="wxs.listObserver"
|
||
:change:basedata="wxs.baseDataObserver"
|
||
>
|
||
<!-- #ifdef MP-WEIXIN -->
|
||
<view
|
||
v-for="(item, index) in listData"
|
||
:key="item.id"
|
||
class="tn-drag__item"
|
||
:style="{
|
||
width: 100 / columns + '%',
|
||
height: itemHeight + 'rpx'
|
||
}"
|
||
:data-index="index"
|
||
:data-basedata="baseData"
|
||
:data-edit="edit"
|
||
@longpress="wxs.longPress"
|
||
@touchstart="wxs.touchStart"
|
||
:catch:touchmove="dragging?wxs.touchMove:''"
|
||
:catch:touchend="dragging?wxs.touchEnd:''"
|
||
>
|
||
<slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot>
|
||
</view>
|
||
<!-- #endif -->
|
||
|
||
<!-- #ifndef MP-WEIXIN -->
|
||
<view
|
||
v-for="(item, index) in listData"
|
||
:key="item.id"
|
||
class="tn-drag__item"
|
||
:style="{
|
||
width: 100 / columns + '%',
|
||
height: itemHeight + 'rpx'
|
||
}"
|
||
@longpress="wxs.longPress"
|
||
:data-index="index"
|
||
:data-basedata="baseData"
|
||
:data-edit="edit"
|
||
@touchstart="wxs.touchStart"
|
||
@touchmove="wxs.touchMove"
|
||
@touchend="wxs.touchEnd"
|
||
>
|
||
<slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot>
|
||
</view>
|
||
<!-- #endif -->
|
||
</view>
|
||
</template>
|
||
<script src="./index.wxs" lang="wxs" module="wxs"></script>
|
||
<script>
|
||
export default {
|
||
name: 'tn-drag',
|
||
props: {
|
||
// 数据源
|
||
// 如果属性中包含fixed,则标识当前数据不允许拖动
|
||
list: {
|
||
type: Array,
|
||
default () {
|
||
return []
|
||
}
|
||
},
|
||
// 是否允许拖动编辑
|
||
edit: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
// 列数
|
||
columns: {
|
||
type: Number,
|
||
default: 3
|
||
},
|
||
// item元素高度, 单位rpx
|
||
itemHeight: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
// 当前父元素滚动的高度
|
||
scrollTop: {
|
||
type: Number,
|
||
default: 0
|
||
}
|
||
},
|
||
computed: {
|
||
wrapHeight() {
|
||
return this.rows * this.itemHeight
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
// 未渲染前节点数据
|
||
baseData: {},
|
||
// 拖动后的数据
|
||
dragData: [],
|
||
// 行数
|
||
rows: 0,
|
||
// 渲染数据
|
||
listData: [],
|
||
// 标记是否正在拖动
|
||
dragging: false
|
||
}
|
||
},
|
||
watch: {
|
||
list(val) {
|
||
this.listData = []
|
||
this.$nextTick(() => {
|
||
this.init()
|
||
})
|
||
},
|
||
columns(val) {
|
||
this.listData = []
|
||
this.$nextTick(() => {
|
||
this.init()
|
||
})
|
||
}
|
||
},
|
||
mounted() {
|
||
this.$nextTick(() => {
|
||
this.init()
|
||
})
|
||
},
|
||
methods: {
|
||
// 初始化
|
||
init() {
|
||
this.dragging = true
|
||
const initDragItem = item => {
|
||
const obj = {
|
||
...item
|
||
}
|
||
const fixed = obj?.fixed || false
|
||
delete obj["fixed"]
|
||
return {
|
||
id: this.unique(),
|
||
fixed,
|
||
data: {
|
||
...obj
|
||
}
|
||
}
|
||
}
|
||
|
||
let i = 0
|
||
const listData = (this.list || []).map((item, index) => {
|
||
let listItem = initDragItem(item)
|
||
// 真实排序
|
||
listItem.realKey = i++
|
||
// 整体排序
|
||
listItem.sortKey = index
|
||
listItem.translateX = `${(listItem.sortKey % this.columns) * 100}%`
|
||
listItem.translateY = `${Math.floor(listItem.sortKey / this.columns) * 100}%`
|
||
return listItem
|
||
})
|
||
this.rows = Math.ceil(listData.length / this.columns)
|
||
this.listData = listData
|
||
this.dragData = listData
|
||
|
||
if (listData.length === 0) return
|
||
// console.log(listData);
|
||
|
||
// 初始化dom元素
|
||
this.$nextTick(() => {
|
||
this.initRect()
|
||
})
|
||
},
|
||
// 初始化dom元素
|
||
initRect() {
|
||
const {
|
||
windowWidth,
|
||
windowHeight
|
||
} = uni.getSystemInfoSync()
|
||
|
||
let baseData = {}
|
||
baseData.windowHeight = windowHeight
|
||
baseData.realTopSize = 0
|
||
baseData.realBottomSize = 0
|
||
baseData.columns = this.columns
|
||
baseData.rows = this.rows
|
||
|
||
const query = uni.createSelectorQuery().in(this)
|
||
query.select('.tn-drag').boundingClientRect()
|
||
query.select('.tn-drag__item').boundingClientRect()
|
||
query.exec(res => {
|
||
if (!res) {
|
||
setTimeout(() => {
|
||
this.initRect()
|
||
}, 10)
|
||
return
|
||
}
|
||
|
||
baseData.itemWidth = res[1].width
|
||
baseData.itemHeight = res[1].height
|
||
baseData.left = res[0].left
|
||
baseData.top = res[0].top + this.scrollTop
|
||
this.dragging = false
|
||
this.baseData = baseData
|
||
})
|
||
|
||
},
|
||
|
||
// 触发震动
|
||
vibrate() {
|
||
uni.vibrateShort()
|
||
},
|
||
// 滚动到指定的位置
|
||
pageScroll(e) {
|
||
uni.pageScrollTo({
|
||
scrollTop: e.scrollTop,
|
||
duration: 0
|
||
})
|
||
},
|
||
// 修改拖动状态
|
||
drag(e) {
|
||
this.dragging = e.dragging
|
||
},
|
||
// 拖拽数据发生改变
|
||
listDataChange(e) {
|
||
this.dragData = e.data
|
||
},
|
||
// item被点击
|
||
itemClick(index) {
|
||
const item = this.dragData[index]
|
||
this.$emit('click', {
|
||
key: item.realKey,
|
||
data: item.data
|
||
})
|
||
},
|
||
|
||
// 拖拽结束事件
|
||
sortEnd(e) {
|
||
this.$emit('end', {
|
||
data: e.data
|
||
})
|
||
},
|
||
// 排序发生改变事件
|
||
change(e) {
|
||
this.$emit('change', {
|
||
data: e.data
|
||
})
|
||
},
|
||
|
||
// 生成元素唯一id
|
||
unique(n = 6) {
|
||
let id = ''
|
||
for (let i = 0; i < n; i++) id += Math.floor(Math.random() * 10)
|
||
return 'tn_' + new Date().getTime() + id
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.tn-drag {
|
||
position: relative;
|
||
|
||
&__item {
|
||
position: absolute;
|
||
z-index: 2;
|
||
top: 0;
|
||
left: 0;
|
||
}
|
||
|
||
&__transition {
|
||
transition: transform 0.25s !important;
|
||
}
|
||
|
||
&__current {
|
||
z-index: 10 !important;
|
||
}
|
||
|
||
&__fixed {
|
||
z-index: 1 !important;
|
||
}
|
||
}
|
||
</style>
|