手搓提词器网页版,有些BUG但是基本功能使用没有问题,有需要的可复制粘贴,BUG自行修复。下面直接进入代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>提词器</title>
<style>
:root {
--primary-color: #1e88e5;
--secondary-color: #26c6da;
--danger-color: #f44336;
--success-color: #66bb6a;
--dark-bg: #121212;
--darker-bg: #0a0a0a;
--light-text: #f5f5f5;
--lighter-text: #ffffff;
--highlight-color: #ffeb3b;
--highlight-bg: rgba(30, 136, 229, 0.2);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Arial', sans-serif;
background-color: var(--dark-bg);
color: var(--light-text);
line-height: 1.6;
padding: 20px;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.container {
max-width: 1200px;
margin: 0 auto;
width: 100%;
flex: 1;
display: flex;
flex-direction: column;
}
h1 {
text-align: center;
margin-bottom: 20px;
color: var(--lighter-text);
text-shadow: 0 0 10px rgba(30, 136, 229, 0.5);
}
.editor-panel {
background-color: var(--darker-bg);
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
margin-bottom: 20px;
}
.control-panel {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 15px;
}
.control-group {
display: flex;
flex-direction: column;
}
label {
margin-bottom: 8px;
font-weight: bold;
color: var(--secondary-color);
}
textarea {
width: 100%;
min-height: 200px;
padding: 12px;
background-color: #1e1e1e;
color: var(--light-text);
border: 1px solid #333;
border-radius: 4px;
resize: vertical;
font-family: inherit;
font-size: 16px;
margin-bottom: 15px;
}
select, input[type="range"] {
width: 100%;
padding: 8px;
background-color: #1e1e1e;
color: var(--light-text);
border: 1px solid #333;
border-radius: 4px;
}
.range-container {
display: flex;
align-items: center;
gap: 10px;
}
.range-value {
min-width: 30px;
text-align: center;
}
.button-group {
display: flex;
gap: 10px;
margin-top: 15px;
flex-wrap: wrap;
}
button {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
flex: 1;
min-width: 120px;
}
.btn-play {
background-color: var(--success-color);
color: white;
}
.btn-pause {
background-color: var(--danger-color);
color: white;
display: none;
}
.btn-fullscreen {
background-color: var(--primary-color);
color: white;
}
.btn-reset {
background-color: #616161;
color: white;
}
button:hover {
opacity: 0.9;
transform: translateY(-2px);
}
button:active {
transform: translateY(0);
}
.teleprompter-container {
flex: 1;
display: flex;
flex-direction: column;
background-color: #000;
border-radius: 8px;
overflow: hidden;
position: relative;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}
.teleprompter-display {
flex: 1;
overflow: hidden;
position: relative;
padding: 20px;
}
.teleprompter-viewport {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.teleprompter-text {
width: 100%;
text-align: center;
transition: transform 0.1s linear;
color: var(--light-text);
}
.word {
transition: all 0.3s ease;
display: inline-block;
margin: 0 3px;
padding: 2px 4px;
border-radius: 3px;
}
.highlight {
color: var(--highlight-color);
background-color: var(--highlight-bg);
font-weight: bold;
transform: scale(1.3);
text-shadow: 0 0 10px rgba(255, 235, 59, 0.7);
position: relative;
z-index: 1;
}
.highlight::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: -10px;
height: 2px;
background-color: var(--highlight-color);
opacity: 0.5;
z-index: -1;
}
/* 全屏样式 */
.fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: #000;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
margin: 0;
}
.fullscreen .teleprompter-display {
width: 100%;
height: 100%;
}
.fullscreen .teleprompter-text {
font-size: 3em !important;
}
/* 响应式调整 */
@media (max-width: 768px) {
.control-panel {
grid-template-columns: 1fr;
}
.teleprompter-display {
padding: 10px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>提词器</h1>
<div class="editor-panel">
<textarea id="prompterText" placeholder="在这里输入您的提词内容...">欢迎使用提词器</textarea>
<div class="control-panel">
<div class="control-group">
<label for="fontFamily">字体选择</label>
<select id="fontFamily">
<option value="Arial, sans-serif">Arial</option>
<option value="'Microsoft YaHei', sans-serif">微软雅黑</option>
<option value="'SimSun', serif">宋体</option>
<option value="'Times New Roman', serif">Times New Roman</option>
<option value="'Courier New', monospace">Courier New</option>
</select>
</div>
<div class="control-group">
<label for="fontSize">字号大小</label>
<div class="range-container">
<input type="range" id="fontSize" min="12" max="72" value="24">
<span class="range-value" id="fontSizeValue">24</span>px
</div>
</div>
<div class="control-group">
<label for="speed">滚动速度</label>
<div class="range-container">
<input type="range" id="speed" min="1" max="100" value="50">
<span class="range-value" id="speedValue">50</span>
</div>
</div>
</div>
<div class="button-group">
<button id="playBtn" class="btn-play">开始</button>
<button id="pauseBtn" class="btn-pause">暂停</button>
<button id="fullscreenBtn" class="btn-fullscreen">全屏</button>
<button id="resetBtn" class="btn-reset">重置</button>
</div>
</div>
<div class="teleprompter-container">
<div class="teleprompter-display">
<div class="teleprompter-viewport">
<div id="teleprompterText" class="teleprompter-text"></div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取DOM元素
const prompterText = document.getElementById('prompterText');
const teleprompterText = document.getElementById('teleprompterText');
const fontFamily = document.getElementById('fontFamily');
const fontSize = document.getElementById('fontSize');
const fontSizeValue = document.getElementById('fontSizeValue');
const speed = document.getElementById('speed');
const speedValue = document.getElementById('speedValue');
const playBtn = document.getElementById('playBtn');
const pauseBtn = document.getElementById('pauseBtn');
const fullscreenBtn = document.getElementById('fullscreenBtn');
const resetBtn = document.getElementById('resetBtn');
const teleprompterContainer = document.querySelector('.teleprompter-container');
const viewport = document.querySelector('.teleprompter-viewport');
// 状态变量
let isPlaying = false;
let scrollInterval;
let words = [];
let currentWordIndex = 0;
let wordElements = [];
let wordPositions = [];
let viewportHeight = 0;
let centerPosition = 0;
// 初始化
updateTeleprompterText();
calculatePositions();
// 事件监听
prompterText.addEventListener('input', updateTeleprompterText);
fontFamily.addEventListener('change', updateTeleprompterStyle);
fontSize.addEventListener('input', function() {
fontSizeValue.textContent = this.value;
updateTeleprompterStyle();
setTimeout(calculatePositions, 100); // 等待渲染完成
});
speed.addEventListener('input', function() {
speedValue.textContent = this.value;
if (isPlaying) {
clearInterval(scrollInterval);
startScrolling();
}
});
playBtn.addEventListener('click', startScrolling);
pauseBtn.addEventListener('click', pauseScrolling);
fullscreenBtn.addEventListener('click', toggleFullscreen);
resetBtn.addEventListener('click', resetTeleprompter);
// 窗口大小变化时重新计算位置
window.addEventListener('resize', function() {
calculatePositions();
updateHighlightPosition();
});
// 键盘快捷键
document.addEventListener('keydown', function(e) {
// 空格键 播放/暂停
if (e.code === 'Space') {
e.preventDefault();
if (isPlaying) {
pauseScrolling();
} else {
startScrolling();
}
}
// ESC键 退出全屏
if (e.code === 'Escape' && teleprompterContainer.classList.contains('fullscreen')) {
toggleFullscreen();
}
// 上箭头 减速
if (e.code === 'ArrowUp') {
e.preventDefault();
speed.value = Math.min(100, parseInt(speed.value) + 5);
speed.dispatchEvent(new Event('input'));
}
// 下箭头 加速
if (e.code === 'ArrowDown') {
e.preventDefault();
speed.value = Math.max(1, parseInt(speed.value) - 5);
speed.dispatchEvent(new Event('input'));
}
});
// 更新提词器文本
function updateTeleprompterText() {
const text = prompterText.value;
words = splitTextIntoWords(text);
renderWords();
updateTeleprompterStyle();
calculatePositions();
}
// 将文本分割为单词数组
function splitTextIntoWords(text) {
// 使用正则表达式分割单词和标点符号
return text.split(/(\s+|\n+|[,.!?;:])/).filter(word => word.trim().length > 0);
}
// 渲染单词
function renderWords() {
teleprompterText.innerHTML = '';
wordElements = [];
words.forEach((word, index) => {
const wordSpan = document.createElement('span');
wordSpan.className = 'word';
wordSpan.textContent = word;
wordSpan.dataset.index = index;
// 处理空格和换行
if (word.match(/\s+/)) {
wordSpan.style.padding = '0 2px';
if (word.includes('\n')) {
wordSpan.style.display = 'block';
wordSpan.style.height = '1em';
wordSpan.style.content = ' ';
}
}
teleprompterText.appendChild(wordSpan);
wordElements.push(wordSpan);
});
// 重置高亮
currentWordIndex = 0;
updateHighlightPosition();
}
// 计算所有单词的位置
function calculatePositions() {
viewportHeight = viewport.clientHeight;
centerPosition = viewportHeight / 2;
wordPositions = [];
// 临时显示所有元素以计算位置
teleprompterText.style.transform = 'translateY(0)';
// 计算每个单词的绝对位置
let currentTop = 0;
wordElements.forEach((wordEl, index) => {
const rect = wordEl.getBoundingClientRect();
const viewportRect = viewport.getBoundingClientRect();
const relativeTop = rect.top - viewportRect.top;
wordPositions[index] = relativeTop;
// 如果是换行元素,增加额外高度
if (wordEl.textContent.includes('\n')) {
currentTop += rect.height;
}
});
}
// 更新高亮单词位置
function updateHighlightPosition() {
// 移除所有高亮
wordElements.forEach(word => {
word.classList.remove('highlight');
});
if (words.length > 0 && currentWordIndex < words.length) {
// 计算需要滚动到的位置,使当前词居中
const targetPosition = centerPosition - wordPositions[currentWordIndex];
// 应用滚动位置
teleprompterText.style.transform = `translateY(${targetPosition}px)`;
// 高亮当前词
wordElements[currentWordIndex].classList.add('highlight');
}
}
// 更新提词器样式
function updateTeleprompterStyle() {
teleprompterText.style.fontFamily = fontFamily.value;
teleprompterText.style.fontSize = `${fontSize.value}px`;
}
// 开始滚动
function startScrolling() {
if (isPlaying) return;
isPlaying = true;
playBtn.style.display = 'none';
pauseBtn.style.display = 'block';
// 计算速度 (值越大速度越慢)
const speedFactor = 101 - speed.value; // 反转值,使滑块右侧为快
const intervalTime = Math.max(50, 2000 / speedFactor);
scrollInterval = setInterval(() => {
currentWordIndex++;
if (currentWordIndex >= words.length) {
// 到达末尾,停止滚动
pauseScrolling();
return;
}
updateHighlightPosition();
}, intervalTime);
}
// 暂停滚动
function pauseScrolling() {
if (!isPlaying) return;
clearInterval(scrollInterval);
isPlaying = false;
playBtn.style.display = 'block';
pauseBtn.style.display = 'none';
}
// 切换全屏
function toggleFullscreen() {
if (teleprompterContainer.classList.contains('fullscreen')) {
teleprompterContainer.classList.remove('fullscreen');
document.exitFullscreen?.();
} else {
teleprompterContainer.classList.add('fullscreen');
teleprompterContainer.requestFullscreen?.();
}
// 全屏切换后重新计算位置
setTimeout(() => {
calculatePositions();
updateHighlightPosition();
}, 300);
}
// 重置提词器
function resetTeleprompter() {
pauseScrolling();
currentWordIndex = 0;
teleprompterText.style.transform = 'translateY(0)';
updateHighlightPosition();
}
});
</script>
</body>
</html>