Files
rrweb/src/Controller.html
2026-04-01 12:00:00 +08:00

237 lines
5.9 KiB
HTML

{#if showController}
<div class="rr-controller">
<div class="rr-timeline">
<span class="rr-timeline__time">{formatTime(currentTime)}</span>
<div class="rr-progress">
<div class="rr-progress__step" ref:step style="width: {percentage}"></div>
<div
class="rr-progress__handler"
ref:handler
style="left: {percentage}"
></div>
</div>
<span class="rr-timeline__time">{formatTime(meta.totalTime)}</span>
</div>
<div class="rr-controller__btns">
<button on:click="toggle()">
{#if isPlaying}
<svg
t="1541411313529"
class="icon"
style=""
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16"
>
<path
d="M682.65984 128q53.00224 0 90.50112 37.49888t37.49888 90.50112l0 512q0 53.00224-37.49888 90.50112t-90.50112 37.49888-90.50112-37.49888-37.49888-90.50112l0-512q0-53.00224 37.49888-90.50112t90.50112-37.49888zM341.34016 128q53.00224 0 90.50112 37.49888t37.49888 90.50112l0 512q0 53.00224-37.49888 90.50112t-90.50112 37.49888-90.50112-37.49888-37.49888-90.50112l0-512q0-53.00224 37.49888-90.50112t90.50112-37.49888zM341.34016 213.34016q-17.67424 0-30.16704 12.4928t-12.4928 30.16704l0 512q0 17.67424 12.4928 30.16704t30.16704 12.4928 30.16704-12.4928 12.4928-30.16704l0-512q0-17.67424-12.4928-30.16704t-30.16704-12.4928zM682.65984 213.34016q-17.67424 0-30.16704 12.4928t-12.4928 30.16704l0 512q0 17.67424 12.4928 30.16704t30.16704 12.4928 30.16704-12.4928 12.4928-30.16704l0-512q0-17.67424-12.4928-30.16704t-30.16704-12.4928z"
></path>
</svg>
{:else}
<svg
t="1541410561137"
class="icon"
style=""
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16"
>
<path
d="M170.65984 896l0-768 640 384zM644.66944 512l-388.66944-233.32864 0 466.65728z"
></path>
</svg>
{/if}
</button>
{#each [1, 2, 4, 8] as s}
<button class:active="s === speed" on:click="setSpeed(s)">{s}x</button>
{/each}
</div>
</div>
{/if}
<script>
import { formatTime } from './utils.js';
export default {
data() {
return {
currentTime: 0,
isPlaying: false,
speed: 1,
};
},
computed: {
meta({ replayer }) {
return replayer.getMetaData();
},
percentage({ currentTime, meta }) {
const percent = Math.min(1, currentTime / meta.totalTime);
return `${100 * percent}%`;
},
},
helpers: {
formatTime,
},
methods: {
loopTimer() {
const now = performance.now();
let lastStep = now;
const self = this;
function update(step) {
let { currentTime, meta, isPlaying, speed } = self.get();
if (!isPlaying) {
return;
}
const stepDiff = Math.floor(step - lastStep);
lastStep = step;
currentTime += speed * stepDiff;
self.set({
currentTime: Math.min(currentTime, meta.totalTime),
});
if (currentTime < meta.totalTime) {
requestAnimationFrame(update);
} else {
self.set({ isPlaying: false, currentTime: 0 });
}
}
requestAnimationFrame(update);
},
play() {
const { replayer, currentTime } = this.get();
if (currentTime > 0) {
replayer.resume(currentTime);
} else {
replayer.play(currentTime);
}
},
pause() {
const { replayer } = this.get();
replayer.pause();
},
toggle() {
const { isPlaying } = this.get();
if (isPlaying) {
this.pause();
} else {
this.play();
}
},
setSpeed(speed) {
const { replayer } = this.get();
replayer.setConfig({ speed });
this.set({ speed });
},
},
onupdate({ changed, current, previous }) {
if (current.replayer && !previous) {
// auto play
this.set({ isPlaying: true });
this.play();
current.replayer.on('pause', () => {
this.set({ isPlaying: false });
});
current.replayer.on('resume', () => {
this.set({ isPlaying: true });
});
}
if (changed.isPlaying) {
if (current.isPlaying) {
this.loopTimer();
}
}
},
ondestroy() {
const { isPlaying } = this.get();
if (isPlaying) {
this.pause();
}
},
};
</script>
<style>
.rr-controller {
width: 100%;
height: 80px;
background: #fff;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
border-radius: 0 0 5px 5px;
}
.rr-timeline {
width: 80%;
display: flex;
align-items: center;
}
.rr-timeline__time {
padding: 0 20px;
color: #11103e;
}
.rr-progress {
width: 100%;
height: 4px;
background: #eee;
position: relative;
border-radius: 3px;
}
.rr-progress__step {
height: 100%;
position: absolute;
left: 0;
top: 0;
background: #e0e1fe;
}
.rr-progress__handler {
width: 20px;
height: 20px;
border-radius: 10px;
position: absolute;
top: 2px;
transform: translate(-50%, -50%);
background: rgb(73, 80, 246);
}
.rr-controller__btns {
display: flex;
}
.rr-controller__btns button {
width: 32px;
height: 32px;
display: flex;
padding: 0;
align-items: center;
justify-content: center;
background: none;
border: none;
border-radius: 50%;
cursor: pointer;
}
.rr-controller__btns button:active {
background: #e0e1fe;
}
.rr-controller__btns button.active {
color: #fff;
background: rgb(73, 80, 246);
}
</style>