vue3自定义video标签视频样式

完整代码,手写得代码比较笨重,可以借鉴一下思路

<template>
  <div @mousemove.stop="topMove" style="width: 100%; height: 100%">
    <div
      :style="
        'width:' +
        myVideoWidth +
        ';height: ' +
        myVideoHeight +
        ';position: relative;'
      "
      @mousemove.stop="mousemove"
    >
      <video
        controls
        ref="video_dom"
        id="myVideo"
        :style="
          'width:' +
          myVideoWidth +
          ';height: ' +
          myVideoHeight +
          ';object-fit: fill;'
        "
        controlsList="nodownload"
      >
        <source src="./2024416-817024.mp4" type="video/mp4" />
        Your browser does not support the video tag.
      </video>
      <div
        ref="progress_bar2"
        class="progress_bar"
        :style="'position: absolute; top:' + top + 'rem;width:' + width + ';'"
        v-show="show"
        @mousemove="progressMove"
      >
        <div class="progress_barzk" @mousemove.stop="progressBarzk">
          <div
            ref="pda"
            class="progress_barzk-A"
            @mousemove.stop="elProgressMove"
            @mousedown.stop="startTimer"
            @mouseup.stop="clearTimer"
          >
            <div
              class="el-progress-bar"
              :style="
                'width:' +
                percentage +
                '%; height: 100%; background: #ff6699;border-radius: 0.625rem;'
              "
            ></div>
            <img
              v-if="biliDetermine"
              :style="
                'position: absolute;top:-0.4275rem;left: ' +
                percentage +
                '%;z-index:1;'
              "
              src="../../assets/image/bilibili.png"
              class="bilibili"
            />
          </div>
        </div>
        <div class="progress_bar_2">
          <img
            class="progress_bofang"
            src="../../assets/image/bofang.png"
            @click="clickPlay"
            v-if="fal"
          />
          <img
            v-else
            class="progress_bofang"
            src="../../assets/image/bofang_1.png"
            @click="clickSuspend"
          />
          <div class="play_time_contrast">
            <div>
              {{
                currentTime.toString().length < 5
                  ? currentTime.toString().padStart(5, "0").replace(".", ":")
                  : currentTime.toString()
              }}
            </div>
            <div>/</div>
            <div>
              {{
                totalTime.toString().length < 5
                  ? totalTime.toString().padStart(5, "0").replace(".", ":")
                  : totalTime.toString().replace(".", ":")
              }}
            </div>
          </div>
          <div class="barrage">
            <div>
              <span
                @click="switchBarrage"
                v-if="switchDetermine"
                class="barrage_svg1"
              >
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  data-pointer="none"
                  viewBox="0 0 24 24"
                  :width="20"
                  :height="20"
                >
                  <path
                    fill-rule="evenodd"
                    d="M11.989 4.828c-.47 0-.975.004-1.515.012l-1.71-2.566a1.008 1.008 0 0 0-1.678 1.118l.999 1.5c-.681.018-1.403.04-2.164.068a4.013 4.013 0 0 0-3.83 3.44c-.165 1.15-.245 2.545-.245 4.185 0 1.965.115 3.67.35 5.116a4.012 4.012 0 0 0 3.763 3.363l.906.046c1.205.063 1.808.095 3.607.095a.988.988 0 0 0 0-1.975c-1.758 0-2.339-.03-3.501-.092l-.915-.047a2.037 2.037 0 0 1-1.91-1.708c-.216-1.324-.325-2.924-.325-4.798 0-1.563.076-2.864.225-3.904.14-.977.96-1.713 1.945-1.747 2.444-.087 4.465-.13 6.063-.131 1.598 0 3.62.044 6.064.13.96.034 1.71.81 1.855 1.814.075.524.113 1.962.141 3.065v.002c.01.342.017.65.025.88a.987.987 0 1 0 1.974-.068c-.008-.226-.016-.523-.025-.856v-.027c-.03-1.118-.073-2.663-.16-3.276-.273-1.906-1.783-3.438-3.74-3.507-.9-.032-1.743-.058-2.531-.078l1.05-1.46a1.008 1.008 0 0 0-1.638-1.177l-1.862 2.59c-.38-.004-.744-.007-1.088-.007h-.13Zm.521 4.775h-1.32v4.631h2.222v.847h-2.618v1.078h2.618l.003.678c.36.026.714.163 1.01.407h.11v-1.085h2.694v-1.078h-2.695v-.847H16.8v-4.63h-1.276a8.59 8.59 0 0 0 .748-1.42L15.183 7.8a14.232 14.232 0 0 1-.814 1.804h-1.518l.693-.308a8.862 8.862 0 0 0-.814-1.408l-1.045.352c.297.396.572.847.825 1.364Zm-4.18 3.564.154-1.485h1.98V8.294h-3.2v.98H9.33v1.43H7.472l-.308 3.453h2.277c0 1.166-.044 1.925-.12 2.277-.078.352-.386.528-.936.528-.308 0-.616-.022-.902-.055l.297 1.067.062.005c.285.02.551.04.818.04 1.001-.067 1.562-.419 1.694-1.057.11-.638.176-1.903.176-3.795h-2.2Zm7.458.11v-.858h-1.254v.858h1.254Zm-2.376-.858v.858h-1.199v-.858h1.2Zm-1.199-.946h1.2v-.902h-1.2v.902Zm2.321 0v-.902h1.254v.902h-1.254Z"
                    clip-rule="evenodd"
                    fill="#fff"
                  ></path>
                  <path
                    fill="#00AEEC"
                    fill-rule="evenodd"
                    d="M22.846 14.627a1 1 0 0 0-1.412.075l-5.091 5.703-2.216-2.275-.097-.086-.008-.005a1 1 0 0 0-1.322 1.493l2.963 3.041.093.083.007.005c.407.315 1 .27 1.354-.124l5.81-6.505.08-.102.005-.008a1 1 0 0 0-.166-1.295Z"
                    clip-rule="evenodd"
                  ></path>
                </svg>
              </span>
              <span @click="switchBarrage" v-else class="barrage_svg1">
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  data-pointer="none"
                  viewBox="0 0 24 24"
                  :width="20"
                  :height="20"
                >
                  <path
                    fill="#fff"
                    fill-rule="evenodd"
                    d="m8.085 4.891-.999-1.499a1.008 1.008 0 0 1 1.679-1.118l1.709 2.566c.54-.008 1.045-.012 1.515-.012h.13c.345 0 .707.003 1.088.007l1.862-2.59a1.008 1.008 0 0 1 1.637 1.177l-1.049 1.46c.788.02 1.631.046 2.53.078 1.958.069 3.468 1.6 3.74 3.507.088.613.13 2.158.16 3.276l.001.027c.01.333.017.63.025.856a.987.987 0 0 1-1.974.069c-.008-.23-.016-.539-.025-.881v-.002c-.028-1.103-.066-2.541-.142-3.065-.143-1.004-.895-1.78-1.854-1.813-2.444-.087-4.466-.13-6.064-.131-1.598 0-3.619.044-6.063.13a2.037 2.037 0 0 0-1.945 1.748c-.15 1.04-.225 2.341-.225 3.904 0 1.874.11 3.474.325 4.798.154.949.95 1.66 1.91 1.708a97.58 97.58 0 0 0 5.416.139.988.988 0 0 1 0 1.975c-2.196 0-3.61-.047-5.513-.141A4.012 4.012 0 0 1 2.197 17.7c-.236-1.446-.351-3.151-.351-5.116 0-1.64.08-3.035.245-4.184A4.013 4.013 0 0 1 5.92 4.96c.761-.027 1.483-.05 2.164-.069Zm4.436 4.707h-1.32v4.63h2.222v.848h-2.618v1.078h2.431a5.01 5.01 0 0 1 3.575-3.115V9.598h-1.276a8.59 8.59 0 0 0 .748-1.42l-1.089-.384a14.232 14.232 0 0 1-.814 1.804h-1.518l.693-.308a8.862 8.862 0 0 0-.814-1.408l-1.045.352c.297.396.572.847.825 1.364Zm-4.18 3.564.154-1.485h1.98V8.289h-3.2v.979h2.067v1.43H7.483l-.308 3.454h2.277c0 1.166-.044 1.925-.12 2.277-.078.352-.386.528-.936.528-.308 0-.616-.022-.902-.055l.297 1.067.062.004c.285.02.551.04.818.04 1.001-.066 1.562-.418 1.694-1.056.11-.638.176-1.903.176-3.795h-2.2Zm7.458.11v-.858h-1.254v.858H15.8Zm-2.376-.858v.858h-1.199v-.858h1.2Zm-1.199-.946h1.2v-.902h-1.2v.902Zm2.321 0v-.902H15.8v.902h-1.254Zm3.517 10.594a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-.002-1.502a2.5 2.5 0 0 1-2.217-3.657l3.326 3.398a2.49 2.49 0 0 1-1.109.259Zm2.5-2.5c0 .42-.103.815-.286 1.162l-3.328-3.401a2.5 2.5 0 0 1 3.614 2.239Z"
                    clip-rule="evenodd"
                  ></path>
                </svg>
              </span>

              <svg
                xmlns="http://www.w3.org/2000/svg"
                data-pointer="none"
                viewBox="0 0 24 24"
                :width="20"
                :height="20"
              >
                <path
                  fill-rule="evenodd"
                  fill="#fff"
                  d="m15.645 4.881 1.06-1.473a.998.998 0 1 0-1.622-1.166L13.22 4.835a110.67 110.67 0 0 0-1.1-.007h-.131c-.47 0-.975.004-1.515.012L8.783 2.3A.998.998 0 0 0 7.12 3.408l.988 1.484c-.688.019-1.418.042-2.188.069a4.013 4.013 0 0 0-3.83 3.44c-.165 1.15-.245 2.545-.245 4.185 0 1.965.115 3.67.35 5.116a4.012 4.012 0 0 0 3.763 3.363c1.903.094 3.317.141 5.513.141a.988.988 0 0 0 0-1.975 97.58 97.58 0 0 1-5.416-.139 2.037 2.037 0 0 1-1.91-1.708c-.216-1.324-.325-2.924-.325-4.798 0-1.563.076-2.864.225-3.904.14-.977.96-1.713 1.945-1.747 2.444-.087 4.465-.13 6.063-.131 1.598 0 3.62.044 6.064.13.96.034 1.71.81 1.855 1.814.075.524.113 1.962.141 3.065v.002c.005.183.01.07.014-.038.004-.096.008-.189.011-.081a.987.987 0 1 0 1.974-.069c-.004-.105-.007-.009-.011.09-.002.056-.004.112-.007.135l-.002.01a.574.574 0 0 1-.005-.091v-.027c-.03-1.118-.073-2.663-.16-3.276-.273-1.906-1.783-3.438-3.74-3.507-.905-.032-1.752-.058-2.543-.079Zm-3.113 4.703h-1.307v4.643h2.2v.04l.651-1.234c.113-.215.281-.389.482-.509v-.11h.235c.137-.049.283-.074.433-.074h1.553V9.584h-1.264a8.5 8.5 0 0 0 .741-1.405l-1.078-.381c-.24.631-.501 1.23-.806 1.786h-1.503l.686-.305c-.228-.501-.5-.959-.806-1.394l-1.034.348c.294.392.566.839.817 1.35Zm-1.7 5.502h2.16l-.564 1.068h-1.595v-1.068Zm-2.498-1.863.152-1.561h1.96V8.289H7.277v.969h2.048v1.435h-1.84l-.306 3.51h2.254c0 1.155-.043 1.906-.12 2.255-.076.348-.38.523-.925.523-.305 0-.61-.022-.893-.055l.294 1.056.061.005c.282.02.546.039.81.039.991-.065 1.547-.414 1.677-1.046.11-.631.175-1.883.175-3.757H8.334Zm5.09-.8v.85h-1.188v-.85h1.187Zm-1.188-.955h1.187v-.893h-1.187v.893Zm2.322.007v-.893h1.241v.893h-1.241Zm.528 2.757a1.26 1.26 0 0 1 1.087-.627l4.003-.009a1.26 1.26 0 0 1 1.094.63l1.721 2.982c.226.39.225.872-.001 1.263l-1.743 3a1.26 1.26 0 0 1-1.086.628l-4.003.009a1.26 1.26 0 0 1-1.094-.63l-1.722-2.982a1.26 1.26 0 0 1 .002-1.263l1.742-3Zm1.967.858a1.26 1.26 0 0 0-1.08.614l-.903 1.513a1.26 1.26 0 0 0-.002 1.289l.885 1.492c.227.384.64.62 1.086.618l2.192-.005a1.26 1.26 0 0 0 1.08-.615l.904-1.518a1.26 1.26 0 0 0 .001-1.288l-.884-1.489a1.26 1.26 0 0 0-1.086-.616l-2.193.005Zm2.517 2.76a1.4 1.4 0 1 1-2.8 0 1.4 1.4 0 0 1 2.8 0Z"
                  clip-rule="evenodd"
                ></path>
              </svg>
            </div>
          </div>
          <el-icon class="full_screen" @click="fullScreen"
            ><FullScreen
          /></el-icon>
        </div>
      </div>
    </div>
    <div></div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";

