首页 / 应用软件 / 开发指南,打造网站内嵌的在线视频速度控制与章节标记工具

开发指南,打造网站内嵌的在线视频速度控制与章节标记工具

开发指南:打造网站内嵌的在线视频速度控制与章节标记工具

摘要

随着在线教育、知识分享和内容创作行业的蓬勃发展,视频内容已成为网站不可或缺的组成部分。然而,大多数网站的视频播放功能相对基础,缺乏个性化控制选项。本文将详细介绍如何通过WordPress代码二次开发,为网站视频播放器添加速度控制与章节标记功能,从而提升用户体验和内容互动性。我们将从需求分析、技术选型、代码实现到测试部署,全面解析这一实用工具的构建过程。


一、需求分析与功能规划

1.1 当前视频播放的局限性

大多数WordPress网站使用默认的视频播放器或第三方插件,这些方案通常存在以下局限性:

  • 播放速度固定,无法根据用户需求调整
  • 缺乏章节标记功能,长视频导航困难
  • 用户无法自定义播放体验
  • 互动性差,用户参与度低

1.2 目标功能定义

我们的开发目标是为WordPress网站视频播放器添加以下核心功能:

  1. 多级播放速度控制:提供0.5x到3.0x之间的多档速度选择
  2. 智能章节标记系统:允许内容创作者为视频添加章节标记
  3. 用户友好的交互界面:直观的控制面板,不影响观看体验
  4. 数据持久化:记住用户的播放偏好设置
  5. 响应式设计:适配各种设备和屏幕尺寸

1.3 技术可行性分析

WordPress作为开源CMS系统,提供了丰富的API和钩子机制,使我们能够:

  • 通过JavaScript操作HTML5视频元素
  • 使用PHP扩展视频元数据处理
  • 利用WordPress数据库存储章节信息
  • 通过AJAX实现前后端数据交互

二、技术架构与开发环境搭建

2.1 开发环境配置

在开始开发前,需要准备以下环境:

  1. 本地开发环境:XAMPP/MAMP或Local by Flywheel
  2. WordPress安装:最新版本的WordPress(5.8+)
  3. 代码编辑器:VS Code、Sublime Text或PHPStorm
  4. 浏览器开发者工具:用于调试JavaScript和CSS
  5. 版本控制系统: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

我们将使用以下关键技术:

  1. HTML5 Video API:控制视频播放的核心JavaScript接口
  2. WordPress REST API:处理章节数据的存储和检索
  3. jQuery:简化DOM操作和事件处理(WordPress已内置)
  4. LocalStorage:存储用户偏好设置
  5. 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 {
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5375.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部