Uniapp + VUE3.0 实现双向滑块视频裁剪效果

效果图

<template>
  <view v-if="info" class="all">
    <video
        :src="info.videoUrl"
        class="video" id="video" :controls="true" object-fit="fill" :show-fullscreen-btn="false"
        play-btn-position="center"
        :autoplay="true" @loadedmetadata="loadedMetadata"></video>
    <view class="slider">
      <view class="thumb-left" @touchmove="e=>handleTouchMove(e,0)" @touchend="e=>handleTouchEnd(e,0)"
            :style="` margin-left: ${thumbLeft}px;`">{{ start }}
      </view>
      <view class="slider-bg"></view>
      <view class="thumb-right" @touchmove="e=>handleTouchMove(e,1)" @touchend="e=>handleTouchEnd(e,1)"
            :style="` margin-right: ${thumbRight}px;`">{{ end }}
      </view>
    </view>
  </view>

</template>

<script lang="ts" setup>
const videoInfo = defineProps(["info"])
const emit = defineEmits(['onChange'])
import {ref, computed, onMounted, getCurrentInstance} from "vue";
import {
  onReady,
} from "@dcloudio/uni-app"

const min = ref(0)
const max = ref(0)
const minInterval = ref(15)//最小裁剪间隔
const thumbLeft = ref(0)
const thumbRight = ref(0)
const start = ref(computed(() => {
  return Math.round((thumbLeft.value) * rate.value)
}))
const end = ref(computed(() => {
  return Math.round((totalWidth.value - thumbRight.value) * rate.value)
}))

const rate = ref(computed(() => {
  return max.value / totalWidth.value
}))
const interval = ref(computed(() => {
  return minInterval.value / rate.value
}))


const instance = getCurrentInstance()
const thumbLeftSize = ref({
  width: 0,
  height: 0,
  left: 0,
  right: 0
})
const thumbRightSize = ref({
  width: 0,
  height: 0,
  left: 0,
  right: 0
})
let dxLeft = 0
let dxRight = 0
const totalWidth = ref(0)
const videoTotalDuration = ref(0)
let videoContext: UniApp.VideoContext = null
let windowWidth = 0
let timer: number = null

function loadedMetadata(e) {
  max.value = Math.floor(e.detail.duration)
  emit('onChange', {start: start.value, end: end.value})
}

onReady(() => {
  videoContext = uni.createVideoContext('video', instance);
  windowWidth = uni.getSystemInfoSync().windowWidth
})
onMounted(() => {
  uni.createSelectorQuery().in(instance).select('.thumb-left').boundingClientRect(data => {
    console.log(data)
    thumbLeftSize.value = data
    console.log(thumbLeftSize.value)
  }).exec();
  uni.createSelectorQuery().in(instance).select('.thumb-right').boundingClientRect(data => {
    console.log(data)
    thumbRightSize.value = data
    console.log(thumbRightSize.value)
    totalWidth.value = thumbRightSize.value.right - thumbLeftSize.value.left - 2 * thumbLeftSize.value.width
  }).exec();
});

function handleTouchMove(e, index: Number) {
  let pageX = e.touches[0].pageX
  if (index == 0) {
    //左边边view
    dxLeft = Math.max(pageX - thumbLeftSize.value.left, 0)
    //修正
    if (dxLeft + dxRight + interval.value > totalWidth.value) {
      dxLeft = totalWidth.value - dxRight
    }
    console.log("pageX:" + pageX, "dxRight:" + dxRight, "dxLeft:" + dxLeft, "thumbRight:" + thumbRight.value, "thumbLeft:" + thumbLeft.value, "width:" + thumbLeftSize.value.width, "windowWidth:" + windowWidth, thumbRightSize.value.right, "totalWidth:" + totalWidth.value)
    if (dxLeft <= interval.value) {
      //左边边界
      thumbLeft.value = 0
      return
    }
    if (dxRight + dxLeft + interval.value > totalWidth.value) {
      thumbLeft.value = windowWidth - thumbRight.value - 2 * thumbLeftSize.value.width - 2 * thumbLeftSize.value.left - interval.value
    } else {
      thumbLeft.value = dxLeft - interval.value
    }
  } else {
    //右边view
    dxRight = Math.max(windowWidth - pageX - thumbRightSize.value.width, 0)
    //修正
    if (dxRight + dxLeft + interval.value > totalWidth.value) {
      dxRight = totalWidth.value - dxLeft
    }
    console.log("pageX:" + pageX, "dxRight:" + dxRight, "dxLeft:" + dxLeft, "thumbRight:" + thumbRight.value, "thumbLeft:" + thumbLeft.value, "width:" + thumbLeftSize.value.width, "windowWidth:" + windowWidth, thumbRightSize.value.right, "totalWidth:" + totalWidth.value)
    if (dxRight <= interval.value) {
      //右边边界
      thumbRight.value = 0
      return
    }
    if (dxRight + dxLeft + interval.value > totalWidth.value) {
      //左边边界修正
      thumbRight.value = windowWidth - thumbLeft.value - 2 * thumbLeftSize.value.width - 2 * thumbLeftSize.value.left - interval.value
    } else {
      thumbRight.value = dxRight - interval.value
    }
  }

}

function handleTouchEnd(e, index: Number) {
  emit('onChange', {start: start.value, end: end.value})
  videoContext.seek(index == 0 ? start.value : end.value);
  videoContext.play();
}
</script>

<style lang="scss" scoped>
.all {
  margin-left: 25rpx;
  margin-right: 25rpx;

  .video {
    height: 400rpx;
    width: 100%;
  }

  .slider {
    display: flex;
    color: white;
    flex-direction: row;
    height: 100rpx;

    .thumb-left {
      width: 50rpx;
      height: 100%;
      color: black;
      display: flex;
      font-size: 12rpx;
      align-items: center;
      justify-content: center;
      background-color: #8EFB7C;
      border-top-left-radius: 20rpx;
      border-bottom-left-radius: 20rpx;
    }

    .slider-bg {
      display: flex;
      flex: 1;
      background-color: #F1FFF0
    }

    .thumb-right {
      width: 50rpx;
      height: 100%;
      color: black;
      display: flex;
      font-size: 12rpx;
      align-items: center;
      justify-content: center;
      background-color: #8EFB7C;
      border-top-right-radius: 20rpx;
      border-bottom-right-radius: 20rpx;
    }
  }
}


</style>
相关推荐
LUwantAC1 小时前
CSS(四)display和float
前端·css
cwtlw1 小时前
CSS学习记录20
前端·css·笔记·学习
谢道韫6661 小时前
今日总结 2024-12-24
javascript·vue.js·elementui
一朵好运莲1 小时前
React引入Echart水球图
开发语言·javascript·ecmascript
米奇妙妙wuu1 小时前
react使用sse流实现chat大模型问答,补充css样式
前端·css·react.js
梦境之冢2 小时前
axios 常见的content-type、responseType有哪些?
前端·javascript·http
racerun2 小时前
vue VueResource & axios
前端·javascript·vue.js
J总裁的小芒果2 小时前
THREE.js 入门(六) 纹理、uv坐标
开发语言·javascript·uv
m0_548514772 小时前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
Calm5502 小时前
Vue3:uv-upload图片上传
前端·vue.js