HomeView.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <template>
  2. <div
  3. class="home"
  4. @mousedown="onMouseDown"
  5. @mousemove="onMouseMove"
  6. @mouseup="onMouseUp"
  7. @mouseleave="onMouseLeave"
  8. @wheel.passive="onWheel"
  9. @dragstart.prevent
  10. >
  11. <img
  12. class="landscape"
  13. src="@/assets/landscape.png"
  14. alt=""
  15. @dragstart.prevent
  16. >
  17. <div
  18. class="people-far"
  19. :style="{
  20. right: peopleFarPositionRight,
  21. }"
  22. >
  23. <img
  24. src="@/assets/people-far.png"
  25. alt=""
  26. @dragstart.prevent
  27. >
  28. </div>
  29. <div
  30. class="people-near"
  31. :style="{
  32. right: peopleNearPositionRight,
  33. }"
  34. >
  35. <img
  36. class="peopleNearSerialFrames"
  37. :class="peopleNearColorStatus"
  38. src="@/assets/people-near-serial-frame.png"
  39. alt=""
  40. @dragstart.prevent
  41. >
  42. <HotSpot
  43. class="hot-spot"
  44. @click="onClickPeopleNearHotSpot"
  45. />
  46. </div>
  47. <img
  48. class="introduce"
  49. :style="{
  50. left: introducePositionLeft,
  51. }"
  52. src="@/assets/introduce.png"
  53. alt=""
  54. @dragstart.prevent
  55. >
  56. </div>
  57. </template>
  58. <script>
  59. export default {
  60. name: 'HomeView',
  61. components: {
  62. },
  63. data() {
  64. return {
  65. landscapePositionRight: '-50%',
  66. peopleFarPositionRight: '0px',
  67. peopleNearPositionRight: '-30%',
  68. introducePositionLeft: '2%',
  69. translateLength: 0,
  70. isMouseDown: false,
  71. moveSpeed: 0,
  72. lastMoveEventTimeStamp: 0,
  73. lastAnimationTimeStamp: 0,
  74. animationFrameId: null,
  75. peopleNearColorStatus: 'no-color', // 'no-color', 'color'
  76. isPeopleNearColorChanging: false,
  77. }
  78. },
  79. watch: {
  80. translateLength: {
  81. handler(v) {
  82. if (v > 0) {
  83. v = 0
  84. this.translateLength = v
  85. this.moveSpeed = 0
  86. } else if (v < -window.innerWidth * 2) {
  87. v = -window.innerWidth * 2
  88. this.translateLength = v
  89. this.moveSpeed = 0
  90. }
  91. this.peopleFarPositionRight = `calc(0px - ${v * 0.2}px)`
  92. this.peopleNearPositionRight = `calc(-30% - ${v * 0.8}px)`
  93. this.introducePositionLeft = `calc(2% + ${v * 1}px)`
  94. }
  95. }
  96. },
  97. mounted() {
  98. this.animationFrameId = requestAnimationFrame(this.inertanceEffect)
  99. },
  100. unmounted() {
  101. cancelAnimationFrame(this.animationFrameId)
  102. },
  103. methods: {
  104. onMouseDown(e) {
  105. this.isMouseDown = true
  106. this.moveSpeed = 0
  107. this.lastMoveEventTimeStamp = 0
  108. this.lastAnimationTimeStamp = Date.now()
  109. },
  110. onMouseUp(e) {
  111. this.isMouseDown = false
  112. },
  113. onMouseLeave() {
  114. this.isMouseDown = false
  115. },
  116. onMouseMove(e) {
  117. if (this.isMouseDown) {
  118. if (this.lastMoveEventTimeStamp) {
  119. const currentMoveSpeed = e.movementX / (e.timeStamp - this.lastMoveEventTimeStamp)
  120. this.moveSpeed = this.moveSpeed * 0.9 + currentMoveSpeed * 0.1
  121. }
  122. this.lastMoveEventTimeStamp = e.timeStamp
  123. }
  124. },
  125. onWheel(e) {
  126. this.translateLength -= e.deltaY
  127. },
  128. inertanceEffect() {
  129. const timeStamp = Date.now()
  130. const timeElapsed = timeStamp - this.lastAnimationTimeStamp
  131. if (this.moveSpeed > 0) {
  132. this.moveSpeed -= 0.003 * timeElapsed
  133. if (this.moveSpeed < 0) {
  134. this.moveSpeed = 0
  135. }
  136. } else if (this.moveSpeed < 0) {
  137. this.moveSpeed += 0.003 * timeElapsed
  138. if (this.moveSpeed > 0) {
  139. this.moveSpeed = 0
  140. }
  141. }
  142. this.translateLength += this.moveSpeed * timeElapsed
  143. this.lastAnimationTimeStamp = timeStamp
  144. this.animationFrameId = requestAnimationFrame(this.inertanceEffect)
  145. },
  146. onClickPeopleNearHotSpot() {
  147. if (this.isPeopleNearColorChanging) {
  148. return
  149. } else {
  150. if (this.peopleNearColorStatus === 'no-color') {
  151. this.peopleNearColorStatus = 'color'
  152. } else {
  153. this.peopleNearColorStatus = 'no-color'
  154. }
  155. this.isPeopleNearColorChanging = true
  156. setTimeout(() => {
  157. this.isPeopleNearColorChanging = false
  158. }, 2500)
  159. }
  160. }
  161. }
  162. }
  163. </script>
  164. <style lang="less" scoped>
  165. .home {
  166. width: 100%;
  167. height: 100%;
  168. background-image: url(@/assets/background.jpg);
  169. background-repeat: repeat;
  170. background-size: contain;
  171. position: relative;
  172. overflow: hidden;
  173. .landscape {
  174. height: 30%;
  175. position: absolute;
  176. top: 0;
  177. right: 0;
  178. }
  179. .people-far {
  180. position: absolute;
  181. top: 20%;
  182. height: 60%;
  183. > img {
  184. height: 100%;
  185. }
  186. }
  187. .people-near {
  188. position: absolute;
  189. bottom: 0;
  190. width: 600px;
  191. height: 800px;
  192. transform: scale(calc(90vh / 800px));
  193. overflow: hidden;
  194. > .hot-spot {
  195. position: absolute;
  196. left: 50%;
  197. transform: translateX(-50%);
  198. top: 15%;
  199. }
  200. > .peopleNearSerialFrames {
  201. position: absolute;
  202. height: 100%;
  203. transition-property: left;
  204. transition-duration: 2.5s;
  205. transition-timing-function: steps(59, jump-end);
  206. &.no-color {
  207. left: 0;
  208. }
  209. &.color {
  210. left: calc(-100% * 59)
  211. }
  212. }
  213. }
  214. .introduce {
  215. position: absolute;
  216. top: 5%;
  217. }
  218. }
  219. </style>