dgex-tantan.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. <image class="tantan-slide-img" mode="aspectFill" :src="item.image" ></image>
  22. <view v-if="index === currentIndex">
  23. <view class="tantan-slide-box-icon tantan-slide-box-dislike"
  24. :style="{
  25. opacity: dislike * 1.5,
  26. transform: 'scale('+ (dislike + 1 > 2 ? 2 : dislike + 1 ) +')',
  27. }">
  28. <image style="width: 30rpx;height: 30rpx;" src="/static/dgex-tantan/close.png"></image>
  29. </view>
  30. <view class="tantan-slide-box-icon tantan-slide-box-love" :style="{
  31. opacity: love * 1.5,
  32. transform: 'scale('+ (love + 1 > 2 ? 2 : love + 1 ) +')',
  33. }">
  34. <image style="width: 30rpx;height: 30rpx;" src="/static/dgex-tantan/like.png"></image>
  35. </view>
  36. </view>
  37. </template>
  38. </view>
  39. </template>
  40. </view>
  41. </view>
  42. </template>
  43. <script>
  44. export default {
  45. name: "slide",
  46. props: {
  47. list: {
  48. type: Array,
  49. default: () => []
  50. }
  51. },
  52. data() {
  53. return {
  54. winWidth: 0,
  55. winHeigh: 0,
  56. /*记录x y轴*/
  57. x: {
  58. start: 0,
  59. move: 0,
  60. end: 0
  61. },
  62. y: {
  63. start: 0,
  64. move: 0,
  65. end: 0
  66. },
  67. visible: 3,
  68. /*下标*/
  69. currentIndex: 0,
  70. /*滑动*/
  71. swipering: false,
  72. /*滑动中*/
  73. slideing: false,
  74. love: 0,
  75. dislike: 0,
  76. }
  77. },
  78. mounted() {
  79. const res = uni.getSystemInfoSync()
  80. console.log(res)
  81. this.winWidth = res.windowWidth
  82. this.winHeigh = res.windowHeight-46
  83. },
  84. methods: {
  85. cardTransform(item, index) {
  86. let css = {};
  87. if (index === this.currentIndex) {
  88. if (this.slideing) {
  89. css["transitionDuration"] = `${!this.swipering ? 1000 : 0}ms`;
  90. } else {
  91. css["transitionDuration"] = `${!this.swipering ? 300 : 0}ms`;
  92. }
  93. }
  94. return css
  95. },
  96. touchStart(e, index) {
  97. if (this.slideing) return;
  98. if (typeof this.list[index].x === 'undefined' && typeof this.list[index].y === 'undefined') {
  99. this.$set(this.list[index], 'y', 0)
  100. this.$set(this.list[index], 'x', 0)
  101. }
  102. this.swipering = true;
  103. this.x.start = e.touches[0].pageX;
  104. this.y.start = e.touches[0].pageY;
  105. },
  106. touchMove(e, index) {
  107. if (this.slideing) return
  108. // 滑动状态/最后一个就不滑动
  109. if (this.list.length == index + 1) {
  110. return;
  111. }
  112. this.x.move = e.touches[0].pageX;
  113. this.y.move = e.touches[0].pageY;
  114. this.list[index].x = this.x.move - this.x.start
  115. this.list[index].y = this.y.move - this.y.start
  116. if (Number.parseInt(this.list[index].x) > 0) {
  117. this.love = Number.parseInt(this.list[index].x) / (100 * 2)
  118. } else {
  119. this.dislike = Math.abs(Number.parseInt(this.list[index].x) / (100 * 2))
  120. }
  121. },
  122. touchEnd(index) {
  123. if (this.slideing) return
  124. this.swipering = false;
  125. if (this.list.length == index + 1) {
  126. return;
  127. }
  128. if (
  129. this.list[index].x > 0 &&
  130. this.list[index].x > this.winWidth / 2 - this.winWidth / 5
  131. ) {
  132. this.touchEndNext(index);
  133. } else if (
  134. this.list[index].x < 0 &&
  135. this.list[index].x < -this.winWidth / 2 + this.winWidth / 5
  136. ) {
  137. this.touchEndNext(index);
  138. } else {
  139. this.list[index].x = 0;
  140. this.list[index].y = 0;
  141. this.slideing = false;
  142. this.love = 0;
  143. this.dislike = 0;
  144. }
  145. },
  146. touchEndNext(index) {
  147. this.slideing = true;
  148. this.list[index].x = this.list[index].x * 5;
  149. this.list[index].y = this.list[index].y * 5;
  150. this.touchEndDone()
  151. },
  152. touchEndDone() {
  153. return new Promise((resolve) => {
  154. setTimeout(() => {
  155. this.slideing = false
  156. this.$emit('onChange', {
  157. currentIndex: this.currentIndex,
  158. currentItem: this.list[this.currentIndex],
  159. type: this.love !== 0 ? 'love' : 'dislike'
  160. })
  161. this.currentIndex++
  162. this.x.move = 0
  163. this.y.move = 0
  164. this.slideing = false
  165. this.btnClickType = false
  166. this.love = 0
  167. this.dislike = 0
  168. resolve()
  169. }, 300);
  170. })
  171. },
  172. footerBtnClick(type) {
  173. if (this.btnClickType) {
  174. return
  175. }
  176. this.btnClickType = true
  177. let w = 0
  178. if (type === 'love') {
  179. w = this.winWidth * 1.5
  180. this.love = 1
  181. } else if (type === 'dislike') {
  182. w = -this.winWidth * 1.5
  183. this.dislike = 1
  184. }
  185. this.$set(this.list[this.currentIndex], 'x', w)
  186. this.touchEndDone()
  187. },
  188. clickImage() {
  189. this.$emit('onClickImage', {
  190. type: 'click',
  191. currentIndex: this.currentIndex,
  192. currentItem: this.list[this.currentIndex],
  193. })
  194. }
  195. }
  196. };
  197. </script>
  198. <style>
  199. /* fa547c f8ba35 */
  200. .tantan-slide {
  201. /* background-color: #2196f3; */
  202. width: 100%;
  203. height: 100%;
  204. display: flex;
  205. justify-content: center;
  206. align-items: center;
  207. overflow: hidden;
  208. }
  209. .tantan-slide-box {
  210. position: relative;
  211. width: calc(100vw - 32rpx);
  212. height: 100%;
  213. perspective: 2100rpx;
  214. perspective-origin: 50% -30%;
  215. transform-style: preserve-3d;
  216. margin: auto;
  217. }
  218. .tantan-slide-box-item {
  219. transform-style: preserve-3d;
  220. display: flex;
  221. width: 100%;
  222. height: 100%;
  223. border-radius: 24rpx;
  224. position: absolute;
  225. opacity: 0;
  226. transform: translate3d(0px, 0px, 0px) rotate(0deg);
  227. transition: 300ms;
  228. color: #fff;
  229. /* display: none; */
  230. }
  231. .tantan-slide-box-item.on {
  232. /* opacity: 1; */
  233. display: block;
  234. }
  235. .tantan-slide-box-item-bg {
  236. height: 380rpx;
  237. background-image: linear-gradient(to bottom, transparent, #000000 70%);
  238. position: absolute;
  239. left: 0;
  240. right: 0;
  241. bottom: 0;
  242. margin: auto;
  243. z-index: 1;
  244. border-bottom-right-radius: 40rpx;
  245. border-bottom-left-radius: 40rpx;
  246. }
  247. .tantan-slide-box-icon {
  248. position: absolute;
  249. width: 70rpx;
  250. height: 70rpx;
  251. top: 45rpx;
  252. border-radius: 100%;
  253. background-color: #fff;
  254. z-index: 1;
  255. opacity: 0;
  256. transition: 100ms;
  257. display: flex;
  258. align-items: center;
  259. justify-content: center;
  260. }
  261. .tantan-slide-box-love {
  262. left: 50rpx;
  263. }
  264. .tantan-slide-box-dislike {
  265. right: 50rpx;
  266. }
  267. .tantan-slide-img {
  268. position: relative;
  269. will-change: transform;
  270. width: 100%;
  271. height: 100%;
  272. border-radius: 40rpx;
  273. }
  274. .tantan-slide-img.on{
  275. transform: scale(1);
  276. width: 50rpx;
  277. height: 50rpx;
  278. }
  279. .tantan-slide-box-info{
  280. padding: 0 32rpx;
  281. color: #ffffff;
  282. }
  283. .tantan-slide-box-info .title{
  284. font-size: 64rpx;
  285. line-height: 1.2;
  286. text-shadow: 0 0 10rpx rgb(0, 0, 0, 0.5);
  287. }
  288. .tantan-slide-box-info .desc{
  289. font-size: 32rpx;
  290. line-height: 1.2;
  291. margin-top: 30rpx;
  292. text-shadow: 0 0 10rpx rgb(0, 0, 0, 0.5);
  293. }
  294. .tantan-slide-box-info .tags{
  295. margin-top: 24rpx;
  296. }
  297. .tantan-slide-box-info .tag{
  298. height: 48rpx;
  299. font-size: 24rpx;
  300. padding: 0 16rpx;
  301. line-height: 48rpx;
  302. background-color: rgba(255, 255,255,0.3);
  303. border-radius: 10rpx;
  304. }
  305. </style>