1.0.3 • Published 2 years ago

video-printscreen-selector v1.0.3

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

Installation

$ npm install video-printscreen-selector

Description

有这么一个需求:上传视频后需要用户上传视频封面,但是用户上传(截取)的封面尺寸跟视频尺寸大小不一,因为封面图片尺寸小于视频尺寸,当开始播放时,图片会给用户一种视频放大了的感觉,体验不太友好。这个组件是通过获取视频的大小,再通过截取视频画面提供上传视频者更方便选择视频封面。

Demo

图中结合ant-design-vue UI 走马灯组件实现选取组件

https://sm.ms/image/dnNhgSuCUk7A2XJ

Usage

示例1:
上传视频文件时实例化(多用于新建)

父组件:
<script>
// 子组件
import videoModal from '@/components/videoController/index.vue'
import VideoController from 'video-printscreen-selector'

beforeUpload (file) {
  if (!validMajorBrowser(this)) return false
  const that = this
  const isJpgOrPng = file.type === 'video/mp4'
  // 判断视频格式
  if (!isJpgOrPng) {
    this.$message.error('目前只能上传 MP4 格式的视频!')
    return false
  }
  // 判断视频大小
  const isLt2M = file.size / 1024 / 1024 < 20
  if (!isLt2M) {
    this.$message.error('视频只能上传 20 M以内!')
    return false
  }
  this.uploading = true
  // 实例化
  this.videoController = new VideoController()
  // 获取视频宽、高、视频长度
  this.videoController.getVidewInfo(file)
  uploadOSS(file).then((results) => {
    // 上传完成后, 赋值视频连接
    this.$set(that.form, 'url', results.res.requestUrls[0].toString())
    this.$refs.videoUrl.clearValidate()
    that.$message.info(`上传成功`)
    this.uploading = false
    this.showVideoModal = true // 弹出子组件
  })
  return false
},
// 附赠base64转file文件方法
onSelectImage (img) {
  const that = this
  // base64转blob
  const base64ToBlob = (base64Data) => {
    const arr = base64Data.split(',')
    const fileType = arr[0].match(/:(.*?)/)[1]
    const bstr = atob(arr[1])
    let l = bstr.length
    const u8Arr = new Uint8Array(l)
    while (l--) {
      u8Arr[l] = bstr.charCodeAt(l)
    }
    return new Blob([u8Arr], {
      type: fileType
    })
  }
  // blob转file
  const blobToFile = (newBlob, fileName) => {
    newBlob.lastModifiedDate = new Date()
    newBlob.name = fileName
    return newBlob
  }
  // 生成blob
  const blob = base64ToBlob(img)
  // 实例化水印对象
  const watermarkMaker = new Watermark()
  // 生成file文件
  const file = blobToFile(blob, Date.parse(new Date()))
  // 这个是作者另外一个图片水印插件
  watermarkMaker.drawWatermarkImg(file, watermark, res => {
    // 图片/视频上传方法
    uploadOSS(res).then((results) => {
      this.$set(that.form, 'image', results.res.requestUrls[0].toString())
      that.$message.info(`上传成功`)
    })
  })
}
</script>

子组件:
<template>
  <a-modal class="modal-group" v-model="showModal" title="视频封面" :width="900" :maskClosable="false">
    <a-carousel class="swiper-group" arrows dots-class="slick-dots slick-thumb">
      <a slot="customPaging" slot-scope="props">
        <img :src="getImgUrl(props.i)" @click="onSelectImage(props.i)" />
      </a>
      <div v-for="(item, i) in imageList" :key="i">
        <img :width="videoController.videoWidth / 3" :height="videoController.videoHeight / 3" :src="item" />
      </div>
    </a-carousel>
    <div class="pages">
      <a-button type="link" :disabled="page.pageIndex === 1" @click="handlePage(0)">上一页</a-button>
      <a-button type="link" :disabled="page.pageIndex === videoController.maxPage" @click="handlePage(1)">下一页</a-button>
    </div>
    <div class="modal-footer" slot="footer">
      <div>
        视频长度:{{ videoController.videoDuration }}s
        &nbsp;
        总页数:{{ videoController.maxPage }}
        &nbsp;
        当前页:
        <a-input-number v-model="page.pageIndex" :min="1" :max="videoController.maxPage" @change="onChangePage" />
      </div>
      <div>
        <a-button @click="showModal = false">取消</a-button>
        <a-button type="primary" @click="submit">确定</a-button>
      </div>
    </div>
    <a-spin class="spin" v-if="loading" tip="图片生成中..." size="large"></a-spin>
    <div v-if="loading" class="spin-mask"></div>
  </a-modal>
</template>

<script>
import VideoController from 'video-printscreen-selector'
  export default {
    data () {
      return {
        showModal: false,
        imageList: [],
        loading: false,
        current: '',
        page: {
          pageIndex: 1,
          pageSize: 10
        }
      }
    },
    props: {
      value: {
        type: Boolean,
        default: false
      },
      videoController: {
        type: Object,
        required: true,
        default: () => {
          return new VideoController() // 默认实例化方法
        }
      },
      videoUrl: {
        type: String,
        default: ''
      }
    },
    watch: {
      value (c) {
        this.showModal = c
      },
      showModal (c) {
        if (!c) {
          this.current = ''
          this.$emit('input', c)
        } else {
          this.getImageList()
        }
      }
    },
    methods: {
      async getImageList () {
        try {
          this.loading = true
          this.imageList = await this.videoController.createVideoImagesList(this.videoUrl, 'multi', this.page) // 通过这个方法获取所需截取的图片范围
          this.$nextTick(() => {
            this.current = this.imageList[0] // 默认选择第一张图片
          })
        } catch (e) {
          this.$message.error(e)
        } finally {
          this.loading = false
        }
      },
      onSelectImage (i) {
        this.current = this.imageList[i]
      },
      getImgUrl (i) {
        return this.imageList[i]
      },
      handlePage (c) {
        if (c) {
          // 下一页
          this.page.pageIndex += 1
        } else {
          // 上一页
          this.page.pageIndex -= 1
        }
        this.getImageList()
      },
      onChangePage (c) {
        this.page.pageIndex = c
        this.getImageList()
      },
      submit () {
        this.$emit('onSelect', this.current)
        this.showModal = false
      }
    }
  }
</script>

示例2:
直接通过视频连接获取(多用于编辑)
import VideoController from 'video-printscreen-selector'

<script>
export default {
    methods: {
        async buildController () {
            const controller = new VideoController()
            const img = await controller.createVideoImagesList(
                '视频链接',
                11
            )
        }
    }
}
</script>

API

实例化后可以获取到的参数/方法:

属性说明类型默认值
videoWidth视频宽度number0
videoHeight视频高度number0
maxPage分页最大页数number0
videoDuration视频长度(秒)number0
createVideoImagesList截取方法,type为single时默认截取视频第1秒,type也可以具体到某一秒(类型必须为number),当type为'multi'为范围截取,此时page参数必传functionurl, type = 'single', page = { pageIndex: 1, pageSize: 10 }
1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago