Vue3实现视频播放弹窗组件,支持全屏播放,音量控制,进度条自定义样式,适配浏览器小窗播放,视频大小自适配,缓冲loading,代码复制即用

发布于:2025-07-28 ⋅ 阅读:(12) ⋅ 点赞:(0)

效果图

 

 组件所需VUE3代码

<template>
  <div class="video-dialog" :class="fullScreen && 'video-dialog-full-screen'">
    <el-dialog
      v-model="props.visible"
      draggable
      :show-close="false"
      title=""
      center
      align-center
      @close="changeVisible"
    >
      <!-- 视频容器 -->
      <div
        class="video-content"
        :style="{
          backgroundImage: firstFrameUrl ? `url(${firstFrameUrl})` : 'none',
        }"
      >
        <!-- 背景磨砂层 -->
        <div class="video-backdrop" v-if="firstFrameUrl"></div>

        <!-- 视频加载中状态 -->
        <div class="video-loading" v-if="isLoading">
          <div class="loading-spinner"></div>
          <p v-if="loadingText">{{ loadingText }}</p>
        </div>

        <!-- 视频标签 -->
        <video
          ref="videoRef"
          :src="videoSrc"
          @timeupdate="updateProgress"
          @ended="handleEnded"
          @click="togglePlay"
          @volumechange="updateVolume"
          @seeked="updateBackground"
          @loadedmetadata="handleMetadataLoaded"
          @error="handleVideoError"
          @waiting="handleVideoBuffering"
          @playing="handleVideoPlaying"
        ></video>

        <!-- 播放错误提示 -->
        <div class="video-error" v-if="videoError">
          <img :src="DataUrl.ErrorIcon || 'https://picsum.photos/48/48'" alt="播放错误" class="error-icon" />
          <p class="error-text">{{ errorMessage }}</p>
          <p class="error-tips">建议使用MP4格式(H.264编码)重新上传</p>
        </div>

        <!-- 视频数据 -->
        <ul class="video-data" v-if="previewInfo">
          <li>
            <img :src="DataUrl.ZanIcon" alt="" class="data-icon i-1" />
            <p>760</p>
          </li>
          <li>
            <img :src="DataUrl.PingIcon" alt="" class="data-icon i-2" />
            <p>670</p>
          </li>
          <li>
            <img :src="DataUrl.LookEyeIcon" alt="" class="data-icon i-3" />
            <p>890</p>
          </li>
        </ul>

        <!-- 视频基本信息 -->
        <div class="video-base-info" v-if="previewInfo">
          <div class="title flex">
            <h1>网红名称</h1>
            <span></span>
            <p>2025.03.30</p>
          </div>
          <p class="note">
            风掠过耳际时突然懂了:原来旅行不是赶路,是让山川湖海,把心里的褶皱慢慢烫平。
          </p>
        </div>

        <img
          @click="changeVisible"
          :src="DataUrl.CloseRadiuIcon"
          alt=""
          class="close-icon"
        />
      </div>

      <!-- 视频进度条 -->
      <div class="video-progress">
        <div class="progress-bg" @click="seekToPosition">
          <div class="progress-value" :style="{ width: progress + '%' }"></div>
          <div class="progress-pointer" :style="{ left: progress + '%' }"></div>
        </div>
      </div>

      <!-- 视频控制栏 -->
      <div class="video-footer-tool">
        <div class="flex">
          <!-- 播放按钮 -->
          <img
            :src="isPlaying ? DataUrl.PauseIcon : DataUrl.PlayZIcon"
            alt=""
            class="icon-1"
            @click="togglePlay"
          />
          <!-- 下一个按钮 -->
          <img
            :src="DataUrl.PlayNextIcon"
            alt=""
            class="icon-2"
            @click="playNextVideo"
          />
          <!-- 音量控制 -->
          <div class="volume-container">
            <img
              :src="isMuted ? DataUrl.MuteIcon : DataUrl.YlIcon"
              alt=""
              class="icon-3"
              @click="toggleMute"
            />
            <div class="hover-mute-content" @mouseenter="showVolumeSlider">
              <div
                class="hover-mute-content-value"
                :style="{ width: volumePercent + '%' }"
                @mousedown="startVolumeAdjust"
              ></div>
            </div>
          </div>
          <!-- 视频时间 -->
          <p>
            {{ currentTime }} /<span>{{ durationTime }}</span>
          </p>
        </div>
        <!-- 全屏按钮 -->
        <div>
          <img
            :src="fullScreen ? DataUrl.UnFdIcon : DataUrl.FdIcon"
            alt=""
            class="icon-4"
            @click="fullScreen = !fullScreen"
          />
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch, nextTick } from "vue"
import DataUrl from "@/config/data-url.js"

// 定义props
const props = defineProps({
  visible: {
    type: Boolean,
    default: false,
  },
  previewInfo: {
    type: Boolean,
    default: true,
  },
  videoInfo: {
    type: Object,
    default: {},
  },
})