let video_dom = ref();
let Width = `${600 / 16}rem`;
let Height = `${500 / 16}rem`;
let myVideoWidth = ref(Width);
let myVideoHeight = ref(Height);
let top = ref();
let width = ref();
let progress_bar2 = ref();
let fal = ref<boolean>(true);
let show = ref<boolean>(false);
let percentage = ref(0); //进度条
let moveDetermine = ref<boolean>(false); //长按单击判断
let biliDetermine = ref<boolean>(false); //进度条bilibuli图标是否显示
let switchDetermine = ref<boolean>(false);
let currentTime = ref<string | number>("00:00");
let totalTime = ref<string | number>("00:00");
let clientY: any;
let timer: any;
let clientTime = ref(0);
let pda = ref();

const setTop = () => {
  setTimeout(() => {
    const videoDisplayHeight = video_dom.value.clientHeight;
    const progressBarHeight = progress_bar2.value.clientHeight;
    top.value = (videoDisplayHeight - progressBarHeight) / 16;
    width.value = "100%";
  }, 100);
};

const startTimer = () => {
  moveDetermine.value = true;
};
const clearTimer = () => {
  moveDetermine.value = false;
};
const progressBarzk = () => {
  biliDetermine.value = true;
};

const elProgressMove = (event: any) => {
  let b = (event.clientX / pda.value.clientWidth) * 100; //鼠标滑动距离
  let a = video_dom.value.duration * (b / 100); //播放开始时间
  if (moveDetermine.value) {
    percentage.value = b;
    clientTime.value = a;
  }
  pda.value.addEventListener("click", () => {
    event.stopPropagation();
    if (moveDetermine.value) {
      moveDetermine.value = false;
      return;
    }
    percentage.value = b;
    video_dom.value.currentTime = a;
    video_dom.value.play();
  });
};
//打开弹幕
const switchBarrage = () => {
  switchDetermine.value = !switchDetermine.value;
};
const mousemove = () => {
  setTop();
  setTimeout(() => {
    show.value = true;
  }, 100);
};
const topMove = () => {
  setTimeout(() => {
    show.value = false;
  }, 100);

  biliDetermine.value = false;
};
const progressMove = () => {
  clearInterval(timer);
  show.value = true;
  biliDetermine.value = false;
  moveDetermine.value = false;
};
//播放视频
const clickPlay = () => {
  video_dom.value.play();
  fal.value = !fal.value;
  // progressBar();
};
//暂停视频
const clickSuspend = () => {
  fal.value = !fal.value;
  video_dom.value.pause();
};
//展开全屏
const fullScreen = async () => {
  if (
    !document.fullscreenElement
    // &&
    // !document.mozFullScreenElement &&
    // !document.webkitFullscreenElement &&
    // !document.msFullscreenElement
  ) {
    if (document.documentElement.requestFullscreen) {
      // document.documentElement.requestFullscreen();
      myVideoWidth.value = "100vw";
      myVideoHeight.value = "100vh";
      document.documentElement.requestFullscreen();
      setTop();
    }
    // else if (document.documentElement.mozRequestFullScreen) {
    //   document.documentElement.mozRequestFullScreen();
    // } else if (document.documentElement.webkitRequestFullscreen) {
    //   document.documentElement.webkitRequestFullscreen();
    // } else if (document.documentElement.msRequestFullscreen) {
    //   document.documentElement.msRequestFullscreen();
    // }
  } else {
    // 如果当前页面已处于全屏状态,则退出全屏
    if (document.exitFullscreen) {
      document.exitFullscreen();
      myVideoWidth.value = Width;
      myVideoHeight.value = Height;
      setTop();
    }
    // else if (document.mozCancelFullScreen) {
    //   document.mozCancelFullScreen();
    // } else if (document.webkitExitFullscreen) {
    //   document.webkitExitFullscreen();
    // } else if (document.msExitFullscreen) {
    //   document.msExitFullscreen();
    // }
  }
};
//退出全屏
const exitFullScreen = () => {
  document.addEventListener("fullscreenchange", exitHandler);
  document.addEventListener("webkitfullscreenchange", exitHandler);
  document.addEventListener("mozfullscreenchange", exitHandler);
  document.addEventListener("MSFullscreenChange", exitHandler);
  function exitHandler() {
    if (!document.fullscreenElement) {
      myVideoWidth.value = Width;
      myVideoHeight.value = Height;
      setTop();
    }
  }
};

