123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- <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>
|