// 视频源
const videoSrc = ref(
  props.videoInfo?.url ||
    "https://umi-rise.oss-ap-southeast-1.aliyuncs.com/20250707/WeChat_20250707174726.mp4"
)

// 组件状态
const videoRef = ref(null)
const isPlaying = ref(false)
const isMuted = ref(false)
const progress = ref(0)
const currentTime = ref("00:00")
const durationTime = ref("00:00")
const showControls = ref(true)
const timer = ref(null)
const fullScreen = ref(false)

// 音量控制状态
const volumePercent = ref(70)
const isAdjustingVolume = ref(false)
const isVolumeSliderVisible = ref(false)

// 背景控制状态
const showLeftBackground = ref(false)
const showRightBackground = ref(false)
const videoAspectRatio = ref(0)
const firstFrameUrl = ref("")
const isFirstFrameLoaded = ref(false)

// 播放错误状态
const videoError = ref(false)
const errorMessage = ref("")

// 新增:加载状态
const isLoading = ref(true)
const loadingText = ref("准备播放...")

const emit = defineEmits(["update-visible", "confim"])

// 关闭对话框
const changeVisible = () => {
  if (videoRef.value) {
    videoRef.value.pause();
    isPlaying.value = false; // 重置播放状态
  }
  emit("update-visible", false)
}

// 播放/暂停视频
const togglePlay = () => {
  if (videoRef.value) {
    if (isPlaying.value) {
      videoRef.value.pause()
    } else {
      videoRef.value.play().catch((err) => {
        console.log("自动播放失败,需要用户交互后才能播放", err)
      })
    }
    isPlaying.value = !isPlaying.value
  }
}

// 更新进度条
const updateProgress = () => {
  if (videoRef.value) {
    const percent = (videoRef.value.currentTime / videoRef.value.duration) * 100
    progress.value = Math.min(100, percent)
    currentTime.value = formatTime(videoRef.value.currentTime)

    if (videoRef.value.duration > 0 && durationTime.value === "00:00") {
      durationTime.value = formatTime(videoRef.value.duration)
    }
  }
}

// 格式化时间
const formatTime = (seconds: number) => {
  const minutes = Math.floor(seconds / 60)
  const secs = Math.floor(seconds % 60)
  return `${minutes.toString().padStart(2, "0")}:${secs
    .toString()
    .padStart(2, "0")}`
}

// 进度条点击跳转
const seekToPosition = (e: MouseEvent) => {
  if (videoRef.value) {
    const progressBar = e.currentTarget as HTMLElement
    const rect = progressBar.getBoundingClientRect()
    const clickX = e.clientX - rect.left
    const percent = (clickX / rect.width) * 100
    videoRef.value.currentTime = (percent / 100) * videoRef.value.duration
  }
}

// 音量控制
const toggleMute = () => {
  if (videoRef.value) {
    isMuted.value = !isMuted.value
    videoRef.value.muted = isMuted.value
    volumePercent.value = isMuted.value ? 0 : volumePercent.value
  }
}

const showVolumeSlider = () => {
  isVolumeSliderVisible.value = true
}

const startVolumeAdjust = (e: MouseEvent) => {
  isAdjustingVolume.value = true
  adjustVolume(e)
  document.addEventListener("mousemove", adjustVolume)
  document.addEventListener("mouseup", endVolumeAdjust)
  e.preventDefault()
}

const adjustVolume = (e: MouseEvent) => {
  if (!isAdjustingVolume.value || !videoRef.value) return

  const volumeBar = document.querySelector(".hover-mute-content") as HTMLElement
  if (!volumeBar) return

  const rect = volumeBar.getBoundingClientRect()
  const clickX = e.clientX - rect.left
  let percent = (clickX / rect.width) * 100
  percent = Math.max(0, Math.min(100, percent))

  volumePercent.value = percent
  videoRef.value.volume = percent / 100

  if (isMuted.value) {
    isMuted.value = false
    videoRef.value.muted = false
  }
}

const endVolumeAdjust = () => {
  isAdjustingVolume.value = false
  document.removeEventListener("mousemove", adjustVolume)
  document.removeEventListener("mouseup", endVolumeAdjust)
}

// 更新音量显示
const updateVolume = () => {
  if (videoRef.value) {
    if (videoRef.value.muted !== isMuted.value) {
      isMuted.value = videoRef.value.muted
    }

    if (!isMuted.value) {
      volumePercent.value = Math.round(videoRef.value.volume * 100)
    }
  }
}

// 更新背景显示
const updateBackground = () => {
  if (!videoRef.value || !videoRef.value.videoWidth) return
  // 计算视频宽高比
  videoAspectRatio.value =
    videoRef.value.videoWidth / videoRef.value.videoHeight
  // 获取容器尺寸
  const container = videoRef.value.parentElement
  if (!container) return
  const containerWidth = container.offsetWidth
  const containerHeight = container.offsetHeight
  // 计算容器宽高比
  const containerAspectRatio = containerWidth / containerHeight

  // 根据宽高比差异调整视频显示逻辑
  const isVideoWider = videoAspectRatio.value > containerAspectRatio
  showLeftBackground.value = isVideoWider
  showRightBackground.value = isVideoWider
}