const videoDomMousemove = () => {
  video_dom.value.addEventListener("mousemove", (event: any) => {
    // const controls = video_dom.value.controls;
    const rect = video_dom.value.getBoundingClientRect();
    if (event.clientY >= rect.bottom - 40) {
      // console.log("鼠标移到进度条上");
    } else if (event.clientY < rect.bottom - 40) {
      // console.log("鼠标离开进度条");
      moveDetermine.value = false;
    }
    clientY = event.clientY;
    clearInterval(timer);
    timer = setInterval(() => {
      if (clientY == event.clientY) {
        show.value = false;
      }
    }, 2000);
  });
};
const loadedmetadata = () => {
  video_dom.value.addEventListener("loadedmetadata", function () {
    //加载数据
    // console.log("视频原始宽度:", video_dom.value.videoWidth);
    // console.log("视频原始高度:", video_dom.value.videoHeight);
    //视频的总长度
    totalTime.value = (video_dom.value.duration / 60).toFixed(2);
  });
};
const timeupdate = () => {
  video_dom.value.addEventListener("timeupdate", function () {
    if (!moveDetermine.value) {
      currentTime.value = (video_dom.value.currentTime / 60).toFixed(2);
      const currentTime2 = video_dom.value.currentTime;
      const duration = video_dom.value.duration;
      percentage.value = (currentTime2 / duration) * 100;
      if (percentage.value == 100) {
        fal.value = true;
      }
    }
  });
};
onMounted(() => {
  videoDomMousemove();
  exitFullScreen();
  loadedmetadata();
  setTop();
  timeupdate();
  video_dom.value.addEventListener("play", function () {
    //播放开始执行的函数
    console.log("开始播放");
    fal.value = false;
  });
  video_dom.value.addEventListener("playing", function () {
    //播放中
    console.log("播放中");
    fal.value = false;
  });
  video_dom.value.addEventListener("waiting", function () {
    //加载
    console.log("加载中");
  });
  video_dom.value.addEventListener("pause", function () {
    //暂停开始执行的函数
    console.log("暂停播放");
    fal.value = true;
  });

  video_dom.value.addEventListener(
    "ended",
    function () {
      //结束
      console.log("播放结束");
    },
    false
  );
});
</script>

