drop-card.uvue 7.7 KB
Newer Older
DCloud_JSON's avatar
DCloud_JSON 已提交
1
<template>
2 3
  <view class="root">
    <template v-for="(item,index) in cardList" :key="index">
4
      <view class="card" ref="card" @touchstart="touchstart($event as TouchEvent)" @touchmove="touchmove($event as TouchEvent)" @touchend="touchend" @touchcancel="touchend">
5
        <image class="card-img" ref="card-img" :src="item"></image>
6 7 8 9
        <view class="state">
          <image class="state-icon like" ref="state-icon-like" src="/static/template/drop-card/like.png" mode="widthFix"></image>
          <image class="state-icon dislike" ref="state-icon-dislike" src="/static/template/drop-card/dislike.png" mode="widthFix"></image>
        </view>
DCloud_JSON's avatar
DCloud_JSON 已提交
10
      </view>
11
    </template>
DCloud_JSON's avatar
DCloud_JSON 已提交
12 13 14 15
  </view>
</template>
<script lang="ts">
  let sX : number = 0,
16
    sY : number = 0,
17 18 19
    screenWidth : number = 1,
    floating:boolean = false,
    touchstartAfter:boolean = false;
20
    
DCloud_JSON's avatar
DCloud_JSON 已提交
21 22 23
  export default {
    data() {
      return {
24 25
        x: 0 as number,
        y: 0 as number,
26 27 28 29 30
        cardList: [
          '/static/template/drop-card/1.jpg',
          '/static/template/drop-card/2.jpg',
          '/static/template/drop-card/3.jpg'
        ] as string[],
31
        // 页码
32 33
        currentIndex:0 as number,
        $nodesMap:new Map<string, INode[]>()
DCloud_JSON's avatar
DCloud_JSON 已提交
34 35
      }
    },
36
    onReady() {
DCloud_JSON's avatar
DCloud_JSON 已提交
37 38
      uni.getSystemInfo({
        success: (e) => {
39 40 41 42
          // console.log('e',e);
          screenWidth = e.screenWidth;
          let height = e.screenHeight - 200 + 'px'
          for (var i = 0; i < 3; i++) {
43 44
            this.setINodeStyle('card',i,'height', height);
            this.setINodeStyle('card-img',i,'height', height);
45
          }
DCloud_JSON's avatar
DCloud_JSON 已提交
46
        }
47 48 49
      })
      this.initCardList()
    },
50 51 52 53 54 55 56 57 58
    computed: {
      movePercent() : number {
        return Math.abs(this.x) / (screenWidth/2*3)
      },
      likeOpacity() : number {
        return this.x < 0 ? 0 : this.movePercent * 100
      },
      dislikeOpacity() : number {
        return this.x > 0 ? 0 : this.movePercent * 100
59 60 61
      },
      topCardIndex():number{
        return 2 - Math.abs(this.currentIndex)%3
62
      }
DCloud_JSON's avatar
DCloud_JSON 已提交
63
    },
64
    methods: {
65 66
      // 工具方法,用于快速设置 INode 的 style
      setINodeStyle(refName:string,index:number,propertyName:string,propertyStyle:any):void{
67
        let nodes:INode[]|null = this.$nodesMap.get(refName)
68 69
        if(nodes == null){
          nodes = this.$refs.get(refName) as INode[]
70
          this.$nodesMap.set(refName,nodes)
71 72 73 74
        }else{
          // console.log('直接拿');
        }
        (nodes)[index].style.setProperty(propertyName,propertyStyle);
75 76 77 78 79 80 81 82 83 84
      },
      // 设置卡片样式(层级,大小,上边距)
      initCardList(){
        for (var i = 0; i < 3; i++) {
          let endIndex = (i + this.currentIndex)%3
          this.setINodeStyle('card',i,'margin-top', 100 - 30*endIndex+'px');
          this.setINodeStyle('card',i,'transform', 'scale('+(0.9+0.05*endIndex)+')')
          // console.log(0.9+0.05*endIndex,50 - 20*endIndex+'px');
          this.setINodeStyle('card',i,'z-index', endIndex)
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
85
      },
86
      moveCard() {
87
        for (var i = 0; i < 3; i++) {
88 89 90 91 92 93 94 95 96 97
          // 设置置顶卡片样式
          if(i === this.topCardIndex){
            this.setINodeStyle('card',this.topCardIndex,'transform', 'translateX('+this.x+'px) translateY('+this.y+'px) rotate('+this.x/-30+'deg) scale('+( 0.9+0.05*2 + movePercent/20 )+')')
            this.setINodeStyle('state-icon-like',this.topCardIndex,'opacity', x < 0 ? 0 : movePercent * 10)
            this.setINodeStyle('state-icon-dislike',this.topCardIndex,'opacity', x > 0 ? 0 : movePercent * 10)
          }else{
            let endIndex = (i + this.currentIndex)%3
            this.setINodeStyle('card',i,'transform', 'scale('+( 0.9+0.05*endIndex + movePercent*0.05 )+')')
            this.setINodeStyle('card',i,'margin-top', 100 - 30*endIndex - movePercent*30 +'px');
          }
98
        }
99
      },
100 101 102 103
      touchstart(e : TouchEvent) {
        // console.log('touchstart')
        if(floating){
          return // 浮动动画进行中
104
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
105
        sX = e.touches[0].screenX;
106 107
        sY = e.touches[0].screenY;
        this.x = 0
108 109 110
        this.y = 0
        
        touchstartAfter = true
DCloud_JSON's avatar
DCloud_JSON 已提交
111
      },
112 113 114 115 116 117 118 119 120
      touchmove(e : TouchEvent) {
        // console.log('touchmove')
        
        if(!touchstartAfter){
          return //
        }
        
        if(floating){
          return // 浮动动画进行中
121
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
122 123 124
        this.x += e.touches[0].screenX - sX;
        this.y += e.touches[0].screenY - sY;
        sX = e.touches[0].screenX;
125
        sY = e.touches[0].screenY;
126
        this.moveCard()
DCloud_JSON's avatar
DCloud_JSON 已提交
127
      },
128
      touchend() {
129 130 131 132 133 134
        // console.log('touchend')
        touchstartAfter = false
        if(floating){
          return // 浮动动画进行中
        }
        
135
        // console.log('touchend');
136
        floating = true
137

138 139 140 141 142 143 144 145
        // 设置释放之后飘走的方向 0回到坐标中心 1向右 2向左
        let k:number = 0;
        if (this.x > screenWidth / 6 ) {
          k = 1
        }else if(this.x < screenWidth * -1 / 6){
          k = -1
        }
        
146
        this.x = k * screenWidth * 1.5
147
        this.y = this.y * 3 * k * k
148

149
        // 设置动画时间
150 151 152 153 154
        let transitionDuration = 300;
        let floatCardIndex = this.topCardIndex
        this.setINodeStyle('card',floatCardIndex,'transitionProperty','transform');
        this.setINodeStyle('card',floatCardIndex,'transitionDuration',transitionDuration);
        // this.setINodeStyle('card',floatCardIndex,'transitionOrigin','bottom center');
155 156 157
        this.moveCard()
         // 移动结束
        setTimeout(()=>{
158 159 160
          // 动画速度设置为0(即:关闭动画)
          this.setINodeStyle('card',floatCardIndex,'transitionDuration',0);
          
161
          if(this.x != 0.0){
162
              // 飘动的卡片挪回中心
163 164
              this.setINodeStyle('card',floatCardIndex,'transform', 'translate(0,0) rotate(0) scale(0.9)')
              this.setINodeStyle('card',floatCardIndex,'z-index', -1)
165 166 167
              this.setINodeStyle('state-icon-like',floatCardIndex,'opacity', 0)
              this.setINodeStyle('state-icon-dislike',floatCardIndex,'opacity', 0)
              
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
              setTimeout(()=>{
                // 坐标归零
                this.x = 0
                this.y = 0
                
                // 动画改成marginTop,scale
                this.setINodeStyle('card',floatCardIndex,'transitionProperty','marginTop,scale');
                this.setINodeStyle('card',floatCardIndex,'transitionDuration',transitionDuration);
                // 切换卡片顺序
                this.currentIndex ++
                // 根据最新卡片顺序,设置层级大小样式
                this.initCardList()
                floating = false
              },0)
          }else{
            floating = false
184
          }
185
        },transitionDuration)
186
        
DCloud_JSON's avatar
DCloud_JSON 已提交
187 188 189 190 191 192 193 194 195 196 197
      }
    }
  }
</script>
<style>
  .root {
    flex: 1;
    position: relative;
  }

  .card {
198
    width: 700rpx;
DCloud_JSON's avatar
DCloud_JSON 已提交
199 200 201
    height: 750rpx;
    position: absolute;
    margin: 0 25rpx;
202
    margin-top: 50px;
DCloud_JSON's avatar
DCloud_JSON 已提交
203
    border-radius: 10px;
204 205
    color: #FFF;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
206 207
    background-color: #FFF;
    /* transform-origin:bottom; */
208
    transition:margin-top 10ms;
209
    transition-timing-function: ease-in;
DCloud_JSON's avatar
DCloud_JSON 已提交
210 211
  }
  
212 213 214 215 216 217 218 219 220 221 222
  .card-img {
    border-radius: 10px;
  }

  .state {
    top: 20rpx;
    left: 20rpx;
    width: 650rpx;
    padding: 4px;
    position: absolute;
    flex-direction: row;
223 224 225
    justify-content: space-between;
  }
  
226 227 228 229 230 231 232 233 234
  .state-icon {
    width: 30px;
    height: 30px;
    border: 1px solid #FFF;
    background-color: #FFF;
    padding: 3px;
    border-radius: 100px;
    box-shadow: 0 0 1px #EBEBEB;
    opacity: 0;
235 236
  }
  
DCloud_JSON's avatar
DCloud_JSON 已提交
237
</style>