// 加载第一帧
const loadFirstFrame = async () => {
  if (!videoRef.value) return

  try {
    // 尝试获取视频编码信息(部分浏览器支持)
    const videoTracks = videoRef.value.videoTracks
    if (videoTracks && videoTracks.length > 0) {
      const codec = videoTracks[0].codec || videoTracks[0].kind
      if (codec && !codec.includes("avc1") && !codec.includes("h264")) {
        console.warn("检测到非H.264编码,可能无法播放:", codec)
        // 可在这里显示警告提示
      }
    }

    // 尝试直接使用视频帧
    await captureFrame()
  } catch (error) {
    console.error("直接捕获失败:", error)

    // 尝试通过Fetch和Blob URL绕过跨域
    try {
      const response = await fetch(videoSrc.value)
      const blob = await response.blob()
      const blobUrl = URL.createObjectURL(blob)

      const tempVideo = document.createElement("video")
      tempVideo.crossOrigin = "anonymous"
      tempVideo.src = blobUrl

      await new Promise((resolve, reject) => {
        tempVideo.onloadedmetadata = resolve
        tempVideo.onerror = reject
      })

      tempVideo.currentTime = 0.1

      await new Promise((resolve, reject) => {
        tempVideo.onseeked = resolve
        tempVideo.onerror = reject
      })

      const canvas = document.createElement("canvas")
      canvas.width = tempVideo.videoWidth
      canvas.height = tempVideo.videoHeight

      const ctx = canvas.getContext("2d")
      ctx.drawImage(tempVideo, 0, 0, canvas.width, canvas.height)

      firstFrameUrl.value = canvas.toDataURL("image/jpeg", 0.8)
      isFirstFrameLoaded.value = true

      // 清理资源
      URL.revokeObjectURL(blobUrl)
      tempVideo.remove()
    } catch (error) {
      console.error("Blob方法失败:", error)
      // 回退到默认占位图
      firstFrameUrl.value =
        "https://umi-rise.oss-ap-southeast-1.aliyuncs.com/20250707/cover-video-00008.png"
      isFirstFrameLoaded.value = true
    }
  }
}

const captureFrame = () => {
  return new Promise((resolve, reject) => {
    if (!videoRef.value || !videoRef.value.videoWidth) {
      reject(new Error("视频未加载"))
      return
    }

    const video = videoRef.value
    video.currentTime = 0.5

    const handleSeeked = () => {
      const canvas = document.createElement("canvas")
      canvas.width = video.videoWidth
      canvas.height = video.videoHeight

      const ctx = canvas.getContext("2d")
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height)

      try {
        firstFrameUrl.value = canvas.toDataURL("image/jpeg", 0.8)
        isFirstFrameLoaded.value = true
        resolve()
      } catch (error) {
        reject(error)
      } finally {
        video.removeEventListener("seeked", handleSeeked)
      }
    }

    video.addEventListener("seeked", handleSeeked)
  })
}

// 处理视频元数据加载完成
const handleMetadataLoaded = () => {
  loadingText.value = "加载中..."
  // 视频元数据加载完成,但可能还需要缓冲
  // 不立即隐藏loading,等待canplay或playing事件
}

// 处理视频缓冲
const handleVideoBuffering = () => {
  if (!isLoading.value) {
    isLoading.value = true
    loadingText.value = "缓冲中..."
  }
}

// 处理视频开始播放
const handleVideoPlaying = () => {
  // 视频真正开始播放时,隐藏loading
  isLoading.value = false
  isPlaying.value = true
}

// 处理视频播放错误
const handleVideoError = () => {
  if (!videoRef.value) return
  const error = videoRef.value.error
  if (!error) return

  // 根据错误码判断原因
  switch (error.code) {
    case error.MEDIA_ERR_ABORTED:
      errorMessage.value = "视频加载被中断"
      break
    case error.MEDIA_ERR_NETWORK:
      errorMessage.value = "网络错误,无法加载视频"
      break
    case error.MEDIA_ERR_DECODE:
      errorMessage.value = "视频编码不支持,无法播放"
      break
    case error.MEDIA_ERR_SRC_NOT_SUPPORTED:
      errorMessage.value = "视频格式不支持"
      break
    default:
      errorMessage.value = "播放失败,请重试"
  }

  // 显示错误提示,隐藏第一帧背景和loading
  videoError.value = true
  firstFrameUrl.value = ""
  isLoading.value = false
  isPlaying.value = false
}

// 播放下一个视频
const playNextVideo = () => {
  console.log("播放下一个视频")
}

// 视频播放结束
const handleEnded = () => {
  isPlaying.value = false
  console.log("视频播放结束")
}

// 显示/隐藏控制栏
const toggleControls = () => {
  showControls.value = !showControls.value
  if (timer.value) clearTimeout(timer.value)
  timer.value = setTimeout(() => {
    showControls.value = false
  }, 3000)
}