<style lang="scss" scoped>
@import "./index.scss";

video::-webkit-media-controls {
  display: none;
}
</style>

css样式

@keyframes bilibili {
  from {
    width: 1rem;
    height: 0rem;
  }
  to {
    width: 1rem;
    height: 1rem;
  }
}

@keyframes progressBar {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

.progress_bar {
  // background-color: red;
  height: 3.125rem;
  display: flex;
  justify-content: center;
  flex-direction: column;
  animation: progressBar 0.3s ease-out;

  .full_screen {
    width: 1rem;
    height: 1rem;
    background-color: #fff;
  }
  .progress_barzk {
    width: 100%;
    display: flex;
    align-items: center;
    padding: 0.375rem 0.375rem;
    box-sizing: border-box;
    .progress_barzk-A {
      width: 100%;
      height: 0.5rem;
      position: relative;

      background-color: rgba(51, 51, 51, 0.5);
      border-radius: 0.625rem;

      .bilibili {
        width: 1rem;
        height: 1rem;
        animation: bilibili 1s;
        // filter: brightness(10);
      }
    }
  }
  .progress_bar_2 {
    display: flex;
    align-items: center;

    .progress_bofang {
      width: 1.5rem;
      height: 1.5rem;
      filter: brightness(10); /* 通过 hue-rotate 滤镜旋转颜色 */
    }
    .play_time_contrast {
      margin-left: 0.625rem;
      color: #fff;
      font-size: 0.875rem;
      min-width: 5.5rem;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .barrage {
      min-width: 6.25rem;
      display: flex;
      margin-left: 1.875rem;
      .barrage_svg1 {
        margin-right: 0.375rem;
      }
    }
  }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值