Component({ options: { addGlobalClass: true, // 指定所有 _ 开头的数据字段为纯数据字段 pureDataPattern: /^_/ }, properties: { duration: { type: Number, value: 500 }, easingFunction: { type: String, value: 'default' }, loop: { type: Boolean, value: true }, targetPlayIndex: { type: Number, value: -1, observer: function (newVal) { if (newVal >= 0) { this.targetPlay(newVal) } } }, // {id, url, objectFit} videoList: { type: Array, value: [], observer: function (newVal = []) { this._videoListChanged(newVal) } } }, data: { nextQueue: [], // 待播放列表 prevQueue: [], // 已播放列表 curQueue: [], // 当前播放列表 circular: false, // 是否循环 _last: 0, // 上一次显示 _maxCount: -1, _dataIdx: 0, initIndex: 0, playerIdx: 0, playing: false, _change: -1, _invalidUp: 0, _invalidDown: 0, _videoContexts: [] }, lifetimes: { attached() { this.data._videoContexts = [ wx.createVideoContext('video_0', this), wx.createVideoContext('video_1', this), wx.createVideoContext('video_2', this) ] } }, created() { this._swipering = false }, methods: { // 添加新的视频源 _videoListChanged(newVal) { const data = this.data newVal.forEach(item => { data.nextQueue.push(item) }) const maxCount = newVal.length if (data.curQueue.length === 0) { this.setData({ curQueue: data.nextQueue.splice(0, 3), _maxCount: maxCount }, () => { this.playCurrent(0) }) } }, animationfinish(e) { const { _last, _change, curQueue, prevQueue, nextQueue, _dataIdx } = this.data const current = e.detail.current const diff = current - _last this._swipering = false this.playCurrent(current) const change = current !== this.data._last if (diff === 0 || !change) { return } const direction = (diff === 1 || diff === -2) ? 'up' : 'down' console.log('direction', direction) if (direction === 'up') { if (this.data._invalidDown === 0) { this.data._dataIdx++ if (this.data._dataIdx >= this.data._maxCount) { this.data._dataIdx = 0 } this.loadCurQueue(this.data._dataIdx, current) } else { this.data._invalidDown -= 1 } } if (direction === 'down') { if (this.data._invalidUp === 0) { this.data._dataIdx-- if (this.data._dataIdx < 0) { this.data._dataIdx = this.data._maxCount - 1 } this.loadCurQueue(this.data._dataIdx, current) } else { this.data._invalidUp -= 1 } } this.triggerEvent('change', { activeId: curQueue[current].id }) let circular = true this.data._last = current // if (_dataIdx === 0) { // circular = false // } // if (prevQueue.length === 0 && current !== 2) { // circular = false // } this.setData({ curQueue, circular, }) }, loadCurQueue(dataIdx, playerIdx) { const { _maxCount, curQueue, videoList } = this.data const current = playerIdx; let curDataIdx = dataIdx; if (curDataIdx > _maxCount) { curDataIdx = _maxCount; } let pre = 0, next = 0, preV, nextV, curVideo; pre = current - 1; if (pre < 0) { pre = 2; } next = current + 1; if (next > 2) { next = 0; } if (curDataIdx - 1 >= 0) { preV = videoList[curDataIdx - 1]; } else { preV = videoList[_maxCount - 1]; } console.log('curDataIdx + 1 ', curDataIdx + 1) if (curDataIdx + 1 < _maxCount) { nextV = videoList[curDataIdx + 1]; } else { nextV = videoList[0]; } curVideo = videoList[curDataIdx]; curQueue[pre] = preV curQueue[next] = nextV curQueue[current] = curVideo }, /** * 指定视频播放 * @param {videoList(index)} dataIdx */ targetPlay(dataIdx) { let curQueue = this.data.videoList.slice(); if (dataIdx >= this.data._maxCount) { this._dataIdx = dataIdx = this.data._maxCount - 1 } if (this.data._maxCount - dataIdx < 3) { if (this.data._maxCount - dataIdx === 2) { const last = this.data.videoList.slice().shift(); curQueue = curQueue.splice(dataIdx, 2).concat(last) } if (this.data._maxCount - dataIdx === 1) { const first = this.data.videoList.slice().pop(); curQueue = [first].concat(curQueue.splice(0, 2)); } } else { curQueue = curQueue.splice(dataIdx, 3) } this.setData({ curQueue: curQueue, _dataIdx: dataIdx, playerIdx: 0 }, () => { this.playCurrent(0) }) }, // 避免卡顿 playCurrent(current) { this.data._videoContexts.forEach((ctx, index) => { index !== current ? ctx.pause() : ctx.play() }) this.setData({ playing: true, playerIdx: current }, () => { this.data._videoContexts.forEach((ctx, index) => { index !== current ? ctx.seek(0) : null }) }) // // 重置所有视频pause时重置时间 // setTimeout(() => { // this.data._videoContexts.forEach((ctx, index) => { // index !== current ? ctx.seek(0) : null // }) // }, 100) }, onPlay(e) { this.trigger(e, 'play') }, onPause(e) { this.trigger(e, 'pause') }, onEnded(e) { this.trigger(e, 'ended') }, onError(e) { this.trigger(e, 'error') }, onTimeUpdate(e) { this.trigger(e, 'timeupdate') }, onWaiting(e) { this.trigger(e, 'wait') }, onProgress(e) { this.trigger(e, 'progress') }, onLoadedMetaData(e) { this.trigger(e, 'loadedmetadata') }, trigger(e, type, ext = {}) { const detail = e.detail const activeId = e.target.dataset.id this.triggerEvent(type, Object.assign({ ...detail, activeId }, ext)) }, onVideoOverlayTap() { if (this.data.playing) { this.data._videoContexts.forEach((ctx, index) => { ctx.pause() }) this.setData({ playing: false }) } else { this.data._videoContexts.forEach((ctx, index) => { index !== this.data.playerIdx ? ctx.pause() : ctx.play() }) this.setData({ playing: true }) } }, onSwiping() { this._swipering = true } } })