Files
FirstUI-vue/components/firstui/fui-drag/fui-drag.vue
2023-08-17 21:28:49 +08:00

373 lines
9.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--本文件由FirstUI授权予新疆天衡创新研究院有限公司手机号 1861 4072 54 9身份证尾号5A07X5专用请尊重知识产权勿私下传播违者追究法律责任-->
<template>
<!-- #ifndef APP-VUE || MP-WEIXIN || H5 -->
<view class="fui-drag__wrap" ref="fui_drag" :id="elId"
:style="{width:wrapWidth+'px',height:(rows * cellHeight)+'px'}"
:class="[dragging?'fui-drag-item__show':'fui-drag-item__hidden']">
<!-- #endif -->
<!-- #ifdef APP-VUE || MP-WEIXIN || H5 -->
<!-- vue3下编译到小程序data数据与wxs混用中无法获取 $data数据无法直接应用到页面uni-app官方编译bug-->
<view class="fui-drag__wrap" :catch:touchmove="wxDrag?true:''"
:class="[dragging?'fui-drag-item__show':'fui-drag-item__hidden']" ref="fui_drag" :id="elId"
:style="{width:wrapWidth+'px',height:(rows * cellHeight)+'px'}" :list="list"
:change:list="handler.listChange" :param="param" :change:param="handler.paramChange">
<view class="fui-drag-item__wrap" :style="{width:cellWidth+'px',height:cellHeight+'px'}"
v-for="(item, index) in list" :key="item.id" :data-index="index" @longpress="handler.longPress"
:data-param="param" :data-isdrag="isDrag && dragging?1:0" @touchstart="handler.touchStart"
@touchmove="handler.touchMove" @touchend="handler.touchEnd" @mousedown="handler.mousedown"
@tap="itemClick(index)">
<template v-if="custom">
<slot :model="item.entity" :width="cellWidth" :height="cellHeight" :index="index"></slot>
</template>
<template v-else>
<f-drag-item @delete="deleteItem" :src="(item.entity && item.entity.src) || 'true'"
:text="item.entity && item.entity.text" :width="cellWidth" :height="cellHeight"
:styles="styles" :index="index">
</f-drag-item>
</template>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view fireEventSync="true" class="fui-drag-item__wrap" v-for="(item, index) in list" :key="item.id"
:style="{width:cellWidth+'px',height:cellHeight+'px'}" @touchstart="touchstart"
@touchmove="touchmove" @touchend="touchend" @longpress="longPress" :data-index="index"
:ref="'f_drag_'+index">
<template v-if="custom">
<slot :model="item.entity" :width="cellWidth" :height="cellHeight" :index="index"></slot>
</template>
<template v-else>
<f-drag-item @delete="deleteItem" :src="item.entity && item.entity.src"
:text="item.entity && item.entity.text" :width="cellWidth" :height="cellHeight"
:styles="styles" :index="index">
</f-drag-item>
</template>
</view>
<!-- #endif -->
<!-- #ifndef APP-PLUS || MP-WEIXIN || H5-->
<view class="fui-drag-item__wrap"
:class="{'fui-drag__cur':current===index,'fui-drag__trans':current!==index}"
v-for="(item, index) in list" :key="item.id"
:style="{width:cellWidth+'px',height:cellHeight+'px',transform: `translate3d(${index === current ? transX : item.transX}, ${index === current ? transY: item.transY}, 0px)`}"
@touchstart="touchstart" @touchmove.stop.prevent="touchmove" @touchend="touchend"
@longpress="longPress" :data-index="index">
<template v-if="custom">
<slot :model="item.entity" :width="cellWidth" :height="cellHeight" :index="index"></slot>
</template>
<template v-else>
<f-drag-item @delete="deleteItem" :src="(item.entity && item.entity.src) || ''"
:text="item.entity && item.entity.text" :width="cellWidth" :height="cellHeight"
:styles="styles" :index="index">
</f-drag-item>
</template>
</view>
<!-- #endif -->
</view>
</template>
<!-- #ifdef APP-VUE || MP-WEIXIN || H5-->
<script src="./index.wxs" module="handler" lang="wxs"></script>
<!-- #endif -->
<script>
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom');
// #endif
import fDragItem from './f-drag-item.vue'
import bindingx from './bindingx.js'
import mpjs from './mpjs.js'
export default {
name: "fui-drag",
mixins: [mpjs, bindingx],
emits: ['change', 'end', 'click', 'delete'],
components: {
fDragItem
},
props: {
itemList: {
type: Array,
default () {
return [];
}
},
width: {
type: [Number, String],
default: 0
},
// 每行显示个数
columns: {
type: [Number, String],
default: 1
},
//必传square为true时失效
itemHeight: {
type: [Number, String],
default: 0
},
// 是否正方形显示为true时itemHeight失效
square: {
type: Boolean,
default: false
},
styles: {
type: Object,
default () {
return {}
}
},
// 页面滚动高度
scrollTop: {
type: Number,
default: 0
},
//是否可拖拽
isDrag: {
type: Boolean,
default: true
},
custom: {
type: Boolean,
default: false
}
},
watch: {
itemList(val) {
this.list = []
setTimeout(() => {
this.reset()
}, 0);
},
width(val) {
this.list = []
setTimeout(() => {
this.reset()
}, 0);
},
columns(val) {
this.list = []
setTimeout(() => {
this.reset()
}, 0);
}
},
data() {
const elId = `fui_${Math.ceil(Math.random() * 10e5).toString(36)}`
return {
elId,
// #ifdef APP-VUE || MP-WEIXIN || H5
param: {},
// #endif
windowHeight: 0,
wrapWidth: 0,
wrapHeight: 0,
cellWidth: 0,
cellHeight: 0,
changeList: [],
rows: 3,
options: [],
dragging: true,
wrapTop: 0,
wrapLeft: 0,
list: [],
wxDrag: true
};
},
mounted() {
this.$nextTick(() => {
this.reset();
})
},
methods: {
getId() {
return `${Math.ceil(Math.random() * 10e5).toString(36)}_${new Date().getTime()}`
},
getWidth(fn) {
let width = Number(this.width)
let sys = uni.getSystemInfoSync()
this.windowHeight = sys.windowHeight;
if (width === 0) {
width = sys.windowWidth
} else {
width = uni.upx2px(width)
}
this.wrapWidth = width
//此处小数会导致出现误差
this.cellWidth = width / Number(this.columns)
let cellHeight = uni.upx2px(this.itemHeight)
if (this.square) {
cellHeight = this.cellWidth
}
this.cellHeight = cellHeight
fn && fn()
},
reset() {
this.options = []
// #ifndef APP-NVUE
this.wxDrag = true;
this.dragging = false
// #endif
this.getWidth(() => {
setTimeout(() => {
this.init()
}, 0);
})
},
getDom(callback, index = 0) {
// #ifndef APP-NVUE
uni.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(this)
// #endif
.select(`#${this.elId}`)
.boundingClientRect()
.exec(ret => {
if (index >= 10) return
if (!ret && !ret[0]) {
index++
this.getDom(callback, index)
return
}
let wrapTop = ret[0].top + this.scrollTop;
let wrapLeft = ret[0].left
callback && callback(wrapTop, wrapLeft)
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['fui_drag'], (ret) => {
if (ret && ret.size) {
let wrapTop = ret.size.top + this.scrollTop;
let wrapLeft = ret.size.left
callback && callback(wrapTop, wrapLeft)
}
})
// #endif
},
init(index = 0) {
let options = JSON.parse(JSON.stringify(this.itemList));
let columns = Number(this.columns)
this.rows = Math.ceil(options.length / this.columns);
if (options.length === 0) return;
setTimeout(() => {
this.getDom((wrapTop, wrapLeft) => {
let list = options.map((item, index) => {
return {
id: this.getId(),
realKey: index,
sortKey: index,
//若有误差cellWidth、cellHeight取整
transX: `${index%columns * this.cellWidth}px`,
transY: `${Math.floor(index/columns) * this.cellHeight}px`,
entity: item
}
});
this.changeList = list;
this.list = list
this.wrapTop = wrapTop;
this.wrapLeft = wrapLeft;
// #ifdef APP-VUE || MP-WEIXIN || H5
this.param = {
windowHeight: this.windowHeight,
columns: Number(this.columns),
rows: this.rows,
cellWidth: this.cellWidth,
cellHeight: this.cellHeight,
wrapLeft: this.wrapLeft,
wrapTop: this.wrapTop
};
// #endif
this.dragging = true
})
}, 500)
},
drag(e) {
this.wxDrag = e.wxdrag;
},
sortend(e) {
this.$emit('end', {
itemList: e.itemList
});
},
change(e) {
this.$emit('change', {
itemList: e.itemList
});
},
itemClick(index) {
if (!this.changeList || this.changeList.length === 0) return;
let item = this.changeList[index];
this.$emit('click', {
index: item.realKey,
item: item.entity
});
},
deleteItem(e) {
this.$emit('delete', {
index: e.index
});
},
listChange(e) {
this.changeList = e.itemList;
},
pageScroll(e) {
// #ifndef APP-NVUE
uni.pageScrollTo({
scrollTop: e.scrollTop,
duration: 0
});
// #endif
}
}
}
</script>
<style scoped>
.fui-drag__wrap {
/* #ifndef APP-NVUE */
width: 100%;
box-sizing: border-box;
transform: translate3d(0, 0, 0);
/* #endif */
position: relative;
}
.fui-drag-item__wrap {
position: absolute;
left: 0;
top: 0;
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
overflow: hidden;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 1;
/* #ifdef H5 */
cursor: grab;
/* #endif */
}
.fui-drag-item__hidden {
opacity: 0;
transition-property: opacity;
transition-duration: .35s;
}
.fui-drag-item__show {
opacity: 1 !important;
}
.fui-drag__trans {
transition-property: transform;
transition-duration: .35s;
}
.fui-drag__trans-end {
transition-property: transform;
transition-duration: .35s;
}
.fui-drag__cur {
z-index: 5 !important;
}
</style>