VideoFeed.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <script>
  2. import { defineComponent } from 'vue'
  3. import Player from '@/components/Player.vue'
  4. import { config } from '@/main.js'
  5. import { animate, createSpring } from 'animejs'
  6. export default defineComponent({
  7. name: 'VideoFeed',
  8. data() {
  9. return {
  10. player1: null,
  11. player2: null,
  12. config,
  13. animating: false,
  14. feedIndex: 0,
  15. currentPlayer: "player1",
  16. stiffness: 550,
  17. damping: 15
  18. }
  19. },
  20. props: {
  21. feed: {
  22. type: Object,
  23. required: true
  24. }
  25. },
  26. methods: {
  27. scrollDown() {
  28. if(this.animating) return;
  29. if (this.feedIndex >= this.feed.length - 1) {
  30. console.log("Reached end of feed");
  31. this.animating = false;
  32. return;
  33. }
  34. this.animating = true;
  35. const screenHeight = window.innerHeight;
  36. const inactivePlayer = this.currentPlayer === "player1" ? ".player2" : ".player1";
  37. const activePlayer = this.currentPlayer === "player1" ? ".player1" : ".player2";
  38. const nextIndex = this.feedIndex + 1; // calculate this early!
  39. // Move the inactive player down
  40. animate(inactivePlayer, {
  41. translateY: screenHeight,
  42. duration: 0
  43. });
  44. if (this.currentPlayer === "player1") {
  45. this.player2 = this.feed[nextIndex];
  46. } else {
  47. this.player1 = this.feed[nextIndex];
  48. }
  49. // animate players
  50. animate(activePlayer, {
  51. translateY: [0, -screenHeight],
  52. duration: 500,
  53. ease: createSpring({stiffness: this.stiffness, damping: this.damping})
  54. });
  55. animate(inactivePlayer, {
  56. translateY: [screenHeight, 0],
  57. duration: 500,
  58. ease: createSpring({stiffness: this.stiffness, damping: this.damping})
  59. }).then(() => {
  60. const nextPlayer = this.currentPlayer === "player1" ? "player2" : "player1";
  61. this.feedIndex = nextIndex;
  62. this.currentPlayer = nextPlayer;
  63. this.animating = false;
  64. });
  65. },
  66. scrollUp() {
  67. if(this.animating) return;
  68. if (this.feedIndex <= 0) {
  69. console.log("Reached beginning of feed");
  70. this.animating = false;
  71. return;
  72. }
  73. this.animating = true;
  74. const screenHeight = window.innerHeight;
  75. const inactivePlayer = this.currentPlayer === "player1" ? ".player2" : ".player1";
  76. const activePlayer = this.currentPlayer === "player1" ? ".player1" : ".player2";
  77. const nextIndex = this.feedIndex - 1; // calculate this early!
  78. // Move the inactive player up
  79. animate(inactivePlayer, {
  80. translateY: -screenHeight,
  81. duration: 0
  82. });
  83. if (this.currentPlayer === "player1") {
  84. this.player2 = this.feed[nextIndex];
  85. } else {
  86. this.player1 = this.feed[nextIndex];
  87. }
  88. // animate players
  89. animate(activePlayer, {
  90. translateY: [0, screenHeight],
  91. duration: 500,
  92. ease: createSpring({stiffness: this.stiffness, damping: this.damping})
  93. });
  94. animate(inactivePlayer, {
  95. translateY: [-screenHeight, 0],
  96. duration: 500,
  97. ease: createSpring({stiffness: this.stiffness, damping: this.damping})
  98. }).then(() => {
  99. const nextPlayer = this.currentPlayer === "player1" ? "player2" : "player1";
  100. this.feedIndex = nextIndex;
  101. this.currentPlayer = nextPlayer;
  102. this.animating = false;
  103. });
  104. },
  105. handleScroll(event) {
  106. if(this.animating) return;
  107. if(event.deltaY > 0) {
  108. this.scrollDown();
  109. } else {
  110. this.scrollUp();
  111. }
  112. },
  113. },
  114. created () {
  115. // initial setup for players
  116. this.player1 = this.feed[this.feedIndex];
  117. this.player2 = this.feed[this.feedIndex + 1];
  118. document.addEventListener("DOMContentLoaded", () => {
  119. animate(".player2", {
  120. translateY: window.innerHeight,
  121. duration: 1
  122. })
  123. })
  124. document.addEventListener("wheel", this.handleScroll);
  125. },
  126. components: { Player },
  127. })
  128. </script>
  129. <template>
  130. <div id="player-container">
  131. <Player
  132. class-name="player1 player-wrapper"
  133. :video="player1?.id ?? 1"
  134. :key="player1?.id ?? 1"
  135. :information="{
  136. title: player1?.title ?? '',
  137. description: player1?.description ?? '',
  138. likes: player1?.likes ?? 13242,
  139. dislikes: player1?.dislikes ?? 13242,
  140. comments: player1?.comments ?? 13242,
  141. shares: player1?.shares ?? 13242,
  142. author: player1?.author?.username ?? 'john clapper',
  143. authorAvatar: `${config.serverURL}/account/${player1?.author?.id ?? 1}/picture`,
  144. }"
  145. />
  146. <Player
  147. class-name="player2 player-wrapper"
  148. :video="player2?.id ?? 1"
  149. :key="player2?.id ?? 1"
  150. :information="{
  151. title: player2?.title ?? '',
  152. description: player2?.description ?? '',
  153. likes: player2?.likes ?? 13242,
  154. dislikes: player2?.dislikes ?? 13242,
  155. comments: player2?.comments ?? 13242,
  156. shares: player2?.shares ?? 13242,
  157. author: player2?.author?.username ?? 'johnclapper',
  158. authorAvatar: `${config.serverURL}/account/${player2?.author?.id ?? 1}/picture`,
  159. }"
  160. />
  161. </div>
  162. </template>
  163. <style scoped>
  164. .player-wrapper {
  165. position: absolute;
  166. width: 100%;
  167. height: 100vh;
  168. top: 0;
  169. left: 0;
  170. }
  171. .player1 {
  172. position: absolute;
  173. }
  174. .player2 {
  175. position: absolute;
  176. }
  177. </style>