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