123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <template>
- <view class="tm-dragGrid relative fulled" :style="{height:totalH+'px'}">
-
- <view class="absolute "
- :class="[ani&&!disabled?'aniOn':'',nowMove_index==index||endDrage?'':'tranAni']"
- :style="{
- width:itemWidth+'px',
- height:h+'px',
- left:item.left+'px',
- top:item.top+'px',
- zIndex:nowMove_index==index?5:0
- }"
- v-for="(item,index) in listData"
- :key="index"
- :id="'tm-dragGrid-' + index"
- @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)"
- @longpress="startEdit"
- >
- <slot name="default" :item="item.data">
- <view v-if="model==0" class="flex-center flex-col" style="width:70%">
- <view style="width:100%"><tm-badges @click.stop="delitem(item)" v-if="!disabled" :offset="[0,-5]" icon="icon-times"></tm-badges></view>
- <tm-icons :size="45" :name="item.data.icon" :color="item.data.color"></tm-icons>
- <text class="text-size-s pt-10">{{item.data.text}}</text>
- </view>
- <view v-if="model==1" style="width:100%;height:100%">
- <tm-badges @click.stop="delitem(item)" v-if="!disabled" :offset="[-5,-5]" icon="icon-times"></tm-badges>
- <view :class="['bg-gradient-'+item.data.color+'-accent']" class=" flex-center round-4 text-size-s" style="width: 90%;height:100rpx">
- {{item.data.text}}
- </view>
- </view>
- </slot>
- </view>
- </view>
- </template>
- <script>
- /**
- * 宫格拖动排序
- * @property {Number} col = [] 4,一行排列几个
- * @property {Number} width = [] 0,组件宽度,可以不设置默认取父组件宽度
- * @property {Number} itemHeight = [] 120,项目的高度
- * @property {Boolean} ani = [] true,是否开启拖动显示内容抖动动画
- * @property {Boolean} disabled = [] false,是否开启拖动
- * @property {Boolean} longTap = [] true,是否允许长按启动编辑模式。
- * @property {Number} model = [0|1] 0,0图标模式,1方块样式。
- * @property {Array} list = [] [],排序的列表,只要是数组就可,至于内容是什么格式无所谓。
- * @property {Function} change 拖放排序时触发,返回更改后的列表数据。
- * @property {Function} remove 删除一个项目时触发。
- */
- import tmIcons from '@/tm-vuetify/components/tm-icons/tm-icons.vue';
- import tmBadges from '@/tm-vuetify/components/tm-badges/tm-badges.vue';
- export default {
- name:"tm-dragGrid",
- components:{tmBadges,tmIcons},
- props:{
- //几列,一行排几个。
- col:{
- type:Number,
- default:4
- },
- //组件宽度,可以不设置默认取父组件宽度
- width:{
- type:Number,
- default:0
- },
- //项目的高度
- itemHeight:{
- type:Number,
- default:120
- },
- //是否开启拖动显示内容抖动动画
- ani:{
- type:Boolean,
- default:true
- },
- disabled: {
- type: String | Boolean,
- default: false
- },
- list:{
- type:Array,
- default:()=>{}
- },
- //是否开户长按开始编辑。
- longTap:{
- type:Boolean,
- default:true
- },
- model:{
- type:Number,
- default:0,
- }
- },
- data() {
- return {
- w:0,
- h:0,
- row:0,
- totalH:0,
- listData:[],
- itemWidth:0,
- endDrage: false,
- Drage__id: '', //正在被拖动的id;
- nowMove_index: null, //现在正在移动的索引
- x:0,
- y:0,
- prarentTop:0,
- prarentLeft:0,
- grid:0,
- isDrage:false,
-
- };
- },
- computed:{
- },
- created() {
- this.grid = this.list.length;
- },
- mounted() {
- this.inits();
- },
- watch:{
- list:{
- deep:true,
- handler(){
- this.inits();
- }
- }
- },
- methods: {
- startEdit(){
- if(this.longTap==false) return;
- this.$emit("update:disabled",false)
- },
- delitem(item){
- this.list.splice(item.index,1)
- this.$emit('remove',item)
- this.$emit('change', this.listData);
- },
- m_start(event,index){
- event.preventDefault()
- event.stopPropagation()
- if (this.disabled) return;
- this.nowMove_index = index;
- this.endDrage = false;
- this.isDrage = true;
- if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
- var touch = event.changedTouches[0];
- this.y = touch.pageY - event.currentTarget.offsetTop - this.prarentTop
- this.x = touch.pageX - event.currentTarget.offsetLeft - this.prarentLeft
-
- } else {
- this.y = event.pageY - event.currentTarget.offsetTop - this.prarentTop
- this.x = event.pageX - event.currentTarget.offsetLeft - this.prarentLeft
-
- }
-
- // #ifdef MP
- uni.vibrateShort({})
- // #endif
- },
- m_move(event,index){
- let t = this
- if (this.disabled) return;
- event.preventDefault()
- event.stopPropagation()
- if(!this.isDrage) return;
- if (t.endDrage==true) return;
-
- //当前元素的top位置。
- let chy = 0;
- let chx = 0;
- if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
- var touch = event.changedTouches[0];
- chy = touch.pageY - t.y - this.prarentTop
- chx = touch.pageX - t.x - this.prarentLeft
-
- } else {
- chy = event.pageY - t.y - this.prarentTop
- chx = event.pageX - t.x - this.prarentLeft
- }
-
- t.listData.splice(index, 1, {
- ...t.listData[index],
- top: chy,
- left: chx,
- })
- t.nowMove_index = index;
-
- const currenit_index = index;
- const currentSort = t.listData[currenit_index].sort;
- const currenit_id = t.listData[currenit_index].__id;
-
- // 计算当前移动的index.
- let moveIndex = Math.round(chx / t.itemWidth) + Math.round(chy / t.h)*t.col;
-
- 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].sort > currentSort && elList[i].sort <= moveIndex) {
- elList[i].sort -= 1;
- };
- } else if (currentSort > moveIndex) {
- if (elList[i].sort < currentSort && elList[i].sort >= moveIndex) {
- elList[i].sort += 1;
- };
- }
- };
- elList[currenit_index].sort = moveIndex;
- elList = elList.map(el => {
- if (el.__id != currenit_id) {
- el.left = el.sort % t.col * t.itemWidth;
- el.top = parseInt(el.sort / t.col) * t.h;
-
- }
- return el;
- })
- t.listData = elList;
-
- },
- m_end(event,index){
-
- if (this.disabled) return;
- let t = this;
- event.preventDefault()
- event.stopPropagation()
- this.isDrage = false;
- this.endDrage = true;
- if (this.nowMove_index == null) return;
- let elList = [...t.listData]
- elList = this.setTL(elList);
- elList.sort((a,b)=>a.sort-b.sort)
- t.listData = [...elList]
- this.nowMove_index = null;
- this.moveChange();
- },
- moveChange(e, index) {
- if (this.disabled) return;
- //change后修改的数据 。
- const elList = [...this.listData]
- elList.sort((a,b)=>a.sort-b.sort-b)
- this.$emit('change',elList);
- },
- inits() {
- if(this.grid==0) return;
- this.$nextTick(async function() {
- let p = await this.$Querey(".tm-dragGrid", this).catch(e => {})
- this.grid = this.list.length;
- this.listData = [];
- //组件的宽度
- this.w = uni.upx2px(this.width) || p[0].width || 300;
- this.prarentTop = p[0].top;
- this.prarentLeft = p[0].left;
-
- //项目的高度。
- this.h = uni.upx2px(this.itemHeight)
- //项目的宽度
- this.itemWidth = this.w / this.col
- //行数。
- this.row = Math.ceil(this.grid / this.col);
-
- //总高度
- this.totalH = this.h * this.row
- //构造一个list宫格列表出来。
- for(let i=0;i<this.grid;i++){
- this.listData.push({
- "data":this.list[i],
- "__id":uni.$tm.guid(),
- "top":0,
- "left":0,
- "sort":i,
- "index":i
- })
- }
- let list = this.setTL([...this.listData]);
- this.listData = [...list];
- })
- },
- //计算位置。
- setTL(el){
- for(let i = 0;i < el.length;i++){
- el[i].left = el[i].sort % this.col * this.itemWidth;
- el[i].top = parseInt(el[i].sort / this.col) * this.h;
- }
- return el;
- }
- },
- }
- </script>
- <style lang="scss" scoped>
- .aniOn{
- animation:doudong 0.5s linear infinite;
- background:linear-gradient();
- background: -webkit-linear-gradient();
-
- }
- .tranAni{
- transition:all 0.15s
- }
- @keyframes doudong {
- 0%{
- transform: rotate(-2deg) translateX(2rpx) translateY(2rpx);
- }
- 25%{
- transform: rotate(0deg) translateX(-2rpx) translateY(-2rpx);
- }
- 50%{
- transform: rotate(0deg) translateX(0rpx) translateY(-2rpx);
- }
- 75%{
- transform: rotate(0deg) translateX(0rpx) translateY(2rpx);
- }
- 100%{
- transform: rotate(-2deg) translateX(2rpx) translateY(2rpx);
- }
- }
- </style>
|