const playVideo = () => {
  videoError.value = false
  isLoading.value = true // 开始加载
  loadingText.value = "准备播放..."
  
  videoRef.value.removeEventListener("click", toggleControls)
  videoRef.value.addEventListener("click", toggleControls)
  videoRef.value.play().catch((err) => {
    console.log("自动播放失败", err)
    isLoading.value = false // 加载失败,隐藏loading
  })
  
  videoRef.value.addEventListener("click", toggleControls)
  nextTick(updateProgress)
  nextTick(updateBackground)

  // 延迟加载第一帧,确保视频元素已初始化
  setTimeout(loadFirstFrame, 100)
}

// 生命周期钩子
onMounted(() => {
  if (videoRef.value) {
    playVideo()
  }

  // 监听窗口大小变化
  window.addEventListener("resize", updateBackground)
})

// 监听全屏状态变化
watch(
  () => fullScreen.value,
  () => {
    nextTick(updateBackground)
  }
)

// 监听视频源变化
watch(
  () => props.videoInfo?.url,
  (newUrl, oldUrl) => {
    if (newUrl && newUrl !== oldUrl) {
      // 更新视频源
      videoSrc.value = newUrl

      // 重置视频状态
      videoError.value = false
      isPlaying.value = false
      progress.value = 0
      currentTime.value = "00:00"
      
      // 加载新视频时显示loading
      isLoading.value = true
      loadingText.value = "准备播放..."

      // 重新加载并播放新视频
      if (videoRef.value) {
        videoRef.value.src = newUrl
        videoRef.value.load()
        videoRef.value.play().catch((err) => {
          console.log("切换视频播放失败:", err)
          isPlaying.value = false
          isLoading.value = false // 加载失败,隐藏loading
        })
        
        // 重新加载第一帧
        loadFirstFrame()
      }
    }
  },
  { immediate: true }
)

// 组件卸载时清理
onUnmounted(() => {
  if (timer.value) clearTimeout(timer.value)
  window.removeEventListener("resize", updateBackground)
})
</script>

