文章目录[隐藏]
开发指南:打造网站内嵌的在线视频速度控制与章节标记工具
摘要
随着在线教育、知识分享和内容创作行业的蓬勃发展,视频内容已成为网站不可或缺的组成部分。然而,大多数网站的视频播放功能相对基础,缺乏个性化控制选项。本文将详细介绍如何通过WordPress代码二次开发,为网站视频播放器添加速度控制与章节标记功能,从而提升用户体验和内容互动性。我们将从需求分析、技术选型、代码实现到测试部署,全面解析这一实用工具的构建过程。
一、需求分析与功能规划
1.1 当前视频播放的局限性
大多数WordPress网站使用默认的视频播放器或第三方插件,这些方案通常存在以下局限性:
- 播放速度固定,无法根据用户需求调整
- 缺乏章节标记功能,长视频导航困难
- 用户无法自定义播放体验
- 互动性差,用户参与度低
1.2 目标功能定义
我们的开发目标是为WordPress网站视频播放器添加以下核心功能:
- 多级播放速度控制:提供0.5x到3.0x之间的多档速度选择
- 智能章节标记系统:允许内容创作者为视频添加章节标记
- 用户友好的交互界面:直观的控制面板,不影响观看体验
- 数据持久化:记住用户的播放偏好设置
- 响应式设计:适配各种设备和屏幕尺寸
1.3 技术可行性分析
WordPress作为开源CMS系统,提供了丰富的API和钩子机制,使我们能够:
- 通过JavaScript操作HTML5视频元素
- 使用PHP扩展视频元数据处理
- 利用WordPress数据库存储章节信息
- 通过AJAX实现前后端数据交互
二、技术架构与开发环境搭建
2.1 开发环境配置
在开始开发前,需要准备以下环境:
- 本地开发环境:XAMPP/MAMP或Local by Flywheel
- WordPress安装:最新版本的WordPress(5.8+)
- 代码编辑器:VS Code、Sublime Text或PHPStorm
- 浏览器开发者工具:用于调试JavaScript和CSS
- 版本控制系统:Git(可选但推荐)
2.2 项目结构设计
我们将创建一个独立的WordPress插件来管理所有功能代码:
wp-content/plugins/video-enhancer-tool/
├── video-enhancer.php # 主插件文件
├── includes/
│ ├── class-video-processor.php # 视频处理类
│ ├── class-chapter-manager.php # 章节管理类
│ └── class-settings-handler.php # 设置处理类
├── assets/
│ ├── css/
│ │ ├── video-controls.css # 控制界面样式
│ │ └── admin-styles.css # 后台管理样式
│ ├── js/
│ │ ├── video-controls.js # 前端控制逻辑
│ │ ├── chapter-editor.js # 章节编辑器
│ │ └── admin-scripts.js # 后台脚本
│ └── images/ # 图标和图片资源
├── templates/ # 前端模板文件
│ └── video-player-enhanced.php
└── languages/ # 国际化文件
2.3 核心技术与API
我们将使用以下关键技术:
- HTML5 Video API:控制视频播放的核心JavaScript接口
- WordPress REST API:处理章节数据的存储和检索
- jQuery:简化DOM操作和事件处理(WordPress已内置)
- LocalStorage:存储用户偏好设置
- CSS3 Flexbox/Grid:构建响应式控制界面
三、播放速度控制功能实现
3.1 HTML5视频播放器基础集成
首先,我们需要确保网站的视频使用HTML5播放器,这是实现高级控制的基础:
// 在video-enhancer.php中
function vet_replace_video_shortcode($output, $tag) {
if ('video' !== $tag) {
return $output;
}
// 为视频元素添加ID和类名以便JavaScript操作
$output = preg_replace('/<video/', '<video data-vet-enhanced="true"', $output);
return $output;
}
add_filter('do_shortcode_tag', 'vet_replace_video_shortcode', 10, 2);
3.2 速度控制界面设计
创建直观的速度控制界面,包含按钮和下拉菜单:
/* assets/css/video-controls.css */
.vet-controls-container {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(0, 0, 0, 0.7);
padding: 10px 15px;
border-radius: 5px;
margin-top: 10px;
color: white;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
.vet-speed-control {
display: flex;
align-items: center;
}
.vet-speed-label {
margin-right: 10px;
font-size: 14px;
opacity: 0.9;
}
.vet-speed-buttons {
display: flex;
gap: 5px;
}
.vet-speed-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
font-size: 13px;
transition: all 0.2s ease;
}
.vet-speed-btn:hover {
background: rgba(255, 255, 255, 0.2);
}
.vet-speed-btn.active {
background: #0073aa;
border-color: #0073aa;
}
.vet-speed-dropdown {
position: relative;
display: inline-block;
}
.vet-speed-dropdown-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 5px 15px 5px 10px;
border-radius: 3px;
cursor: pointer;
font-size: 13px;
position: relative;
}
.vet-speed-dropdown-btn:after {
content: "▼";
font-size: 10px;
margin-left: 5px;
}
.vet-speed-dropdown-content {
display: none;
position: absolute;
bottom: 100%;
left: 0;
background: rgba(0, 0, 0, 0.9);
min-width: 80px;
border-radius: 3px;
z-index: 1000;
margin-bottom: 5px;
}
.vet-speed-dropdown-content.show {
display: block;
}
.vet-speed-option {
color: white;
padding: 8px 12px;
text-decoration: none;
display: block;
cursor: pointer;
font-size: 13px;
}
.vet-speed-option:hover {
background: rgba(255, 255, 255, 0.1);
}
3.3 JavaScript速度控制逻辑
实现播放速度控制的核心JavaScript代码:
// assets/js/video-controls.js
(function($) {
'use strict';
// 视频增强工具主对象
var VideoEnhancer = {
// 初始化
init: function() {
this.setupVideoPlayers();
this.bindEvents();
this.loadUserPreferences();
},
// 查找页面上的视频元素并添加控制
setupVideoPlayers: function() {
$('video[data-vet-enhanced="true"]').each(function() {
var $video = $(this);
// 确保视频有ID
if (!$video.attr('id')) {
$video.attr('id', 'vet-video-' + Math.random().toString(36).substr(2, 9));
}
// 添加控制容器
VideoEnhancer.addControls($video);
});
},
// 为视频添加控制界面
addControls: function($video) {
var videoId = $video.attr('id');
var controlsHtml = `
<div class="vet-controls-container" data-video-id="${videoId}">
<div class="vet-speed-control">
<span class="vet-speed-label">播放速度:</span>
<div class="vet-speed-buttons">
<button class="vet-speed-btn" data-speed="0.5">0.5x</button>
<button class="vet-speed-btn" data-speed="0.75">0.75x</button>
<button class="vet-speed-btn active" data-speed="1">1x</button>
<button class="vet-speed-btn" data-speed="1.25">1.25x</button>
<button class="vet-speed-btn" data-speed="1.5">1.5x</button>
<button class="vet-speed-btn" data-speed="2">2x</button>
</div>
<div class="vet-speed-dropdown">
<button class="vet-speed-dropdown-btn">更多速度</button>
<div class="vet-speed-dropdown-content">
<div class="vet-speed-option" data-speed="0.25">0.25x</div>
<div class="vet-speed-option" data-speed="0.5">0.5x</div>
<div class="vet-speed-option" data-speed="0.75">0.75x</div>
<div class="vet-speed-option" data-speed="1">1x</div>
<div class="vet-speed-option" data-speed="1.25">1.25x</div>
<div class="vet-speed-option" data-speed="1.5">1.5x</div>
<div class="vet-speed-option" data-speed="1.75">1.75x</div>
<div class="vet-speed-option" data-speed="2">2x</div>
<div class="vet-speed-option" data-speed="2.5">2.5x</div>
<div class="vet-speed-option" data-speed="3">3x</div>
</div>
</div>
</div>
<div class="vet-chapter-control">
<button class="vet-chapters-toggle-btn">章节</button>
<div class="vet-chapters-panel">
<div class="vet-chapters-list"></div>
</div>
</div>
</div>
`;
// 将控制容器插入到视频后面
$video.after(controlsHtml);
// 初始化章节功能
VideoEnhancer.loadChaptersForVideo(videoId);
},
// 绑定事件处理
bindEvents: function() {
// 速度按钮点击事件
$(document).on('click', '.vet-speed-btn', function() {
var speed = $(this).data('speed');
VideoEnhancer.setPlaybackSpeed(speed, $(this));
});
// 下拉速度选项点击事件
$(document).on('click', '.vet-speed-option', function() {
var speed = $(this).data('speed');
VideoEnhancer.setPlaybackSpeed(speed, $(this));
});
// 下拉菜单显示/隐藏
$(document).on('click', '.vet-speed-dropdown-btn', function(e) {
e.stopPropagation();
$(this).siblings('.vet-speed-dropdown-content').toggleClass('show');
});
// 点击其他地方关闭下拉菜单
$(document).on('click', function() {
$('.vet-speed-dropdown-content').removeClass('show');
});
// 章节切换按钮
$(document).on('click', '.vet-chapters-toggle-btn', function() {
$(this).siblings('.vet-chapters-panel').toggleClass('show');
});
},
// 设置播放速度
setPlaybackSpeed: function(speed, $element) {
// 获取对应的视频元素
var videoId = $element.closest('.vet-controls-container').data('video-id');
var video = document.getElementById(videoId);
if (video) {
// 设置播放速度
video.playbackRate = speed;
// 更新按钮状态
$('.vet-speed-btn').removeClass('active');
$('.vet-speed-btn[data-speed="' + speed + '"]').addClass('active');
// 更新下拉按钮文本
var $dropdownBtn = $element.closest('.vet-controls-container').find('.vet-speed-dropdown-btn');
$dropdownBtn.text(speed + 'x');
// 保存用户偏好
VideoEnhancer.saveUserPreference('playbackSpeed', speed);
// 显示速度变化提示
VideoEnhancer.showSpeedNotification(speed);
}
},
// 显示速度变化提示
showSpeedNotification: function(speed) {
// 创建或获取通知元素
var $notification = $('.vet-speed-notification');
if ($notification.length === 0) {
$notification = $('<div class="vet-speed-notification"></div>');
$('body').append($notification);
}
// 设置内容和显示
$notification.text('播放速度: ' + speed + 'x').addClass('show');
// 2秒后隐藏
setTimeout(function() {
$notification.removeClass('show');
}, 2000);
},
// 加载用户偏好设置
loadUserPreferences: function() {
var savedSpeed = localStorage.getItem('vet_playback_speed');
if (savedSpeed) {
// 页面加载后应用保存的速度
$(document).ready(function() {
setTimeout(function() {
$('.vet-speed-btn[data-speed="' + savedSpeed + '"]').click();
}, 500);
});
}
},
// 保存用户偏好
saveUserPreference: function(key, value) {
if (key === 'playbackSpeed') {
localStorage.setItem('vet_playback_speed', value);
}
},
// 加载视频章节
loadChaptersForVideo: function(videoId) {
// 通过AJAX获取章节数据
$.ajax({
url: vet_ajax.ajax_url,
type: 'POST',
data: {
action: 'vet_get_chapters',
video_id: videoId,
nonce: vet_ajax.nonce
},
success: function(response) {
if (response.success && response.data.chapters) {
VideoEnhancer.renderChapters(videoId, response.data.chapters);
}
}
});
},
// 渲染章节列表
renderChapters: function(videoId, chapters) {
var $chaptersList = $('.vet-controls-container[data-video-id="' + videoId + '"] .vet-chapters-list');
var html = '';
if (chapters.length > 0) {
html += '<div class="vet-chapters-header">视频章节</div>';
chapters.forEach(function(chapter) {
html += `
<div class="vet-chapter-item" data-timestamp="${chapter.timestamp}">
<div class="vet-chapter-time">${VideoEnhancer.formatTime(chapter.timestamp)}</div>
<div class="vet-chapter-title">${chapter.title}</div>
</div>
`;
});
// 绑定章节点击事件
$chaptersList.html(html);
$chaptersList.find('.vet-chapter-item').on('click', function() {
var timestamp = $(this).data('timestamp');
var video = document.getElementById(videoId);
if (video) {
video.currentTime = timestamp;
video.play();
}
});
} else {
$chaptersList.html('<div class="vet-no-chapters">暂无章节标记</div>');
}
},
// 格式化时间显示
formatTime: function(seconds) {
var hrs = Math.floor(seconds / 3600);
var mins = Math.floor((seconds % 3600) / 60);
var secs = Math.floor(seconds % 60);
if (hrs > 0) {
return hrs + ':' + (mins < 10 ? '0' : '') + mins + ':' + (secs < 10 ? '0' : '') + secs;
} else {
return mins + ':' + (secs < 10 ? '0' : '') + secs;
}
}
};
// 初始化
$(document).ready(function() {
VideoEnhancer.init();
});
})(jQuery);
3.4 后端支持代码
创建PHP类来处理速度控制相关的后端逻辑:
// includes/class-video-processor.php
class Video_Enhancer_Processor {
// 初始化
public function __construct() {
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
add_action('wp_ajax_vet_get_chapters', array($this, 'ajax_get_chapters'));
add_action('wp_ajax_nopriv_vet_get_chapters', array($this, 'ajax_get_chapters'));
add_action('wp_ajax_vet_save_chapters', array($this, 'ajax_save_chapters'));
}
// 加载前端资源
public function enqueue_frontend_assets() {
// 加载CSS
wp_enqueue_style(
'video-enhancer-controls',
plugin_dir_url(__FILE__) . '../assets/css/video-controls.css',
array(),
'1.0.0'
);
// 加载JavaScript
wp_enqueue_script(
'video-enhancer-controls',
plugin_dir_url(__FILE__) . '../assets/js/video-controls.js',
array('jquery'),
'1.0.0',
true
);
// 传递AJAX参数到前端
wp_localize_script('video-enhancer-controls', 'vet_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('vet_ajax_nonce')
));
}
// 加载后台资源
public function enqueue_admin_assets($hook) {
// 只在文章编辑页面加载
if ('post.php' !== $hook && 'post-new.php' !== $hook) {
return;
}
wp_enqueue_style(
'video-enhancer-admin',
plugin_dir_url(__FILE__) . '../assets/css/admin-styles.css',
array(),
'1.0.0'
);
wp_enqueue_script(
'video-enhancer-admin',
plugin_dir_url(__FILE__) . '../assets/js/admin-scripts.js',
array('jquery', 'jquery-ui-sortable'),
'1.0.0',
true
);
}
// AJAX获取章节数据
public function ajax_get_chapters() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'vet_ajax_nonce')) {
wp_die('安全验证失败');
}
$video_id = sanitize_text_field($_POST['video_id']);
$post_id = get_the_ID();
// 获取章节数据
$chapters = $this->get_chapters_for_video($post_id, $video_id);
wp_send_json_success(array(
'chapters' => $chapters
));
}
// 获取视频章节
private function get_chapters_for_video($post_id, $video_id) {
$chapters = get_post_meta($post_id, '_vet_video_chapters_' . $video_id, true);
if (empty($chapters) || !is_array($chapters)) {
return array();
}
// 按时间戳排序
usort($chapters, function($a, $b) {
return $a['timestamp'] - $b['timestamp'];
});
return $chapters;
}
}
四、章节标记系统实现
4.1 章节数据结构设计
章节数据需要包含以下信息:
- 时间戳(秒)
- 章节标题
- 章节描述(可选)
- 缩略图(可选)
// includes/class-chapter-manager.php
class Video_Enhancer_Chapter_Manager {
// 初始化
public function __construct() {
add_action('add_meta_boxes', array($this, 'add_chapter_meta_box'));
add_action('save_post', array($this, 'save_chapter_data'));
}
// 添加章节管理元框
public function add_chapter_meta_box() {
$post_types = apply_filters('vet_supported_post_types', array('post', 'page'));
foreach ($post_types as $post_type) {
add_meta_box(
'vet-chapter-manager',
'视频章节管理',
array($this, 'render_chapter_meta_box'),
$post_type,
'normal',
'high'
);
}
}
// 渲染章节管理界面
public function render_chapter_meta_box($post) {
// 获取文章中的视频
$videos = $this->extract_videos_from_content($post->post_content);
if (empty($videos)) {
echo '<p>本文中没有找到视频。请先添加视频到内容中。</p>';
return;
}
// 添加非ce字段
wp_nonce_field('vet_save_chapters', 'vet_chapter_nonce');
echo '<div class="vet-chapter-manager">';
foreach ($videos as $index => $video) {
$video_id = $video['id'];
$chapters = $this->get_chapters_for_video($post->ID, $video_id);
echo '<div class="vet-video-section">';
echo '<h3>视频 #' . ($index + 1) . '</h3>';
echo '<div class="vet-video-preview">' . $video['html'] . '</div>';
// 章节管理界面
$this->render_chapter_editor($video_id, $chapters);
echo '</div>';
}
echo '</div>';
}
// 渲染章节编辑器
private function render_chapter_editor($video_id, $chapters) {
?>
<div class="vet-chapter-editor" data-video-id="<?php echo esc_attr($video_id); ?>">
<div class="vet-chapter-header">
<h4>章节管理</h4>
<button type="button" class="button vet-add-chapter">添加章节</button>
</div>
<div class="vet-chapters-list">
<?php if (!empty($chapters)): ?>
<?php foreach ($chapters as $chapter): ?>
<div class="vet-chapter-item" data-timestamp="<?php echo esc_attr($chapter['timestamp']); ?>">
<input type="hidden" name="vet_chapters[<?php echo esc_attr($video_id); ?>][timestamp][]" value="<?php echo esc_attr($chapter['timestamp']); ?>">
<input type="hidden" name="vet_chapters[<?php echo esc_attr($video_id); ?>][title][]" value="<?php echo esc_attr($chapter['title']); ?>">
<div class="vet-chapter-preview">
<span class="vet-chapter-time"><?php echo $this->format_time($chapter['timestamp']); ?></span>
<span class="vet-chapter-title"><?php echo esc_html($chapter['title']); ?></span>
</div>
<div class="vet-chapter-actions">
<button type="button" class="button vet-edit-chapter">编辑</button>
<button type="button" class="button button-link vet-remove-chapter">删除</button>
</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<p class="vet-no-chapters">暂无章节,点击"添加章节"按钮创建</p>
<?php endif; ?>
</div>
<!-- 章节编辑模板 -->
<div class="vet-chapter-template" style="display: none;">
<div class="vet-chapter-item">
<input type="hidden" name="vet_chapters[<?php echo esc_attr($video_id); ?>][timestamp][]" value="">
<input type="hidden" name="vet_chapters[<?php echo esc_attr($video_id); ?>][title][]" value="">
<div class="vet-chapter-preview">
<span class="vet-chapter-time">00:00</span>
<span class="vet-chapter-title">新章节</span>
</div>
<div class="vet-chapter-actions">
<button type="button" class="button vet-edit-chapter">编辑</button>
<button type="button" class="button button-link vet-remove-chapter">删除</button>
</div>
</div>
</div>
</div>
<?php
}
// 从内容中提取视频
private function extract_videos_from_content($content) {
$videos = array();
// 匹配视频短代码
preg_match_all('/]*]/', $content, $shortcode_matches);
foreach ($shortcode_matches[0] as $shortcode) {
$video_id = 'video-' . md5($shortcode);
$videos[] = array(
'id' => $video_id,
'html' => do_shortcode($shortcode)
);
}
// 匹配HTML5视频标签
preg_match_all('/<video[^>]*>/', $content, $html_matches);
foreach ($html_matches[0] as $index => $video_tag) {
$video_id = 'html5-video-' . $index;
$videos[] = array(
'id' => $video_id,
'html' => $video_tag . '</video>'
);
}
return $videos;
}
// 保存章节数据
public function save_chapter_data($post_id) {
// 检查nonce
if (!isset($_POST['vet_chapter_nonce']) ||
!wp_verify_nonce($_POST['vet_chapter_nonce'], 'vet_save_chapters')) {
return;
}
// 检查权限
if (!current_user_can('edit_post', $post_id)) {
return;
}
// 保存章节数据
if (isset($_POST['vet_chapters']) && is_array($_POST['vet_chapters'])) {
foreach ($_POST['vet_chapters'] as $video_id => $chapters_data) {
$chapters = array();
if (isset($chapters_data['timestamp']) && isset($chapters_data['title'])) {
$timestamps = $chapters_data['timestamp'];
$titles = $chapters_data['title'];
for ($i = 0; $i < count($timestamps); $i++) {
if (!empty($timestamps[$i]) && !empty($titles[$i])) {
$chapters[] = array(
'timestamp' => floatval($timestamps[$i]),
'title' => sanitize_text_field($titles[$i])
);
}
}
}
// 按时间戳排序
usort($chapters, function($a, $b) {
return $a['timestamp'] - $b['timestamp'];
});
// 保存到post meta
update_post_meta($post_id, '_vet_video_chapters_' . sanitize_key($video_id), $chapters);
}
}
}
// 格式化时间显示
private function format_time($seconds) {
$mins = floor($seconds / 60);
$secs = floor($seconds % 60);
return sprintf('%02d:%02d', $mins, $secs);
}
}
4.2 章节编辑器前端交互
// assets/js/admin-scripts.js
(function($) {
'use strict';
// 章节编辑器对象
var ChapterEditor = {
init: function() {
this.bindEvents();
this.initSortable();
},
bindEvents: function() {
// 添加章节按钮
$(document).on('click', '.vet-add-chapter', function() {
ChapterEditor.addNewChapter($(this).closest('.vet-chapter-editor'));
});
// 编辑章节按钮
$(document).on('click', '.vet-edit-chapter', function() {
ChapterEditor.editChapter($(this).closest('.vet-chapter-item'));
});
// 删除章节按钮
$(document).on('click', '.vet-remove-chapter', function() {
ChapterEditor.removeChapter($(this).closest('.vet-chapter-item'));
});
// 视频时间点击事件
$(document).on('click', '.vet-video-preview video', function() {
var $video = $(this);
var currentTime = $video[0].currentTime;
var $editor = $video.closest('.vet-video-section').find('.vet-chapter-editor');
// 在章节编辑器中显示当前时间
ChapterEditor.showCurrentTime($editor, currentTime);
});
},
// 初始化可排序
initSortable: function() {
$('.vet-chapters-list').sortable({
handle: '.vet-chapter-preview',
update: function() {
ChapterEditor.updateChapterOrder($(this));
}
});
},
// 添加新章节
addNewChapter: function($editor) {
var $template = $editor.find('.vet-chapter-template .vet-chapter-item').clone();
var $list = $editor.find('.vet-chapters-list');
// 移除"暂无章节"提示
$list.find('.vet-no-chapters').remove();
// 添加到列表
$list.append($template);
// 编辑新章节
ChapterEditor.editChapter($template);
},
// 编辑章节
editChapter: function($chapterItem) {
var $preview = $chapterItem.find('.vet-chapter-preview');
var $timeSpan = $preview.find('.vet-chapter-time');
var $titleSpan = $preview.find('.vet-chapter-title');
var currentTime = $timeSpan.text();
var currentTitle = $titleSpan.text();
// 创建编辑表单
var $form = $('<div class="vet-chapter-edit-form"></div>');
$form.html(`
<div class="vet-edit-fields">
<div class="vet-field">
<label>时间戳 (秒):</label>
<input type="number" class="vet-time-input" step="0.1" min="0" value="${ChapterEditor.timeToSeconds(currentTime)}">
</div>
<div class="vet-field">
<label>章节标题:</label>
<input type="text" class="vet-title-input" value="${currentTitle}">
</div>
<div class="vet-edit-actions">
<button type="button" class="button button-primary vet-save-chapter">保存</button>
<button type="button" class="button vet-cancel-edit">取消</button>
</div>
</div>
`);
// 替换预览为编辑表单
$preview.hide();
$chapterItem.find('.vet-chapter-actions').hide();
$chapterItem.append($form);
// 绑定保存事件
$form.find('.vet-save-chapter').on('click', function() {
var timeInput = $form.find('.vet-time-input').val();
var titleInput = $form.find('.vet-title-input').val();
if (timeInput && titleInput) {
// 更新时间戳和标题
$chapterItem.find('input[name*="timestamp"]').val(timeInput);
$chapterItem.find('input[name*="title"]').val(titleInput);
// 更新预览显示
$timeSpan.text(ChapterEditor.secondsToTime(timeInput));
$titleSpan.text(titleInput);
}
// 恢复显示
$form.remove();
$preview.show();
$chapterItem.find('.vet-chapter-actions').show();
});
// 绑定取消事件
$form.find('.vet-cancel-edit').on('click', function() {
$form.remove();
$preview.show();
$chapterItem.find('.vet-chapter-actions').show();
});
},
// 删除章节
removeChapter: function($chapterItem) {
if (confirm('确定要删除这个章节吗?')) {
$chapterItem.remove();
// 如果没有章节了,显示提示
var $list = $chapterItem.closest('.vet-chapters-list');
if ($list.children('.vet-chapter-item').length === 0) {
$list.html('<p class="vet-no-chapters">暂无章节,点击"添加章节"按钮创建</p>');
}
}
},
// 显示当前时间
showCurrentTime: function($editor, currentTime) {
// 创建或更新时间提示
var $timeHint = $editor.find('.vet-current-time-hint');
if ($timeHint.length === 0) {
$timeHint = $('<div class="vet-current-time-hint"></div>');
$editor.find('.vet-chapter-header').after($timeHint);
}
var timeStr = ChapterEditor.secondsToTime(currentTime);
$timeHint.html('当前视频时间: <strong>' + timeStr + '</strong> (点击视频可获取当前时间)');
// 3秒后淡出
$timeHint.show();
setTimeout(function() {
$timeHint.fadeOut();
}, 3000);
},
// 更新章节顺序
updateChapterOrder: function($list) {
// 重新排序后,可以在这里添加额外的处理逻辑
console.log('章节顺序已更新');
},
// 时间字符串转秒数
timeToSeconds: function(timeStr) {
var parts = timeStr.split(':');
if (parts.length === 2) {
return parseInt(parts[0]) * 60 + parseInt(parts[1]);
}
return 0;
},
// 秒数转时间字符串
secondsToTime: function(seconds) {
var mins = Math.floor(seconds / 60);
var secs = Math.floor(seconds % 60);
return (mins < 10 ? '0' : '') + mins + ':' + (secs < 10 ? '0' : '') + secs;
}
};
// 初始化
$(document).ready(function() {
ChapterEditor.init();
});
})(jQuery);
4.3 章节标记样式设计
/* assets/css/admin-styles.css */
/* 章节管理器样式 */
.vet-chapter-manager {
padding: 15px;
background: #f8f9fa;
border-radius: 5px;
}
.vet-video-section {
margin-bottom: 30px;
padding: 20px;
background: white;
border: 1px solid #ddd;
border-radius: 5px;
}
.vet-video-section h3 {
margin-top: 0;
color: #23282d;
border-bottom: 2px solid #0073aa;
padding-bottom: 10px;
}
.vet-video-preview {
margin: 15px 0;
text-align: center;
}
.vet-video-preview video {
