+
60
-

回答

参考这个

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>时间轴剪辑播放器</title>
  <style>
    body {
      font-family: sans-serif;
      margin: 20px;
    }

    #preview {
      width: 600px;
      height: 340px;
      background: #000;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    #preview img, #preview video {
      max-width: 100%;
      max-height: 100%;
    }

    #timelineWrapper {
      position: relative;
      width: 100%;
      margin-top: 20px;
      overflow-x: auto;
    }

    #timeline {
      display: flex;
      height: 100px;
      border: 2px dashed #ccc;
      padding: 10px;
      position: relative;
      min-width: 600px;
    }

    .clip {
      width: 100px;
      height: 80px;
      margin-right: 5px;
      border: 1px solid #999;
      background-size: cover;
      background-position: center;
      position: relative;
    }

    #pointer {
      position: absolute;
      width: 2px;
      background: red;
      top: 0;
      bottom: 0;
      left: 0;
      cursor: ew-resize;
    }

    #controls {
      margin-top: 20px;
    }

    button {
      margin-right: 10px;
    }
  </style>
</head>
<body>

<h2>剪辑时间轴播放器</h2>

<div id="preview"></div>

<div id="timelineWrapper">
  <div id="timeline" ondragover="event.preventDefault()" ondrop="handleDrop(event)">
    <div id="pointer"></div>
  </div>
</div>

<div id="controls">
  <button onclick="playSequence()">播放</button>
  <button onclick="pauseSequence()">暂停</button>
  <button onclick="stopSequence()">停止</button>
</div>

<script>
  const timeline = document.getElementById('timeline');
  const pointer = document.getElementById('pointer');
  const preview = document.getElementById('preview');

  let clips = [];
  let totalDuration = 0;
  let currentIndex = 0;
  let currentTime = 0;
  let isPaused = false;
  let isStopped = false;
  let pointerInterval = null;

  function handleDrop(event) {
    event.preventDefault();
    const files = Array.from(event.dataTransfer.files);

    files.forEach(file => {
      const url = URL.createObjectURL(file);
      const ext = file.name.split('.').pop().toLowerCase();
      let type = '';

      if (['mp4', 'webm', 'ogg'].includes(ext)) {
        type = 'video';
        const video = document.createElement('video');
        video.src = url;
        video.addEventListener('loadedmetadata', () => {
          const duration = video.duration;
          addClip(type, url, duration);
        });
      } else if (['png', 'jpg', 'jpeg', 'gif'].includes(ext)) {
        type = 'image';
        addClip(type, url, 5); // 图片固定播放 5s
      }
    });
  }

  function addClip(type, src, duration) {
    clips.push({ type, src, duration });

    const div = document.createElement('div');
    div.className = 'clip';
    if (type === 'image') {
      div.style.backgroundImage = `url(${src})`;
    } else {
      div.style.background = '#333 url(play-icon.png) center center no-repeat';
    }
    timeline.appendChild(div);

    updateTotalDuration();
  }

  function updateTotalDuration() {
    totalDuration = clips.reduce((sum, clip) => sum + clip.duration, 0);
  }

  function playSequence(startTime = 0) {
    if (clips.length === 0) return;

    isPaused = false;
    isStopped = false;

    // 如果是从中间跳转
    if (startTime > 0) {
      [currentIndex, currentTime] = findClipByGlobalTime(startTime);
    }

    startPointerAnimation(startTime);
    playClipAt(currentIndex, currentTime);
  }

  function pauseSequence() {
    isPaused = true;
    const video = preview.querySelector('video');
    if (video) video.pause();
    clearInterval(pointerInterval);
  }

  function stopSequence() {
    isStopped = true;
    clearInterval(pointerInterval);
    preview.innerHTML = '';
    currentIndex = 0;
    currentTime = 0;
    pointer.style.left = `0px`;
  }

  function findClipByGlobalTime(globalTime) {
    let time = 0;
    for (let i = 0; i < clips.length; i++) {
      const next = time + clips[i].duration;
      if (globalTime < next) {
        return [i, globalTime - time];
      }
      time = next;
    }
    return [clips.length - 1, 0];
  }

  function playClipAt(index, offset = 0) {
    if (index >= clips.length || isStopped) return;

    const clip = clips[index];
    preview.innerHTML = '';

    if (clip.type === 'image') {
      const img = document.createElement('img');
      img.src = clip.src;
      preview.appendChild(img);
      setTimeout(() => {
        if (!isPaused && !isStopped) {
          currentIndex++;
          playClipAt(currentIndex);
        }
      }, (clip.duration - offset) * 1000);
    } else if (clip.type === 'video') {
      const video = document.createElement('video');
      video.src = clip.src;
      video.autoplay = true;
      video.controls = false;
      video.currentTime = offset;
      preview.appendChild(video);

      video.onended = () => {
        if (!isPaused && !isStopped) {
          currentIndex++;
          playClipAt(currentIndex);
        }
      };
    }
  }
function startPointerAnimation(startAt = 0) {
  const timelineWidth = timeline.scrollWidth;

  pointerInterval = setInterval(() => {
    if (isPaused || isStopped) return;

    // 计算当前总播放时间
    let elapsed = 0;
    for (let i = 0; i < currentIndex; i++) {
      elapsed += clips[i].duration;
    }
    const video = preview.querySelector('video');
    if (video) {
      elapsed += video.currentTime;
    } else {
      elapsed += currentTime;
    }

    if (elapsed >= totalDuration) {
      clearInterval(pointerInterval);
      return;
    }

    pointer.style.left = `${(elapsed / totalDuration) * timelineWidth}px`;
  }, 50);
}

pointer.addEventListener('mousedown', (e) => {
  e.preventDefault();
  clearInterval(pointerInterval);
  isPaused = true;

  const rect = timeline.getBoundingClientRect();

  const onMove = (moveEvent) => {
    let x = moveEvent.clientX - rect.left;
    x = Math.max(0, Math.min(x, timeline.scrollWidth));
    pointer.style.left = `${x}px`;
  };

  const onUp = (upEvent) => {
    let x = upEvent.clientX - rect.left;
    x = Math.max(0, Math.min(x, timeline.scrollWidth));
    const percent = x / timeline.scrollWidth;
    const jumpTime = percent * totalDuration;

    document.removeEventListener('mousemove', onMove);
    document.removeEventListener('mouseup', onUp);

    stopSequence(); // 先停止
    playSequence(jumpTime); // 再跳转播放
  };

  document.addEventListener('mousemove', onMove);
  document.addEventListener('mouseup', onUp);
});

</script>

</body>
</html>

网友回复

我知道答案,我要回答