<style lang="scss" scoped>
.video-dialog,
.video-dialog-full-screen {
  :deep(.el-overlay) {
    background: rgba(0, 0, 0, 0.66);
  }

  :deep(.el-dialog) {
    width: 900px;
    --el-dialog-border-radius: 20px;
    --el-dialog-padding-primary: 0;
    background: transparent;
    border-radius: 12px;
    padding: 0;
    overflow: hidden;

    .video-content {
      width: 100%;
      height: 503px;
      position: relative;
      overflow: hidden;
      background-size: cover;
      background-position: center;

      // 背景磨砂层
      .video-backdrop {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.4);
        backdrop-filter: blur(10px);
        z-index: 1;
      }

      video {
        max-width: 100%;
        max-height: 100%;
        height: 100%;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        object-fit: contain;
        z-index: 2;
      }

      // 加载状态样式
      .video-loading {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 5; // 高于视频但低于错误提示
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        background: rgba(0, 0, 0, 0.6);
        
        .loading-spinner {
          width: 48px;
          height: 48px;
          border: 4px solid rgba(255, 255, 255, 0.3);
          border-radius: 50%;
          border-top-color: #ff3f81;
          animation: spin 1s linear infinite;
          margin-bottom: 16px;
        }
        
        p {
          color: white;
          font-size: 16px;
          font-family: 'PingFang SC', sans-serif;
        }
      }
      
      @keyframes spin {
        to { transform: rotate(360deg); }
      }
      
      // 播放错误提示
      .video-error {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: 10; // 最高层级
        text-align: center;
        width: 80%;

        .error-icon {
          width: 48px;
          height: 48px;
          margin-bottom: 16px;
        }

        .error-text {
          font-size: 18px;
          color: #ff4d4f;
          margin-bottom: 8px;
        }

        .error-tips {
          font-size: 14px;
          color: rgba(255, 255, 255, 0.7);
        }
      }

      // 视频数据
      .video-data {
        position: absolute;
        right: 24px;
        bottom: 49px;
        z-index: 3;
        li {
          margin-bottom: 17px;
          &:last-child {
            margin-bottom: 0;
          }
        }
        .data-icon {
          width: 24px;
          height: 24px;
          display: block;
          margin: auto;
        }
        p {
          font-family: DIN, DIN;
          color: #ffffff;
          text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6);
          margin-top: 15px;
          font-weight: 400;
          font-size: 16px;
        }
      }

      .close-icon {
        position: absolute;
        right: 24px;
        top: 35px;
        width: 50px;
        height: 50px;
        z-index: 2;
        cursor: pointer;
      }

      .video-base-info {
        position: absolute;
        left: 24px;
        bottom: 12px;
        z-index: 3;
        .title {
          align-items: center;
          h1 {
            font-family: PingFang SC, PingFang SC;
            font-weight: 500;
            font-size: 18px;
            color: #ffffff;
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6);
          }
          span {
            margin: 0 8px;
            display: inline-block;
            width: 2px;
            height: 2px;
            background: #ffffff;
            box-shadow: 1px 1px 2px 0px rgba(0, 0, 0, 0.6);
          }
          p {
            font-family: DIN, DIN;
            font-weight: 400;
            font-size: 12px;
            color: #eae9e8;
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6);
          }
        }
        .note {
          margin-top: 2px;
          width: 234px;
          font-family: PingFang SC, PingFang SC;
          font-weight: 400;
          font-size: 14px;
          color: #ffffff;
          text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6);
          line-height: 1.5;
        }
      }
    }

    .video-content::before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      backdrop-filter: blur(8px);
      background: rgba(255, 255, 255, 0.1);
      z-index: 2;
      pointer-events: none;
    }

    // 进度条样式
    .video-progress {
      position: absolute;
      bottom: 56px;
      left: 0;
      right: 0;
      height: 4px;
      z-index: 3;
      .progress-bg {
        width: 100%;
        height: 100%;
        background: rgba(255, 255, 255, 0.2);
        border-radius: 2px;
        cursor: pointer;
        .progress-value {
          height: 100%;
          background: #ff3f81;
          border-radius: 2px;
          width: 0;
          transition: width 0.1s;
          position: relative;
        }
        .progress-value::after {
          content: "";
          position: absolute;
          right: 0;
          top: 50%;
          transform: translateY(-50%);
          width: 12px;
          height: 12px;
          background: #ff3f81;
          border-radius: 50%;
        }
        .progress-pointer {
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          width: 12px;
          height: 12px;
          background: #ff3f81;
          border-radius: 50%;
          margin-left: -6px;
          box-shadow: 0 0 8px rgba(255, 63, 129, 0.5);
          display: none;
        }
      }
    }

    // 底部控制栏样式
    .video-footer-tool {
      height: 56px;
      width: 100%;
      display: flex;
      justify-content: space-between;
      align-items: center;
      background: #16110c;
      padding: 0 24px;

      .icon-1,
      .icon-2,
      .icon-3 {
        width: 14.22px;
        height: 16px;
        margin-right: 24px;
        cursor: pointer;
        object-fit: contain;
      }

      .icon-3 {
        width: 16px;
        margin-right: 0;
      }

      .icon-4 {
        width: 18px;
        height: 18px;
        cursor: pointer;
      }

      p {
        font-family: PingFang SC, PingFang SC;
        font-weight: 500;
        font-size: 14px;
        color: #ffffff;
        span {
          color: rgba($color: #ffffff, $alpha: 0.65);
        }
      }

      // 音量控制样式
      .volume-container {
        display: flex;
        align-items: center;
        margin-right: 24px;
        .hover-mute-content {
          width: 68px;
          height: 6px;
          border-radius: 24px;
          background: rgba(255, 255, 255, 0.37);
          cursor: pointer;
          position: relative;
          display: none;
          margin-left: 24px;
          .hover-mute-content-value {
            position: absolute;
            top: 0;
            left: 0;
            width: 50%;
            height: 100%;
            background: #ffffff;
            border-radius: 24px;
            transition: width 0.1s;

            &::after {
              content: "";
              position: absolute;
              right: 0;
              top: 50%;
              transform: translateY(-50%);
              width: 12px;
              height: 12px;
              background: #ffffff;
              border-radius: 50%;
              box-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
            }
          }
        }
      }
      .volume-container:hover {
        width: calc(72px + 68px - 24px);
        max-width: calc(72px + 68px - 24px);
        .hover-mute-content {
          display: block;
        }
      }
    }
  }
}

// 全屏模式样式
.video-dialog-full-screen {
  :deep(.el-dialog) {
    width: 100%;
    height: 100%;
    --el-dialog-border-radius: 0;
    background: transparent;
    border-radius: 0;

    .video-content {
      width: 100%;
      height: calc(100vh - 56px);
      video {
        max-width: 100%;
        max-height: 100%;
        height: 100%;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        object-fit: contain;
        z-index: 2;
      }
    }
  }
}
</style>

DataUrl  Icon文件
新建或者自定义一个相关文件,将以下ICON.base64代码引入,这边用的是js文件

