uni-item-manage/tm-vuetify/components/tm-dragList/tm-dragList.vue
2023-10-18 15:52:41 +08:00

272 lines
7.3 KiB
Vue
Raw Permalink 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.

<template>
<view class="tm-dragList ">
<view :style="{height:h*list.length+'px',width:w+'px'}" class="relative"
:class="[disabled?'opacity-7':'']">
<view class="fulled-height overflow" :class="[bgColor,black_tmeme?'grey-darken-4 bk':'',
'absolute',
'tm-dragList-item','shadow-'+(nowMove_index==index?16:0),'flex-between']" v-for="(item,index) in listData"
:key="index" :style="{
transition: nowMove_index==index||endDrage?'all 0s':'all 0.25s',
top: item.top+'px',
height:h+'px',width:w+'px',zIndex:nowMove_index==index?5:0}">
<view class=" flex-start fulled" :class="[black_tmeme?'border-grey-darken-5-b-1':'border-b-1']"
:style="{height:(h-1)+'px'}"
>
<view v-if="item['icon']" class="flex-shrink pl-32 fulled-height flex-center">
<tm-icons :black="black_tmeme" :color="item['color']||'black'" :fllowTheme="fllowTheme" dense
:name="item['icon']" :size="40"></tm-icons>
</view>
<view class="pl-32 text-size-n" :class="[black_tmeme?'bk':'']">{{item.text}}</view>
</view>
<view
:style="{height:(h-1)+'px',width: '100rpx'}"
@touchstart="m_start($event,index)"
@mousedown="m_start($event,index)"
@touchmove.stop.prevent="m_move($event,index)"
@mousemove.stop.prevent="m_move($event,index)"
@touchend="m_end($event,index)"
@mouseup="m_end($event,index)"
class="flex-shrink flex-end " :class="[black_tmeme?'border-grey-darken-5-b-1':'border-b-1']">
<text class="iconfont icon-menu pr-32 text-size-n"
:class="[black_tmeme?' bk text-grey-darken-2':'text-grey']"></text>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* 拖放排序
* @property {String | Boolean} black = [true|false] 默认null是否开启暗黑模式
* @property {String | Boolean} disabled = [true|false] 默认false是否禁用禁用后无法操作。
* @property {Number} width = [] 默认0组件的宽度rpx,可不提供,默认为父组件的宽度。
* @property {Number} height = [] 默认120列表项目的高度rpx,
* @property {String} bgColor = [] 默认white项目的背景色
* @property {String} right-icon = [] 默认:'',项目右边可拖动的图标
* @property {String} rang-key = [] 默认:'text'列表项目读取文本的key
* @property {String} list = [] 默认:[],列表数据[{text: "菜单选项",icon: 'icon-menu',color:'red'}]
* @param {Function} change 拖动排序后触发返回新的排序后list数据。
*/
import tmIcons from '@/tm-vuetify/components/tm-icons/tm-icons.vue';
export default {
name: "tm-dragList",
components: {
tmIcons
},
props: {
disabled: {
type: String | Boolean,
default: false
},
// 跟随主题色的改变而改变。
fllowTheme: {
type: Boolean | String,
default: true
},
// 是否开启暗黑模式
black: {
type: String | Boolean,
default: null
},
width: {
type: Number,
default: 0
},
height: {
type: Number,
default: 120
},
list: {
type: Array,
default: () => {
return []
}
},
rangKey: {
type: String,
default: 'text'
},
rightIcon: {
type: String,
default: "icon-menu"
},
bgColor: {
type: String,
default: "white"
},
},
destroyed() {
clearTimeout(999)
},
watch: {
list: {
deep: true,
handler() {
this.jishunTopData();
}
}
},
data() {
return {
w: 0,
h: 0,
totalH: 0,
y: 0,
new_index: null, //即将被替换的索引(实质性被替换)
nowMove_index: null, //现在正在移动的索引
listData: [], //被处理过的数据。
new_item: [], //虚拟列表,内部排列好,但未在页面中渲染。
endDrage: false,
Drage__id: '', //正在被拖动的id;
h_top: 0,
};
},
computed: {
black_tmeme: function() {
if (this.black !== null) return this.black;
return this.$tm.vx.state().tmVuetify.black;
},
},
async mounted() {
let t = this;
this.jishunTopData();
},
methods: {
jishunTopData() {
this.$nextTick(async function() {
this.listData = [];
let p = await this.$Querey(".tm-dragList", this).catch(e => {})
this.w = uni.upx2px(this.width) || p[0].width;
this.h = uni.upx2px(this.height)
this.totalH = this.h * this.list.length
let list = [];
for (let i = 0; i < this.list.length; i++) {
let p = this.list[i];
p['top'] = i * this.h;
p['i'] = i;
p['__id'] = uni.$tm.guid();
this.listData.push(p)
}
this.new_item = [...this.listData];
})
},
m_start(event, index) {
event.preventDefault()
event.stopPropagation()
if (this.disabled) return;
this.nowMove_index = index;
this.endDrage = false;
this.new_item = [...this.listData];
if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
var touch = event.changedTouches[0];
this.y = touch.pageY - event.currentTarget.offsetTop - this.listData[index].top
} else {
this.y = event.pageY - event.currentTarget.offsetTop - this.listData[index].top
}
// #ifdef MP
uni.vibrateShort({})
// #endif
},
m_move(event, index) {
if (this.disabled) return;
let t = this
event.preventDefault()
event.stopPropagation()
if (t.nowMove_index == null) return;
//当前元素的top位置。
let ch = 0;
if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
var touch = event.changedTouches[0];
ch = touch.pageY - t.y
} else {
ch = event.pageY - t.y
}
t.listData.splice(index, 1, {
...t.listData[index],
top: ch
})
const currenit_index = index;
const currentSort = t.listData[currenit_index].i;
const currenit_id = t.listData[currenit_index].__id;
// 计算当前移动的index.
let moveIndex = Math.round(ch / t.h);
moveIndex = moveIndex < 0 ? 0 : moveIndex;
moveIndex = moveIndex > t.listData.length - 1 ? t.listData.length - 1 : moveIndex;
moveIndex = Math.abs(moveIndex)
index = moveIndex;
let elList = [...t.listData]
for (let i = 0; i < elList.length; i++) {
if (currentSort < moveIndex) {
if (elList[i].i > currentSort && elList[i].i <= moveIndex) {
elList[i].i -= 1;
};
} else if (currentSort > moveIndex) {
if (elList[i].i < currentSort && elList[i].i >= moveIndex) {
elList[i].i += 1;
};
}
};
elList[currenit_index].i = moveIndex;
elList = elList.map(im => {
if (im.__id != currenit_id) {
im.top = im.i * t.h;
}
return im;
})
t.listData = elList;
t.new_index = moveIndex;
// #ifdef MP
uni.vibrateShort({})
// #endif
},
m_end(event, index) {
if (this.disabled) return;
let t = this;
event.preventDefault()
event.stopPropagation()
this.nowMove_index = null;
this.endDrage = true;
if (this.new_index == null) return;
let elList = t.listData
elList = elList.map(im => {
im.top = im.i * t.h;
return im;
})
elList.sort((a,b)=>a.i-b.i)
t.listData = [...elList]
this.moveChange();
},
moveChange(e, index) {
if (this.disabled) return;
//change后修改的数据 。
this.$emit('change', this.listData);
}
},
}
</script>
<style lang="scss">
</style>