滚动条控制播放的canvas逐帧动画

业务需求滚动条滚动播放视频内容,最后想到用canvas逐帧动画来处理。记录下最终效果。
  1 <template>
  2   <div class="home">
  3     <div class="canvas">
  4       <canvas ref="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
  5     </div>
  6   </div>
  7 </template>
  8 
  9 <script>
 10 import { debounce, throttle } from '@/utils'
 11 
 12 export default {
 13   name: 'App',
 14   data() {
 15     return {
 16       $_resizeCanvas: null,
 17       ctx: null,
 18       canvasWidth: 0,
 19       canvasHeight: 0,
 20       sources: [],
 21       count: 0,
 22       imgIndex: 0,
 23       top: 0,
 24       flag: false,
 25     }
 26   },
 27 
 28   created() {
 29     this.loadImages()
 30   },
 31   mounted() {
 32     const _this = this
 33     if (!_this.$_resizeCanvas) {
 34       _this.initListener()
 35     }
 36     _this.$nextTick(() => {
 37       _this.ctx = _this.$refs.canvas.getContext('2d')
 38     })
 39   },
 40   beforeDestroy() {
 41     this.$_resizeCanvas = null
 42     window.removeEventListener('resize', this.$_resizeHandler)
 43     window.removeEventListener('scroll', this.scrollToTop)
 44   },
 45   methods: {
 46     initListener() {
 47       this.setCanvasDom()
 48       this.$_resizeCanvas = debounce(this.setCanvasDom, 200)
 49       window.addEventListener('resize', this.$_resizeCanvas)
 50 
 51       window.addEventListener('scroll', this.scrollToTop)
 52     },
 53     setCanvasDom() {
 54       console.log(this.$refs.canvas)
 55       const w = document.body.clientWidth
 56       const h = document.body.clientHeight
 57       if (w > h * 1.77) {
 58         this.canvasWidth = w
 59         this.canvasHeight = Math.floor(w / 1.77)
 60       } else {
 61         this.canvasWidth = Math.floor(h * 1.77)
 62         this.canvasHeight = h
 63       }
 64     },
 65     loadImages() {
 66       const images = []
 67       for (let i = 0; i <= 209; i++) {
 68         images[i] = new Image()
 69         let n = i < 100 ? (i < 10 ? `00` : `0`) : ``
 70         images[i].src = `/img/${n}${i}.webp`
 71         images[i].onload = () => {
 72           this.count++
 73           if (i === 0) {
 74             this.renderImg()
 75           }
 76         }
 77         this.sources[i] = images[i]
 78       }
 79     },
 80     renderImg() {
 81       const _self = this
 82       if (_self.sources[_self.imgIndex]) {
 83         _self.ctx.clearRect(0, 0, _self.canvasWidth, _self.canvasHeight)
 84         _self.ctx.drawImage(_self.sources[_self.imgIndex], 0, 0, _self.canvasWidth, _self.canvasHeight)
 85       }
 86     },
 87     scrollToTop() {
 88       const _this = this
 89       if (_this.flag) {
 90         return
 91       }
 92       requestAnimationFrame(() => {
 93         _this.top = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
 94         const topNum = Math.round(_this.top / 25)
 95         let n = topNum - _this.imgIndex
 96         if (n > 0) {
 97           // 向下滚动
 98           for (let i = 0; i < n; i++) {
 99             _this.imgIndex++
100             _this.renderImg()
101           }
102         } else {
103           for (let i = 0; i < -n; i++) {
104             _this.imgIndex--
105             _this.renderImg()
106           }
107         }
108         _this.flag = false
109       })
110       _this.flag = true
111     },
112   },
113 }
114 </script>
115 
116 <style lang="scss" scoped>
117 .home {
118   height: 15000px;
119   background: #000;
120 }
121 
122 .canvas {
123   width: 100%;
124   height: 100vh;
125   min-width: 1240px;
126   overflow: hidden;
127   position: sticky;
128   top: 0px;
129   left: 0px;
130   display: flex;
131   align-items: flex-end;
132   canvas {
133     width: 100%;
134     overflow: hidden;
135   }
136 }
137 </style>
138   

 

posted @ 2022-06-01 14:49  acttan  阅读(542)  评论(0编辑  收藏  举报