123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- <template>
- <scroll-view scroll-y :show-scrollbar="showScrollBar" class="w-drag-sorts-scroll" :style="{height: scrollBoxPxHeight+'px'}">
- <view class="w-drag-sorts" :style="{height: boxHeight+'px'}" :class="{'inited':inited}">
- <view class="w-drag-sorts-item" v-for="(vo,i) in newList" :key="i"
- :style="{'top': vo.__top + 'px', ...finallyItemStyles}"
- :class="{'draging':currentIndex == i}" @longpress="onRemove(i)" @click="navTo(i)">
- <view class="align-center">
- <view class="ctrl"
- v-if="showDragCtrl"
- @touchmove.stop.prevent
- @touchstart="onTouchstart($event, i)"
- @touchmove="onTouchmove"
- @touchend="onTouchend"
- >
- <!-- <image class="icon" :src="ctrlIcon" /> -->
- <image class="w32 h32" src="@/static/images/user/drag_icon.png"></image>
- </view>
- <view class="text">
- {{vo.indicatorName}}
- </view>
- </view>
- <!-- <view class="content2"> -->
- <view v-if="isRemove==true" class="item-icon" @click.stop="onDisabledClick(i,vo)" >
- <!-- <image class="icon" :src="vo.icon"/> -->
- <image class="w40 h40" src="@/static/images/user/remove_icon.png"></image>
- </view>
- <view v-if="isAdd==true" class="item-icon" @click.stop="onAddClick(i,vo)">
- <!-- <image class="icon" :src="vo.icon"/> -->
- <image class="w40 h40" src="@/static/images/user/remove_add_icon.png"></image>
- </view>
- <!-- </view> -->
-
- </view>
- </view>
- </scroll-view>
- </template>
- <script>
- export default {
- name: "wDragSorts",
- props: {
- //列表数据
- listData: {
- type: Array,
- default: () => []
- },
- //列表项高度
- itemHeight: {
- type: Number,
- default: 80
- },
- //列表内边距,
- itemStyles: {
- type: Object,
- default: () => {
- return {};
- }
- },
- //控制图标
- ctrlIcon:{
- type:String,
- default:'/static/images/user/drag_icon.png'
- },
- //是否显示拖动控制器
- showDragCtrl:{
- type:Boolean,
- default: true,
- },
- //滚动去高度,如果单位rpx,如果不设置,内容容器高度一致
- scrollBoxHeight:{
- type: Number,
- default:-1
- },
- //是否显示删除图标
- isRemove:{
- type:Boolean,
- default: true,
- },
- //是否显示新增图标
- isAdd:{
- type:Boolean,
- default: true,
- }
- },
- data() {
- return {
- newList: [],
- //当前列表项的下标
- currentIndex: -1,
- //记录拖动位置
- moveY: 0,
- //拖动状态
- draging: false,
- //初始化完成
- inited:false,
- }
- },
- computed:{
- itemPxHeight(){
- return uni.rpx2px(this.itemHeight);
- },
- boxHeight(){
- return this.itemPxHeight * this.listData.length;
- },
- finallyItemStyles(){
- return { ...(this.itemStyles || {}), height: this.itemHeight+'rpx'}
- },
- scrollBoxPxHeight(){
- if( this.scrollBoxHeight < 0 ){
- return this.boxHeight
- }else{
- let _height = uni.rpx2px(this.scrollBoxHeight);
- if( _height > this.boxHeight ){
- _height = this.boxHeight
- }
- return _height;
- }
- },
- showScrollBar(){
- return (this.boxHeight - this.scrollBoxPxHeight) > 10;
- }
- },
- watch:{
- showScrollBar:{
- handler(v){
- console.log(v)
- },
- immediate:true
- },
- listData:{
- handler(v){
- this.listData=v
- this.init()
- },
- immediate:true
- }
- },
- created() {
- },
- mounted() {
-
- },
- methods: {
- init() {
- this.inited = false;
- this.newList = this.listData.map(vo => {
- return {
- ...vo,
- __top: 0,
- __height: 0,
- __otop: 0
- }
- });
- // console.log(this.listData,'888')
- // #ifdef MP-WEIXIN
- const selector = uni.createSelectorQuery().in(this);
- // #endif
- // #ifndef MP-WEIXIN
- const selector = uni.createSelectorQuery();
- // #endif
- this.$nextTick(() => {
- selector.selectAll('.w-drag-sorts-item').fields({
- rect: true,
- size: true,
- }, nodeItem => {
- nodeItem.forEach((item, index) => {
- const top = item.height * index;
- this.$set(this.newList, index, {
- ...this.newList[index],
- __height: item.height,
- __top: top,
- __otop: top
- });
- });
- this.inited = true;
- }).exec();
- });
-
- },
-
- onTouchstart(e, i) {
- const pageY = e.touches[0]?.pageY || 0;
- // 记录当前拖动元素的下标
- this.currentIndex = i;
- // 记录拖动前的位置
- this.moveY = pageY
- },
- onTouchmove(e) {
- const pageY = e.touches[0]?.pageY || 0;
- const index = this.currentIndex;
- //列表项替换的阈值,如果移动的位置大于上下项的一半就执行位置占位操作
- const currentItem = this.newList[index];
- const changeVar = currentItem?.__height / 2;
- //判断上下移动的边界
- let newTop = this.newList[index].__top + (pageY - this.moveY);
- const max = currentItem?.__height * (this.newList.length - 1);
- if (newTop < 0) {
- newTop = 0;
- }
- if (newTop > max) {
- newTop = max;
- }
- // 设置被拖动项最新的位置
- this.newList[index].__top = newTop;
- // 记录位置
- this.moveY = pageY;
-
- // 向下拖动
- if (currentItem.__top >= this.newList[index + 1]?.__top - changeVar) {
- this.moveChange(1);
- }
- // 向上拖动
- if (currentItem.__top <= this.newList[index - 1]?.__top + changeVar) {
- this.moveChange(-1);
- }
- },
- moveChange(addValue) {
- const index = this.currentIndex;
- if (this.draging) {
- return
- }
- this.draging = true
- let currentItem = this.newList[index];
- const newIndex = index + addValue;
- //取出被替换项的位置,等交换完位置之后,给当前列表项
- const changeItemOTop = this.newList[newIndex].__otop;
- //交换位置
- this.newList[index] = this.newList[newIndex];
- this.newList[newIndex] = currentItem;
- //把当前项的位置给被替换的列表项
- this.newList[index].__top = currentItem.__otop;
- this.newList[index].__otop = currentItem.__otop;
- //由于当前列表项的top一直在改变,所以这里只需要把被替换列表项的原有位置给当前列表项
- //等到停止拖动再把这个被替换项的位置赋给当前项的top
- this.newList[newIndex].__otop = changeItemOTop;
- this.currentIndex = newIndex;
- this.draging = false;
- },
- onTouchend(e) {
- const index = this.currentIndex;
- this.newList[index].__top = this.newList[index].__otop;
- this.currentIndex = -1;
- const returnData = this.getReturnData();
- this.$emit('draged', [...returnData]);
- },
-
- //返回移除操作附加属性的列表数据
- getReturnData(){
- const tmp = JSON.parse(JSON.stringify(this.newList));
- tmp.map(vo => {
- for (let key in vo) {
- if (key.indexOf('__') == 0) {
- delete vo[key];
- }
- }
- })
- return tmp;
- },
- navTo(i){
- const item = this.getReturnData()[i]
- this.$emit("navClick",i, item);
- },
- //长按删除
- onRemove( i ){
- console.log(i,'1')
- const item = this.getReturnData()[i]
- this.$emit("itemRemoveClick",i, item);
- },
- //禁用
- onDisabledClick( i ){
- const item = this.getReturnData()[i]
- this.$emit("itemDisabledClick",i, item);
- },
- //启用
- onAddClick( i ){
- const item = this.getReturnData()[i]
- this.$emit("itemAddClick",i, item);
- },
- //列表项图标点击事件点击
- onItemIconClick( i ){
- const item = this.getReturnData()[i]
- this.$emit("itemIconClick",i, item);
- },
-
- }
- }
- </script>
- <style scoped lang="scss">
- @mixin iconSize {
- width: 48rpx;
- height: 48rpx;
- }
- .w-drag-sorts {
- width: 100%;
- position: relative;
- z-index: 1;
- height: auto;
- .icon {
- @include iconSize();
- }
-
- &.inited>&-item{
- position: absolute;
- }
- &-item {
- width: 100%;
- display: flex;
- justify-content: space-between;
- align-items: center;
- box-sizing: border-box;
- background-color: #fff;
- padding: 0 30rpx;
- border-bottom: 0 !important;
- &.draging {
- box-shadow: 0 0px 30rpx #ddd;
- z-index: 1;
- }
- .text{
- margin-left: 20rpx;
- font-family: PingFang SC, PingFang SC;
- font-weight: 400;
- font-size: 32rpx;
- color: #222426;
- text-align: left;
- }
- .item-icon{
- @include iconSize();
-
- }
- // .content2 {
- // flex:1;
- // height: 100%;
- // display: flex;
- // align-items: center;
-
- // }
- .ctrl {
- width: 32rpx;
- height: 32rpx;
- }
- }
- }
- </style>
|