dgex-tantan.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <template>
  2. <view class="tantan-slide" :style="{
  3. width: winWidth + 'px',
  4. height: winHeigh + 'px',
  5. }">
  6. <view @touchstart.capture="touchStart($event,currentIndex)"
  7. @touchmove.stop.capture="touchMove($event,currentIndex)"
  8. @touchend.capture="touchEnd(currentIndex)" class="tantan-slide-box">
  9. <template v-for="(item, index) in list">
  10. <view class="tantan-slide-box-item"
  11. :key="index"
  12. v-if="currentIndex + visible >= index"
  13. @click.stop="clickImage"
  14. :style="[cardTransform(item, index), {
  15. 'zIndex': list.length - index,
  16. 'opacity': currentIndex + visible - 1 >= index && currentIndex <= index ? 1 : 0,
  17. 'transform': 'rotate(' + ((item.x || 0) / 30 ) + 'deg) translate3d(' + (item.x || 0) + 'px,' + (item.y || 0) + 'px, '+ 0 +'px)'
  18. }]">
  19. <!-- 加载图片会闪屏 双if避免 -->
  20. <template v-if="currentIndex + visible >= index && currentIndex <= index">
  21. <view class="tantan-slide-img-box" :style="{height: winHeigh + 'px'}">
  22. <image class="tantan-slide-img" :class="{'overturn-shake':overturnType===1,'overturn-back-shake':overturnType===2}" :style="{height: winHeigh + 'px'}" mode="aspectFill" :src="item.image" ></image>
  23. <view class="slide-img-click">
  24. <view class="slide-img-click-item" @click.stop="setImgKey(item,0)"></view>
  25. <view class="slide-img-click-item" @click.stop="setImgKey(item,1)"></view>
  26. </view>
  27. </view>
  28. <view v-if="index === currentIndex">
  29. <view class="tantan-slide-box-icon tantan-slide-box-dislike"
  30. :style="{
  31. opacity: dislike * 1.5,
  32. transform: 'scale('+ (dislike + 1 > 2 ? 2 : dislike + 1 ) +')',
  33. }">
  34. <image style="width: 30rpx;height: 30rpx;" src="/static/dgex-tantan/close.png"></image>
  35. </view>
  36. <view class="tantan-slide-box-icon tantan-slide-box-love" :style="{
  37. opacity: love * 1.5,
  38. transform: 'scale('+ (love + 1 > 2 ? 2 : love + 1 ) +')',
  39. }">
  40. <image style="width: 30rpx;height: 30rpx;" src="/static/dgex-tantan/like.png"></image>
  41. </view>
  42. </view>
  43. </template>
  44. </view>
  45. </template>
  46. </view>
  47. </view>
  48. </template>
  49. <script>
  50. import tools from "@/service/tools";
  51. export default {
  52. name: "slide",
  53. props: {
  54. list: {
  55. type: Array,
  56. default: () => []
  57. }
  58. },
  59. data() {
  60. return {
  61. winWidth: 0,
  62. winHeigh: 0,
  63. /*记录x y轴*/
  64. x: {
  65. start: 0,
  66. move: 0,
  67. end: 0
  68. },
  69. y: {
  70. start: 0,
  71. move: 0,
  72. end: 0
  73. },
  74. visible: 3,
  75. /*下标*/
  76. currentIndex: 0,
  77. /*滑动*/
  78. swipering: false,
  79. /*滑动中*/
  80. slideing: false,
  81. love: 0,
  82. dislike: 0,
  83. imgKey:0,
  84. overturnType:0
  85. }
  86. },
  87. watch:{
  88. 'overturnType':function (){
  89. console.log('this.overturnType:'+this.overturnType)
  90. if(this.overturnType===1){
  91. tools.vibrate()
  92. }
  93. }
  94. },
  95. mounted() {
  96. const res = uni.getSystemInfoSync()
  97. console.log(res)
  98. this.winWidth = res.windowWidth
  99. this.winHeigh = res.windowHeight-46
  100. },
  101. methods: {
  102. setImgKey(item, type){
  103. if( this.overturnType<=0){
  104. let imgNum=item.images.length-1
  105. if(type===0){
  106. if(this.imgKey<=0){
  107. this.setOverturnTwo()
  108. }else {
  109. --this.imgKey
  110. this.setOverturnImg(item)
  111. }
  112. }else {
  113. if(this.imgKey>=imgNum){
  114. this.setOverturnTwo()
  115. }else {
  116. ++this.imgKey
  117. this.setOverturnImg(item)
  118. }
  119. }
  120. }
  121. },
  122. setOverturnImg(item){
  123. // tools.success('one')
  124. // return;
  125. this.overturnType=1;
  126. setTimeout(()=>{
  127. item.image=item.images[this.imgKey]
  128. this.overturnType=2;
  129. setTimeout(()=>{
  130. this.overturnType=0;
  131. },80)
  132. },80)
  133. },
  134. setOverturnTwo(){
  135. // tools.error('two')
  136. // return;
  137. this.overturnType=1;
  138. let overturnNum=1
  139. let overturnServe=setInterval(()=>{
  140. ++overturnNum
  141. if(overturnNum>4){
  142. this.overturnType=0;
  143. clearInterval(overturnServe)
  144. }else {
  145. this.overturnType=(overturnNum%2===1)?1:2
  146. }
  147. },80)
  148. },
  149. cardTransform(item, index) {
  150. let css = {};
  151. if (index === this.currentIndex) {
  152. if (this.slideing) {
  153. css["transitionDuration"] = `${!this.swipering ? 1000 : 0}ms`;
  154. } else {
  155. css["transitionDuration"] = `${!this.swipering ? 300 : 0}ms`;
  156. }
  157. }
  158. return css
  159. },
  160. touchStart(e, index) {
  161. if (this.slideing) return;
  162. if (typeof this.list[index].x === 'undefined' && typeof this.list[index].y === 'undefined') {
  163. this.$set(this.list[index], 'y', 0)
  164. this.$set(this.list[index], 'x', 0)
  165. }
  166. this.swipering = true;
  167. this.x.start = e.touches[0].pageX;
  168. this.y.start = e.touches[0].pageY;
  169. },
  170. touchMove(e, index) {
  171. if (this.slideing) return
  172. // 滑动状态/最后一个就不滑动
  173. if (this.list.length == index + 1) {
  174. return;
  175. }
  176. this.x.move = e.touches[0].pageX;
  177. this.y.move = e.touches[0].pageY;
  178. this.list[index].x = this.x.move - this.x.start
  179. this.list[index].y = this.y.move - this.y.start
  180. if (Number.parseInt(this.list[index].x) > 0) {
  181. this.love = Number.parseInt(this.list[index].x) / (100 * 2)
  182. } else {
  183. this.dislike = Math.abs(Number.parseInt(this.list[index].x) / (100 * 2))
  184. }
  185. },
  186. touchEnd(index) {
  187. if (this.slideing) return
  188. this.swipering = false;
  189. if (this.list.length == index + 1) {
  190. return;
  191. }
  192. if (
  193. this.list[index].x > 0 &&
  194. this.list[index].x > this.winWidth / 2 - this.winWidth / 5
  195. ) {
  196. this.touchEndNext(index);
  197. } else if (
  198. this.list[index].x < 0 &&
  199. this.list[index].x < -this.winWidth / 2 + this.winWidth / 5
  200. ) {
  201. this.touchEndNext(index);
  202. } else {
  203. this.list[index].x = 0;
  204. this.list[index].y = 0;
  205. this.slideing = false;
  206. this.love = 0;
  207. this.dislike = 0;
  208. }
  209. },
  210. touchEndNext(index) {
  211. this.slideing = true;
  212. this.list[index].x = this.list[index].x * 5;
  213. this.list[index].y = this.list[index].y * 5;
  214. this.touchEndDone()
  215. },
  216. touchEndDone() {
  217. return new Promise((resolve) => {
  218. setTimeout(() => {
  219. this.slideing = false
  220. this.$emit('onChange', {
  221. currentIndex: this.currentIndex,
  222. currentItem: this.list[this.currentIndex],
  223. type: this.love !== 0 ? 'love' : 'dislike'
  224. })
  225. this.currentIndex++
  226. this.x.move = 0
  227. this.y.move = 0
  228. this.slideing = false
  229. this.btnClickType = false
  230. this.love = 0
  231. this.dislike = 0
  232. resolve()
  233. }, 300);
  234. })
  235. },
  236. footerBtnClick(type) {
  237. if (this.btnClickType) {
  238. return
  239. }
  240. this.btnClickType = true
  241. let w = 0
  242. if (type === 'love') {
  243. w = this.winWidth * 1.5
  244. this.love = 1
  245. } else if (type === 'dislike') {
  246. w = -this.winWidth * 1.5
  247. this.dislike = 1
  248. }
  249. this.$set(this.list[this.currentIndex], 'x', w)
  250. this.touchEndDone()
  251. },
  252. clickImage() {
  253. this.$emit('onClickImage', {
  254. type: 'click',
  255. currentIndex: this.currentIndex,
  256. currentItem: this.list[this.currentIndex],
  257. })
  258. }
  259. }
  260. };
  261. </script>
  262. <style lang="scss">
  263. .tantan-slide {
  264. width: 100%;
  265. height: 100%;
  266. display: flex;
  267. justify-content: center;
  268. align-items: center;
  269. overflow: hidden;
  270. }
  271. .tantan-slide-box {
  272. position: relative;
  273. width: calc(100vw - 32rpx);
  274. height: 100%;
  275. perspective: 2100rpx;
  276. perspective-origin: 50% -30%;
  277. transform-style: preserve-3d;
  278. margin: auto;
  279. }
  280. .tantan-slide-box-item {
  281. transform-style: preserve-3d;
  282. display: flex;
  283. width: 100%;
  284. height: 100%;
  285. border-radius: 24rpx;
  286. position: absolute;
  287. opacity: 0;
  288. transform: translate3d(0px, 0px, 0px) rotate(0deg);
  289. transition: 300ms;
  290. color: #fff;
  291. }
  292. .tantan-slide-box-icon {
  293. position: absolute;
  294. width: 70rpx;
  295. height: 70rpx;
  296. top: 45rpx;
  297. border-radius: 100%;
  298. background-color: #fff;
  299. z-index: 1;
  300. opacity: 0;
  301. transition: 100ms;
  302. display: flex;
  303. align-items: center;
  304. justify-content: center;
  305. }
  306. .tantan-slide-box-love {
  307. left: 50rpx;
  308. }
  309. .tantan-slide-box-dislike {
  310. right: 50rpx;
  311. }
  312. .tantan-slide-img-box {
  313. position: relative;
  314. will-change: transform;
  315. width: 100%;
  316. height: 100%;
  317. border-radius: 40rpx;
  318. background-repeat: no-repeat;//不平铺
  319. background-position: center center;//居中
  320. background-size: cover;//随容器大小
  321. .tantan-slide-img{
  322. z-index: 10;
  323. border-radius: 40rpx;
  324. width: 100%;
  325. height: 100%;
  326. position: absolute;
  327. left: 0;
  328. top: 0;
  329. }
  330. .slide-img-click{
  331. z-index: 100;
  332. width: 100%;
  333. height: 100%;
  334. display: flex;
  335. justify-content: space-between;
  336. .slide-img-click-item{
  337. z-index: 100;
  338. width: 50%;
  339. height: 100%;
  340. }
  341. }
  342. }
  343. </style>