card.uvue 7.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
<template>
    <view class="card" ref="card" @touchstart="touchstart($event as TouchEvent)"
      @touchmove="touchmove($event as TouchEvent)" @touchend="touchend" @touchcancel="touchend">
      <image class="card-img" ref="card-img" :src="img"></image>
      <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>
          <!-- cardIndex:{{cardIndex}} -->
      </view>
    </view>
</template>
<script>
  let sX : number = 0,
    sY : number = 0,
    screenWidth : number = 1,
    screenHeight : number = 1,
    floating : boolean = false,
    touchstartAfter : boolean = false;
  export default {
    data() {
      return {
DCloud_JSON's avatar
DCloud_JSON 已提交
24
        $elementMap:new Map<string, Element>(),
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
        x: 0 as number,
        y: 0 as number,
        // 飘走的卡片计数
        floatCount:0 as number
      }
    },
    props: {
      img: {
        type: String,
        default: "/static/template/drop-card/1.jpg"
      },
      cardIndex:{
        type:Number,
        default:0
      }
    },
    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
      }
    },
    mounted() {
      uni.getSystemInfo({
        success: (e) => {
          screenWidth = e.screenWidth;
          screenHeight = e.screenHeight;
        }
      })
59

DCloud_JSON's avatar
DCloud_JSON 已提交
60
      // TODO 需要延迟设置才能生效
61
      setTimeout(()=>{
DCloud_JSON's avatar
DCloud_JSON 已提交
62 63
        this.setElementStyle('card','height', screenHeight * 0.7 + 'px');
        this.setElementStyle('card-img','height', screenHeight * 0.7 + 'px');
64
        this.initCardStyle()
DCloud_JSON's avatar
DCloud_JSON 已提交
65
      },200)
66

67 68 69 70
      uni.$on('uni-drop-card-float',()=>{
        this.floatCount ++
        this.initCardStyle()
      })
71

72 73 74 75 76
    },
    methods: {
      initCardStyle(){
        let _index = (this.cardIndex + this.floatCount)%3
        // console.log('~~~~~~_index:'+_index + ' cardIndex:'+this.cardIndex+' floatCount:'+this.floatCount);
DCloud_JSON's avatar
DCloud_JSON 已提交
77 78 79
        this.setElementStyle('card','z-index', _index)
        this.setElementStyle('card','margin-top', screenHeight * 0.15 - 30 * _index + 'px');
        this.setElementStyle('card','transform', 'scale('+(0.9 + 0.05 * _index)+')')
80
      },
DCloud_JSON's avatar
DCloud_JSON 已提交
81
      // 工具方法,用于快速设置 Element 的 style
雪洛's avatar
雪洛 已提交
82 83 84
      setElementStyle(refName:string,propertyName : string, propertyStyle : any) : void {
        const elementMap = this.$data['$elementMap'] as Map<string, Element>
        let element : Element | null = elementMap[refName]
DCloud_JSON's avatar
DCloud_JSON 已提交
85
        if(element == null){
DCloud-WZF's avatar
DCloud-WZF 已提交
86
          element = this.$refs[refName] as Element;
雪洛's avatar
雪洛 已提交
87
          elementMap[refName] = element
88 89 90
        }else{
          // console.log('直接拿');
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
91
        element?.style?.setProperty(propertyName, propertyStyle);
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
      },
      touchstart(e : TouchEvent) {
        // console.log('touchstart')
        if (floating) {
          return // 浮动动画进行中
        }
        sX = e.touches[0].screenX;
        sY = e.touches[0].screenY;
        this.x = 0
        this.y = 0

        touchstartAfter = true
      },
      touchmove(e : TouchEvent) {
        // console.log('touchmove')
        if (!touchstartAfter || floating) {
          return // floating:浮动动画进行中
        }
        this.x += e.touches[0].screenX - sX;
        this.y += e.touches[0].screenY - sY;
        sX = e.touches[0].screenX;
        sY = e.touches[0].screenY;
        this.moveCard()
      },
      touchend() {
        // console.log('touchend')
        touchstartAfter = false
        if(floating){
          return // 浮动动画进行中
        }
        floating = true
123

124 125 126 127 128 129 130
        // 设置释放之后飘走的方向 0回到坐标中心 1向右 2向左
        let k:number = 0;
        if (this.x > screenWidth / 10 ) {
          k = 1
        }else if(this.x < screenWidth * -1 / 10){
          k = -1
        }
131 132

        function cardTo(x:number,y:number,callback: () => void,speed:number = 10){
133
          let interval:number = 0
134
          let acceleration:number = 1
135
          interval = setInterval(()=>{
136
            // 加速度
137 138
            acceleration += 0.2

139
            const dx = x - this.x
140 141 142 143
            if(Math.abs(dx) < 1){
              this.x = x
            }else{
              this.x += dx/speed*acceleration
144
            }
145

146
            const dy = y - this.y
147 148 149 150
            if(Math.abs(dy) < 1){
              this.y = y
            }else{
              this.y += dy/speed*acceleration
151
            }
152

153
            this.moveCard()
154
            if( this.x == x && this.y == y){
155
              clearInterval(interval)
156
              callback()
157
            }
158 159
          },16)
        }
160

161 162 163
        if(k.toInt() != 0){
          cardTo(k * screenWidth * 1.3, this.y * 3,()=>{
            //  状态图标变回透明
DCloud_JSON's avatar
DCloud_JSON 已提交
164 165
            this.setElementStyle("state-icon-like",'opacity', 0)
            this.setElementStyle("state-icon-dislike",'opacity', 0)
166

167
            // 设置为透明,防止飘回时因为 margin-top 太高,露出来
DCloud_JSON's avatar
DCloud_JSON 已提交
168
            this.setElementStyle("card",'opacity', 0)
169
            setTimeout(()=>{
DCloud_JSON's avatar
DCloud_JSON 已提交
170
              this.setElementStyle("card",'opacity', 1)
171
            },300)
172

173
            // 执行卡片飘动后事件,注意uni.$emit是全局事件。其他卡片也会执行
174
            uni.$emit('uni-drop-card-float',null)
175 176
            floating = false
          },8)
177
        }else{
178 179 180 181 182 183 184 185 186 187
          const _x:number = this.x
          const _y:number = this.y
          cardTo( (_x*-0.05).toInt() , (_y*-0.05).toInt() ,()=>{
            cardTo(0,0,()=>{
             console.log('bounce')
             floating = false
            },30)
          })
        }
      },
188
      moveCard() {
DCloud_JSON's avatar
DCloud_JSON 已提交
189
        this.setElementStyle("card",
190
          'transform',
DCloud_JSON's avatar
DCloud_JSON 已提交
191
          `translate(${this.x}px,${this.y}px) rotate(${this.x/-30}deg) scale(1)`
192
        )
DCloud_JSON's avatar
DCloud_JSON 已提交
193 194
        this.setElementStyle("state-icon-like",'opacity', this.x < 0 ? 0 : this.movePercent * 10)
        this.setElementStyle("state-icon-dislike",'opacity', this.x > 0 ? 0 : this.movePercent * 10)
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
      }
    }
  }
</script>

<style>
  .card {
    width: 700rpx;
    height: 750rpx;
    position: absolute;
    top: 0;
    left: 0;
    margin: 0 25rpx;
    margin-top: 50px;
    border-radius: 10px;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
    background-color: #FFF;
DCloud_JSON's avatar
DCloud_JSON 已提交
212
    transition: margin-top 300ms;
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
    transition-timing-function: ease-in;
  }

  .card-img {
    width: 700rpx;
    height: 750rpx;
    border-radius: 10px;
  }

  .state {
    top: 20rpx;
    left: 20rpx;
    width: 650rpx;
    padding: 4px;
    position: absolute;
    flex-direction: row;
    justify-content: space-between;
  }

  .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;
  }
242
</style>