1.组件封装
1px.less 文件
.setLine(@c: #eee) {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 200%;
// border: 1rpx solid @c;
color: @c;
height: 200%;
transform-origin: left top;
transform: scale(0.5);
}
.vh-1px, .vh-1px-t, .vh-1px-b, .vh-1px-tb, .vh-1px-l, .vh-1px-r {
position: relative;
}
.vh-1px {
&:before {
.setLine();
}
}
.vh-1px-t {
&:before {
.setTopLine();
}
}
.vh-1px-b {
&:after {
.setBottomLine();
}
}
.vh-1px-tb {
&:before {
.setTopLine();
}
&:after {
.setBottomLine();
}
}
.vh-1px-l {
&:before {
.setLeftLine();
}
}
.vh-1px-r {
&:after {
.setRightLine();
}
}
.setTopLine(@c: #eee) {
content: " ";
position: absolute;
left: 0;
top: 0;
right: 0;
height: 1rpx;
// border-top: 1rpx solid @c;
color: @c;
transform-origin: 0 0;
transform: scaleY(0.5);
}
.setBottomLine(@c: #eee) {
content: " ";
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1rpx;
// border-bottom: 1rpx solid @c;
color: @c;
transform-origin: 0 100%;
transform: scaleY(0.5);
}
.setLeftLine(@c: #eee) {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 1rpx;
bottom: 0;
// border-left: 1rpx solid @c;
color: @c;
transform-origin: 0 0;
transform: scaleX(0.5);
}
.setRightLine(@c: #eee) {
content: " ";
position: absolute;
right: 0;
top: 0;
width: 1rpx;
bottom: 0;
// border-right: 1rpx solid @c;
color: @c;
transform-origin: 100% 0;
transform: scaleX(0.5);
}
index.vue 文件
<template>
<view class="">
<movable-area class="drag-sort" :style="{height:boxHeight }" id="drag">
<movable-view v-for="(item, index) in currentList" :key="index" :x="item.x" v-if="item.isShow === 1" :data-index="index"
@touchstart="touchstart" @touchmove.stop="touchmove" @touchend="touchend" @click="openTool(item)" :y="item.y"
:direction="direction" disabled damping="40" :animation="item.animation" class="drag-sort-item" :style="styleObject"
:class="{'active': active == index, 'vh-1px-t': item.index > 0}">
<view class="item">
<image :src="item.scr" mode="" style="width: 60rpx;height: 60rpx;"></image>
<view>{{item[props.label]}}</view>
</view>
</movable-view>
</movable-area>
</view>
</template>
<script>
export default {
name: 'drag-sort',
mixins: [],
components: {},
data() {
return {
styleObject: {
color: 'red',
fontSize: '13px'
},
style: {
background: 'red'
},
direction: "all",
windowWidth: 350, //屏幕宽度
height: 100, // 高度
currentList: [],
active: -1, // 当前激活的item
index: 0, // 当前激活的item的原index
topY: 0, // 距离顶部的距离
topX: 0, // 距离左侧偏移位置
deviationX: 0,
deviationY: 0 // 偏移量
}
},
computed: {
boxHeight() {
return (Math.ceil((Number(this.list.length) + 1) / 4)) * this.height + 'px'
}
},
props: {
list: {
type: Array,
default: () => {
return []
}
},
boxStyle: {
type: Object,
default: () => {
return {}
}
},
props: {
type: Object,
default: () => {
return {
label: 'label',
value: 'value'
}
}
}
},
watch: {
list: {
handler() {
this.onUpdateCurrentList(this.list)
},
deep: true
}
},
created() {},
mounted() {
let that = this
//获取屏幕宽度
uni.getSystemInfo({
success: function(res) {
that.windowWidth = res.windowWidth
}
});
this.getLocalstorageList()
},
updated() {},
filters: {},
methods: {
//获取缓存中的应用顺序
getLocalstorageList() {
let that = this
uni.getStorage({
key: 'appList',
success: function(res) {
that.onUpdateCurrentList(res.data)
},
fail: function() {
that.onUpdateCurrentList(that.list)
}
});
},
//存储图标位置
localstorageList(currentList) {
//对象数组根据属性进行排序
currentList.sort(function sortId(a, b) {
return a.SortNumber - b.SortNumber
});
//存储当前应用程序顺序
uni.setStorage({
key: 'appList',
data: currentList,
success: function() {}
});
},
//打开对应的工具
openTool(tools) {
console.log('currentclick', tools)
if (tools.url == 'd') {
//跳转外部小程序
uni.navigateToMiniProgram({
appId: 'wx63fe2171954ab185',
path: '',
extraData: {
'data1': 'test'
},
envVersion: 'develop',
success(res) {
console.log('外部小程序打开成功')
// 打开成功
},
fail(res) {
console.log('外部小程序打开失败')
// 打开失败
}
})
} else {
uni.navigateTo({
//url: `../${tools.value}/index/index`,
url: tools.url,
success: res => {},
fail: () => {},
complete: () => {}
});
}
},
onUpdateCurrentList(list) {
let arr = []
for (const key in list) {
let height = Math.ceil((Number(key) + 1) / 4) - 1
let x = 0
if (key <= 3) {
x = key * this.windowWidth * 0.24 + this.windowWidth * 0.04 || this.windowWidth * 0.04
} else {
if ((Number(key) + 1) % 4 === 0) {
x = 3 * this.windowWidth * 0.24 + this.windowWidth * 0.04 || this.windowWidth * 0.04
} else {
x = ((Number(key) + 1) % 4 - 1) * this.windowWidth * 0.24 + this.windowWidth * 0.04 || this.windowWidth * 0.04
}
}
arr.push({
...list[key],
isShow: 1,
index: Number(key),
SortNumber: Number(key),
y: height * this.height,
x,
animation: true
})
}
this.currentList = arr
},
// 根据排序进行重新计算位置
moveUpdateCurrentList(index) {
for (const i in this.currentList) {
let key
if (this.currentList[i].SortNumber || this.currentList[i].SortNumber === 0) {
key = this.currentList[i].SortNumber
} else {
key = Number(i)
}
let temobj = { ...this.currentList[i]
}
this.currentList[i].y = (Math.ceil((Number(key) + 1) / 4) - 1) * this.height
if (index == key) {
continue
} else {
if (key <= 3) {
this.currentList[i].x = key * this.windowWidth * 0.24 + this.windowWidth * 0.04 || this.windowWidth * 0.04
} else {
if ((Number(key) + 1) % 4 === 0) {
this.currentList[i].x = 3 * this.windowWidth * 0.24 + this.windowWidth * 0.04 || this.windowWidth * 0.04
} else {
this.currentList[i].x = ((Number(key) + 1) % 4 - 1) * this.windowWidth * 0.24 + this.windowWidth * 0.04 || this
.windowWidth * 0.04
}
}
}
}
this.$emit('change', this.currentList)
},
touchstart(e) {
// 计算 x y 轴点击位置
var query = uni.createSelectorQuery().in(this)
query.select('#drag').boundingClientRect()
query.exec((res) => {
this.topY = res[0].top
this.topX = res[0].left
let touchY = e.mp.touches[0].clientY - res[0].top
let touchX = e.mp.touches[0].clientX - res[0].left
this.deviationY = touchY % this.height
this.deviationX = touchX % (this.windowWidth * 0.2)
this.active = Number(e.currentTarget.dataset.index)
this.index = Number(e.currentTarget.dataset.index)
})
},
touchmove(e) {
if (this.active < 0) return
let temY = e.mp.touches[0].clientY - this.topY
let temX = e.mp.touches[0].clientX - this.topX
let touchY = temY - 15
let touchX = temX - this.windowWidth * 0.1
this.currentList[this.active].y = touchY
this.currentList[this.active].x = touchX
this.currentList[this.active].animation = false
this.currentList.every((res, index) => {
let absX = Math.abs(touchX - res.x)
let absY = Math.abs(touchY - res.y)
// 设置元素定点距离多少进行重排
if (0 < absX && absX <= 10 && absY > 0 && absY <= 10 && this.active != index) {
// debugger
let temNumber = this.currentList[index].SortNumber
this.currentList.every((_res, _index) => {
// 判断从大像小移还是从小向大移
if (this.currentList[this.active].SortNumber < this.currentList[index].SortNumber) {
// 移动元素比目标元素所在位置小,之间元素排序--
if (this.currentList[_index].SortNumber > this.currentList[this.active].SortNumber && this.currentList[
_index].SortNumber <= this.currentList[index].SortNumber) {
_res.SortNumber--
}
} else {
// 反之++
if (this.currentList[_index].SortNumber < this.currentList[this.active].SortNumber && this.currentList[
_index].SortNumber >= this.currentList[index].SortNumber) {
_res.SortNumber++
}
}
return true
}, this)
this.currentList[this.active].SortNumber = temNumber
this.moveUpdateCurrentList(temNumber)
return false
} else {
return true
}
}, this)
},
touchend(e) {
if (this.currentList[this.active]) {
this.currentList[this.active].animation = true
}
this.moveUpdateCurrentList(-1)
this.active = -1
//当前顺序本地存储(一定要深拷贝啊啊啊!!!)
this.localstorageList(JSON.parse(JSON.stringify(this.currentList)))
}
}
}
</script>
<style lang='less' scoped>
@import "~./1px.less";
.drag-sort {
width: calc(100% - 20rpx);
}
.drag-sort-item {
position: absolute !important;
display: flex;
height: auto;
align-items: center;
width: 25%;
text-align: center;
color: #333;
box-sizing: border-box;
.item {
position: relative;
flex: 1;
font-size: 24rpx;
}
}
.active {
z-index: 99;
}
</style>
2.页面引用
3.预览
可拖拽排序
备注:这版做的是微信小程序端的,app可自行试试