| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- <template>
- <div
- class="c-video iconfont"
- :style="styles"
- >
- <template v-if="canPlay">
- <video
- ref="player"
- class="c-video__inst"
- :src="src"
- autoplay
- :muted.prop="muted"
- @ended="onEnded"
- @error="onError"
- />
- <canvas
- v-show="isSnapping"
- ref="canvas"
- class="c-video__canvas"
- />
- </template>
- </div>
- </template>
- <script>
- import { getAssetUrl } from '@/api/asset'
- export default {
- name: 'CVideo',
- inject: ['control'],
- props: {
- node: {
- type: Object,
- default: null
- }
- },
- data () {
- return {
- ignore: false,
- url: ''
- }
- },
- computed: {
- isSnapping () {
- return this.control.snapping
- },
- styles () {
- const {
- width,
- height,
- radius
- } = this.node
- return {
- width: `${width}px`,
- height: `${height}px`,
- 'font-size': `${Math.min(width, height) / 3 | 0}px`,
- 'border-radius': `${radius}px`
- }
- },
- src () {
- return this.url ? getAssetUrl(this.url) : ''
- },
- muted () {
- return this.node.mute || this.control.muted
- },
- canPlay () {
- return !this.ignore && this.url
- }
- },
- watch: {
- 'node.sources' () {
- this.reset()
- },
- isSnapping (val) {
- let ignore = false
- const player = this.$refs.player
- if (player) {
- if (val) {
- // 尽量保障出画面
- if (player.currentTime && player.currentTime >= 0.5) {
- player.pause()
- this.getSnap()
- } else {
- ignore = true
- }
- } else {
- player.play()
- const canvas = this.$refs.canvas
- if (canvas) {
- canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height)
- }
- }
- }
- this.ignore = ignore
- }
- },
- created () {
- this.reset()
- },
- methods: {
- reset () {
- this.$index = 0
- this.choose()
- },
- choose () {
- const { sources, toggleType } = this.node
- const length = sources.length
- if (length === 0) {
- this.url = ''
- return
- }
- if (length === 1) {
- this.url = sources[0].keyName
- return
- }
- let index
- switch (toggleType) {
- case 'cycle':
- index = this.$index
- this.$index = (index + 1) % length
- break
- case 'random':
- index = Math.random() * length | 0
- if (sources[index]?.keyName === this.url) {
- if (index === 0) {
- index += 1
- } else {
- index -= 1
- }
- }
- break
- default:
- return
- }
- this.url = sources[index].keyName
- },
- onEnded () {
- this.$refs.player.currentTime = 0
- if (this.node.sources.length > 1) {
- this.choose()
- }
- this.$refs.player.play()
- },
- onError (e) {
- console.warn('video error', e)
- if (this.node.sources.length > 1) {
- this.choose()
- }
- },
- getSnap () {
- const video = this.$refs.player
- const canvas = this.$refs.canvas
- if (video && canvas) {
- const cxt = canvas.getContext('2d')
- canvas.width = this.node.width
- canvas.height = this.node.height
- cxt.drawImage(video, 0, 0, this.node.width, this.node.height)
- }
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .c-video {
- position: relative;
- display: inline-flex;
- justify-content: center;
- align-items: center;
- background-color: rgba(255, 255, 255, 0.8);
- overflow: hidden;
- &::before {
- content: "\ecc1";
- font-size: inherit;
- }
- &__inst,
- &__canvas {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- }
- &__inst {
- object-fit: fill;
- }
- }
- </style>
|