const dataUrl = {
    "ErrorIcon": ``,    "ZanIcon":`data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAAXNSR0IArs4c6QAAAjdJREFUSEu9lb2O00AUhe/ZH1Z2sOQNsWhSUKRyqpVfwC7SQ+EaqNPAE2DeAJ4A+jTwBPgBUqRKFQkKd5FgkRWH3Q2+5BrbOMbC+TEZKYo947nfnLln7oCO2HBEFm0NY+Z3RPSMiHwieg7gy64L3QrGzDYRfSoEvyaiq12B28IyVUUxbwG82EVdLYyZHxHR54qgPgCnaViVKmE0C0tVSa5EXbk1DhP3ibKqJiaZlAak7yOA94X+EyKK5f2fOWNmyVWVqrpUvQTwRj6yLOt8PB6vAPAGjJlfEZE4TK+LVjN+DeBSvul0OprjONFoNPqZw1KQdyAknw4gia1pWicMQ9neVRGWbZkDwGdmAYvSfdoEwJVMbLVaDxeLxVciuivCOEliuqIDYWKSx8eCvV6vOUmJpmkPLMv67vv+xjY2qewJgA8C03VdHwwGYdkgTcKSvAvMMIz7w+Ew8jwv/l85u1wXaXEgdbtdJQiCH2uz/Tlna+s3pSw/YwLr9XoXs9nsZqOCMPO39DDLPTU5wI3lmnmPiG7LsEPOVfEsyi2e10bbts/EiX/VRmaWevZ0z3IlOZILdaMKua57Kk6sLcT7lI7yHGaWOvHbD00E3DZGESb3zrn8NE27CMPwjIhOFUXBcrlM4imKIuWMoyiCqqpi4GQs7Y+jKFq12+0bVVXvgiC4ZeY4U1WlDK7rnsznc/i+D9M088VMp1MyTTOBZs/yL0365dm27dgwDO73++x5nmxdsn1ZO+o2/gKK/QUrGuu3NgAAAABJRU5ErkJggg==`,
    "PingIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAALlJREFUSEvtld0NgzAMhM8blA3KZt2kZRM2Kxu0GxwxSioURcqVEvqCJV5OyF/8b2hs1tg/FgDJJ4DrzrDJzPoE4M7OF3fmFiM4AcUM/z1FbwD+rbtL1aQi9xHwWsWvanVAqcNULT2oVoMOwAWAD2EyVatHAGCKAIckUzUJ8PNw11J0Ao5ddm3vQV5Nko9wh+6ZPoYVP5iZt6psxZOZATY5/kxz6SkkfcHdwqIbv31x7u+Yoy8ndMOPM/JLdRkQa0DJAAAAAElFTkSuQmCC`,
    "LookEyeIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAU1JREFUSEvFVQtRw1AQ3HWABFAAOKAKGBQACmgV0DpoFVAUgAPigKKASqiDI8vcg7R5nySdwM1kJp93t2/33V6IkYMj18f/A5jZKYBbAHcAdK/Y+LUguc2pkGRgZicAHgFMCzLOSS5Sa6IAvusXABcdz0gsJjE2LQAv/taQoyMGoiB7AEcUD5togRwCvGdkqQB8eKXrDMMNycuA+ANgZjrQeUIPdcveNzPTs3JisSQ504dvADO7AiDdY7Eleebr1KogufZn5Sg3Fjr0KgB8ZiivSE7NTMWfvNK9QOpWXgJ4yG3szwByElUkJwmJcsx/JfLkHN2WW7s2RZ82VY+/ut5yeOpw423qLDTMhri4m9GOBCmPirCNASND4/um07Br9nTBrWHpShOg9sou5ofiH83ZaCycN+aU5Hiuzbke/MNJuLP36yKD3hUPEkYH+AKsa5kZ8eiKFwAAAABJRU5ErkJggg==`,
    "CloseRadiuIcon": `data:image/png;base64,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`,
    "PauseIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAhCAYAAADOHBvaAAAAAXNSR0IArs4c6QAAAMtJREFUWEdjZBggwIhs761btwwYGRkFkMVYWFgeKCoqPiDHfffv3xf48+ePAbpeVVXVA3CLb926dZ6BgQFDEUjTv3//CjU0NCaQYvnNmzcDGBkZ1+PQcwFs8e3btx3+//+/H4/BB9TU1BxJsfjWrVsg8xxw6Rm1GFfIjAY1wXQ2mrjQg2g0O41mJ1gIjBYgowUIRgiMFpmjReZoJTFaSYxWEgQrB5iCwV1kQruT9////4/SRUXy3gI1NbVEor3LwMBw69YtUO8yH5ceADqDdhRm0VQiAAAAAElFTkSuQmCC`,
    "PlayZIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAYAAADud3N8AAAAAXNSR0IArs4c6QAAARpJREFUSEvd1t0NgjAQwHEuAZ5doQ+lMI4jOIG6AZ1A3QA3cATmgJC4gSzQnoGIUcNHC1ce7HOTX67/hytUVbXXWqeIWCPiUQhx8xwfKIoCf4wsCALJGLu7svvQ1gKA1Pf9qwt8EH1N2UwroyjKKKeeQjvrDgA7znlOgZuinUXS2xYl6T0LXdp7CTq7NwVq3ZsSNe5Njpr0doWO9naN9vZeC3335pzLVdFGRsTtf6MAUGutL0KIdK1Jc6XULkmS9mPgGs0BQP6uRCdo85RKKRnH8blv/5KiXbcwDM+MsXpo4VOiX93GfhgUaG83J+hUN1LUtBslatyNArXuNhtd0s0apeg2ipZl+UDEzcclkm5T6AERT57nkXYbQ59nnvPXuWPpvAAAAABJRU5ErkJggg==`,
    "PlayNextIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAYAAADud3N8AAAAAXNSR0IArs4c6QAAAZNJREFUSEvV18ttwkAQANAZy+tzSogPtuBGCUkHSQehAuQO7A6gglACHcQdhCtYlinBd38mGhRHRmziZT9I2RMCvI8dZsZjBACoquohDMOaX7tYZVmu+r5Piaj2PC/F4/G4AIBPADgBQBbH8dYmXFXVomka3n9YNaNvAPA+enMrhMjCMOQfYbyKongioo/xRjKUP6/7vs9ms9naVL0FHSw+7Wscx3tdXAcdLO2Qm6CMayWaKfoTciHEs2qi2UIHfC2E2EzhtlGlkLtAz6cmol0QBIns1M7QId6ImEZRlI3Lyzn6jV1k+b3Qi9pu2/ZRtQ3qNqCr6xBxR0QvKr3XGirb6LeG/39RROTBIL9nePOu65a+798lkU6IuIyiKOf/yHnJEFEWBMF6PG+5RM+hnM/nVyOOdZQThYiSv4Y52+hGCJFOja620BwRsyFRpgraCOVQdl1384RogiqFUnZqHXSPiIlqKI1Q3VBqo3wrats2kdXcVNIoo6OYX7QvHUB2jeQBCpC/6PpR8XA4pJ7nrdjiCvgCWcuQkZ35fVAAAAAASUVORK5CYII=`,
    "MuteIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAhCAYAAAC4JqlRAAAAAXNSR0IArs4c6QAAA7dJREFUWEfFV11S2zAQ1or4nZ6geIbI8FQ4QckJCicoOQHNCZKcAHIC4ATACUhPQHhiLME4NyB9dqxtVmN5ZEXOD2WmfshDoux+2v2+b9fA/vMD/5pfSnkURdEsjuPpR2J9GECWZbvz+byPiL8oMQB02u32eFsQFQClVF9rfQ4A4yiKenEcz5qCZVm2l+f5HWPsyDkzEkIYMNs8BsDr6+up1poCmgcR75MkOQsFUkqdIOI1Y2zP+/1GCNHdJrmpHH1IKc8ZYxS0egBg0G63h+53b29vF0VRXDUk+TgA6mee549eSZnWundwcGASKqUubb8/HQAFfHl52dvZ2SEQtdISuRhjF4h4uqa8wQqkaXrKOb+mtkZRNPTVUlMBSQoAHhFx10k2AwDiw533vY8nCEBKSZc6KQ9PoyjquCCWZBjiA2NsCgBdRKRgTU8QgFLqFyJeOn8iEMdWZUEfSNN0AAB9L9MYAB68YO6RRhL68VyVWRVQ6U3ZEbFPXoCIX6j3HogrRPwTAEfHVqrAB2GNC8iAEHHg15Vzfq61JmNxzcYoY0HW7wFSVgCojQDwrdVqjdx+K6WIR5bMYyFEB6SU2NDUGSJ2AYD6V1MGIp6VVXDBGQBZlh3lef7kkK7qNymt1Wo9WTJTFVYBoBiGfAEFGGV4jmgBkKe820sh4jBJkqrCUkryFdva0ToAFGfCOR+6Vm1vt+BDr9Q48adqgcf8WRRFsWW9Z/uTTQAYgi1u/BxQwIQxNiptvEZCpdS74xtdIcSNY3hZeYnZpgBo3A7WKOOrO4w8A6oAUGKXdxsDoD+SAjjnPxxnMxchcIyx3+4+0ASgnDsVR7YCUCbrhMYxyXZ/f/+WzpT7gi0zfXUshKB20VCjcW4ddWMOuEptVMaiCh1KJKWk5Fa6UyFEbAO4BNVaP2xdAasAznkvpAxftkVRxIeHh9W+6IHrEgAX7YpZs/RT02yYAMAtKSbgAbXFh8BB6U50eBcAaA+kHrnjeBUoMhWaJ/7MWJoLxIv5fF65oPWNpWnYtJg0oVilDLvSlaR0l51pURQdak1wHDtVWbcFGVzlbFiaGeVAeyYrd+cJnU+S5N6oalV9G/aC0F9Cs4HOLQ00nxdrX0wCG00TZrJasmU7Ce25SrZFUQztkmt/XAugtE4au7UyBlAY4jWsdJNyF1x62dkIgDNElrZmB0jF/IbWBTemjQE4IPxXMouhliBNU5qgP91KueTbqgV+ub2lIggg9LLzaQAoY6DMtZEbaJvZAf3L/AVCj3VLrOF/ZQAAAABJRU5ErkJggg==`,
    "YlIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAgCAYAAACcuBHKAAAAAXNSR0IArs4c6QAAAnNJREFUWEfllsFx6jAQhiVsc3YJ+MB6uL10gDsgFSSpIOkgpIK8VJB0kHTw6CDcGEswpoNwxpjNrEdiZI3tyGHM5emWIFmf9P/a/Tk7c2RZNsrz/JUxNkXE6ziOP7p+knddYM5P03Q2GAxeETFU/18AQNL1m7+GkFI+IuLc3hAAOn+z84Isy8I8z58ZY7d1J+4dQun/jzE2arryXiGklFPG2Luhfy1HEwTJxxgLfd9/iaJoay52kmOz2dwXRfHXxXB1EEIIko5eEI1tEASJCdIK8ZP+rp5Yr9ez4/H4bsyvgDRCKP1p4R+XG9BzmuRI03TOOSdJ9FgCwBX9UQshhKCNCaDRgL8xppTyARHpZZUDEZ/iOJ6XEGbV63LqNjlIyv1+Px0Oh0tTfyEEeeterd0FQRCVENYPZ3FoOaSU9JJmthGVzz71LdNtlBBpmr5xzm/O2l0t1hBCiMyQs1LOLVkWvUHYL4JznozH44WSn6rulz50bxBKZqquVORovAHAnd5YCEGSlC+vbwizSFUkEUKcAP8LCCrVutu+AMDDReWw+gWzjElpjF5POXqTwzQeIn7EcXxt3ILplWWfENp426IokslkcmrfVg25KyFWq9XI87zWsOJayMwGRrXC87xFFEU7vd6MhZzz3eFwuKptYOdAtSUrO5dUGljdKQnE9/1nVf9dL4K1JSsrGG8BIDoZs22HmhzQClQHURdqTJ84xTs7B7RRuMQ726hOEKoPOAWdH5JVGATB3DSqkxzmqV0M22vk1zAqlFD0092xos5FIIyqZ8a0E8hFIWjXtgTt/Kab0naXD6hG9cg5DxExAYBll/U09xtsmJNzr7Qi0AAAAABJRU5ErkJggg==`,
    "UnFdIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAAXNSR0IArs4c6QAAAadJREFUWEftWN1RwkAQ3h3IOyWQhwR4ix1AB1qCHWgFQgWOFVgCYwXQgXljcvdwdGCeScjKOsbJREz2wMzocPd6e9lvv9x9+4MgXMaYYZZlSwCIEHEeBMGi6ajW+gEA7ogo9Txv5vv+VuIKJUZso5RaAcC0Yn8VhmF87LwxJsqy7LXcK4riZTweX0t8nQwIEWdBEKyPOdFaT4mIAyjXOgzDmQNUMuAYYibcHaq/iPqzvxyGWIF3u90jIg6adAIRIyL6srFkKAWAoyJa9el53i0qpQwADCWiVbWxBCT9fIxa67dq5NKTHQECTJJkjoicCK1WF4CIaPGRy5RSnMEb71Adbb/fj33f57vxbRljBnmeRzYRclXAyVqcXG0+fo6tA9TGnmPofzL0p549dwdENG+jsr7fhTByN8O5jGzBnFCgSV2kDIjbFStV7RDQFjebzbDX6z23hXBO+YGIKRE1lh9sk+f5vViHLrdibPtV5b5jqI0px5Bj6AcGxDqktV4exK06dBIPrA6Drt+fD30q+oqbgaIonkajUWNCrnQz8X6/v5lMJqKR3jvTkq+FkbX/lwAAAABJRU5ErkJggg==`,
    "FdIcon": `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAAXNSR0IArs4c6QAAAg5JREFUWEftWMtxwjAQlQD7TAn4gIAbdBA6SCpIqCChEpIKQiqADkIH4caMBGOX4LuRNlmPbBzQGAnyIRnraO2unp6lXe2j5EIHNeEKw7CVJMmVaQ4AYt/3l0EQRC57CsOwmSTJtW3MT8A0oGdCiBFUIWjked4gCILYBpyO+0oIaZXZA8Dc9/0xbjoHZutcCDxijE1tgK3X62ul1MzGlhCCmx7mwIQQMwAwUm0KSCkdttvthc1iQogrAEDGbMciBabZCotelNJYKXXwq/T3l263+2i7CtoJIR4A4BYAmvt+tVqtuf89BWagOpZSDnq9ntMBdwFatF2tVq1Go/FWBJcC45zfEULw0GcjYowFpy50ih/nHP9YfjkqYMdYrBg7xtD+vC1jS8bYwDX4Ofac8zdCSD+LkeUxrGM4kd4KpdTYNU+dA6qQ5yY6zq4kYS7xPK+PRdo2o58LZt9fVwjEMTe+Lr56wVPiVcBcWasYqxhzZcDVvjpj/4+xrO+jlEa/WZKUUk3sW4vNSN73XUwRNzQjl/HsqZqRkqtp+4Kt2reMxD/PWKxlph+RCFA72W63hxIBvvfr9bq1qPLRtEwZY08uZWaz2dxLKe+cRBWtX2CCPSbY5Vi+U4ZCAS9/XWjWjqp+GTIAuOl0OnMb1gx5sswtklLuhDu01HLQxELAS51tZSpdh/O+tQTVQko5wrjvF5yGMz+76SwAAAAASUVORK5CYII=`,
}

export default dataUrl


网站公告

今日签到

点亮在社区的每一天
去签到