跳转至

全屏模式

Django Admin Dashboards 提供强大的全屏模式控制功能,允许您在演示、监控或专注分析时最大化数据看板可见性。本指南涵盖全屏功能的所有方面。

目录

概述

什么是全屏模式?

全屏模式通过隐藏周围的界面元素来最大化数据看板显示。提供两种不同的模式:

  1. 全屏时隐藏:仅在浏览器进入全屏模式时自动隐藏周围元素
  2. 强制隐藏:无论全屏状态如何,始终隐藏周围元素

全屏模式的优势

  • 演示就绪:为演示提供干净、无干扰的显示
  • 最大化空间:利用整个屏幕进行数据可视化
  • 专注模式:移除界面杂乱,便于专注分析
  • 监控:适合在专用显示器上进行数据看板监控
  • 可访问性:更大的元素,更好的可见性

全屏模式的工作原理

  1. URL 参数检测:JavaScript 从 URL 读取全屏参数
  2. CSS 类应用:基于全屏状态添加/移除 CSS 类
  3. 元素隐藏:使用 CSS display: none 隐藏指定元素
  4. 事件监听:监听浏览器全屏更改事件
  5. 状态管理:在交互过程中保持全屏状态

快速开始

通过 URL 启用全屏

通过 URL 参数控制全屏行为:

    # 仅在全屏模式下隐藏周围元素

    /admin/?_hide_others_in_fullscreen=true

    # 始终隐藏周围元素(强制模式)

    /admin/?_force_hide_others=true

    # 禁用全屏隐藏

    /admin/?_hide_others_in_fullscreen=false

数据看板要求

全屏控制需要数据看板类配置:

    from django_admin_dashboards.base import Dashboard

    class MyDashboard(Dashboard):
        # 启用全屏时隐藏功能

        hide_others_in_fullscreen = True

        # 启用强制隐藏功能

        force_hide_others = False

        # 可选:自定义要隐藏的元素

        fullscreen_hide_selectors = [
            '#header',
            '#footer',
            '.sidebar',
            '.breadcrumbs',
            '.object-tools',
        ]

基础使用示例

    # views.py 或数据看板配置

    from django_admin_dashboards.contrib.auth.dashboard import AuthAppDashboard

    def get_dashboard_for_presentation():
        """返回为演示模式配置的数据看板"""
        dashboard = AuthAppDashboard()

        # 启用全屏功能

        dashboard.hide_others_in_fullscreen = True
        dashboard.force_hide_others = False

        return dashboard
    <a href="{% url 'admin:index' %}?_hide_others_in_fullscreen=true&_dark_mode_on=true"
       class="presentation-mode-link">
        进入演示模式
    </a>

URL 参数

_hide_others_in_fullscreen 参数

仅在浏览器处于全屏模式时隐藏周围元素:

描述 行为
true 启用全屏时隐藏 浏览器进入全屏时隐藏元素
false 禁用全屏时隐藏 无自动隐藏(默认)
1, yes 替代真值 true 相同
0, no 替代假值 false 相同

使用示例:

    # 基本用法

    /admin/?_hide_others_in_fullscreen=true

    # 替代值

    /admin/?_hide_others_in_fullscreen=1
    /admin/?_hide_others_in_fullscreen=yes

    # 禁用

    /admin/?_hide_others_in_fullscreen=false

工作原理: 1. 从 URL 检测参数 2. JavaScript 监听浏览器全屏事件 3. 当浏览器进入全屏时,添加 CSS 类 4. 通过 CSS 隐藏指定元素 5. 当浏览器退出全屏时,移除 CSS 类 6. 元素再次可见

_force_hide_others 参数

无论全屏状态如何,始终隐藏周围元素:

描述 行为
true 启用强制隐藏 始终隐藏指定元素
false 禁用强制隐藏 显示元素(默认)
1, yes 替代真值 true 相同
0, no 替代假值 false 相同

使用示例:

    # 始终隐藏周围元素

    /admin/?_force_hide_others=true

    # 替代值

    /admin/?_force_hide_others=1
    /admin/?_force_hide_others=yes

    # 显示元素

    /admin/?_force_hide_others=false

工作原理: 1. 从 URL 检测参数 2. 立即向 body 添加 CSS 类 3. 通过 CSS 隐藏指定元素 4. 无需浏览器全屏交互 5. 元素保持隐藏直到参数被移除

参数组合

将全屏参数与其他控制组合:

    # 演示模式:全屏隐藏 + 深色模式

    /admin/?_hide_others_in_fullscreen=true&_dark_mode_on=true

    # 监控模式:强制隐藏 + 自动刷新

    /admin/?_force_hide_others=true&_refresh=10

    # 组合:强制隐藏优先于全屏隐藏

    /admin/?_force_hide_others=true&_hide_others_in_fullscreen=true

    # 信息亭模式:强制隐藏 + 无导航

    /admin/?_force_hide_others=true&_disable_navigation=true

参数优先级

当指定两个参数时: 1. _force_hide_others=true 优先(始终隐藏) 2. _force_hide_others 激活时忽略 _hide_others_in_fullscreen 3. 为获得可预测的行为,仅使用一个参数

    # 此组合:强制隐藏始终激活

    /admin/?_force_hide_others=true&_hide_others_in_fullscreen=true

    # 更好:选择一种模式

    /admin/?_force_hide_others=true  # 或

    /admin/?_hide_others_in_fullscreen=true

数据看板配置

基础配置

在数据看板类中启用全屏功能:

    from django_admin_dashboards.base import Dashboard

    class FullscreenEnabledDashboard(Dashboard):
        """支持全屏的数据看板"""

        # 启用全屏时隐藏功能

        hide_others_in_fullscreen = True

        # 启用强制隐藏功能

        force_hide_others = False

        # 自定义要隐藏的元素(可选)

        fullscreen_hide_selectors = [
            '#header',          # Django Admin 头部

            '#footer',          # 页脚(如果存在)

            '.sidebar',         # 导航侧边栏

            '.breadcrumbs',     # 面包屑导航

            '.object-tools',    # 对象操作工具

            '.submit-row',      # 表单提交行

            '.help',            # 帮助文本

            '.extra-actions',   # 任何额外操作按钮

        ]

        def get_context_data(self, request):
            context = super().get_context_data(request)

            # 添加上下文

            context['fullscreen_enabled'] = (
                self.hide_others_in_fullscreen or
                self.force_hide_others
            )

            # 检查当前全屏参数

            context['is_fullscreen_hide'] = self.is_fullscreen_hide_enabled(request)
            context['is_force_hide'] = self.is_force_hide_enabled(request)

            return context

高级配置

    class AdvancedFullscreenDashboard(Dashboard):
        """高级全屏配置"""

        # 全屏设置

        hide_others_in_fullscreen = True
        force_hide_others = False

        # 自定义 CSS 类

        fullscreen_css_class = 'dashboard-fullscreen-mode'
        force_hide_css_class = 'dashboard-force-hide-others'

        # 元素选择器及描述

        fullscreen_hide_selectors = {
            '#header': '主品牌头部',
            '#footer': '页面页脚',
            '.sidebar': '导航侧边栏',
            '.breadcrumbs': '面包屑路径',
            '.object-tools': '对象操作按钮',
            '.submit-row': '表单提交按钮',
            '.help': '帮助文本块',
            'h1:first-of-type': '第一个标题(如果不属于数据看板)',
        }

        # 全屏事件回调

        def on_fullscreen_enter(self, request):
            """进入全屏时调用"""
            # 记录全屏进入

            import logging
            logger = logging.getLogger(__name__)
            logger.info(f"从 {request.path} 进入全屏")

            # 添加上下文

            return {
                'fullscreen_message': '进入演示模式',
                'fullscreen_timestamp': timezone.now(),
            }

        def on_fullscreen_exit(self, request):
            """退出全屏时调用"""
            # 自定义退出处理

            return {
                'fullscreen_message': '退出演示模式',
            }

        def get_context_data(self, request):
            context = super().get_context_data(request)

            # 为模板添加选择器信息

            context['fullscreen_selectors'] = list(
                self.fullscreen_hide_selectors.keys()
                if isinstance(self.fullscreen_hide_selectors, dict)
                else self.fullscreen_hide_selectors
            )

            # 检查全屏状态

            if self.is_fullscreen_hide_enabled(request):
                context.update(self.on_fullscreen_enter(request))

            return context

动态配置

基于用户或请求动态配置全屏行为:

    class DynamicFullscreenDashboard(Dashboard):
        """基于请求动态配置全屏"""

        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)

            # 使用默认值初始化

            self.hide_others_in_fullscreen = False
            self.force_hide_others = False
            self.fullscreen_hide_selectors = []

        def configure_for_request(self, request):
            """基于请求参数或用户进行配置"""

            # 检查 URL 参数

            hide_in_fs = request.GET.get('_hide_others_in_fullscreen', '').lower()
            force_hide = request.GET.get('_force_hide_others', '').lower()

            # 根据 URL 参数设置

            self.hide_others_in_fullscreen = hide_in_fs in ['true', '1', 'yes']
            self.force_hide_others = force_hide in ['true', '1', 'yes']

            # 根据用户角色配置选择器

            if request.user.is_superuser:
                self.fullscreen_hide_selectors = [
                    '#header', '.sidebar', '.breadcrumbs'
                ]
            else:
                # 普通用户仅隐藏最小元素

                self.fullscreen_hide_selectors = [
                    '#header', '.breadcrumbs'
                ]

            # 从设置中添加自定义选择器

            custom_selectors = getattr(settings, 'DASHBOARD_FULLSCREEN_SELECTORS', [])
            self.fullscreen_hide_selectors.extend(custom_selectors)

        def get_context_data(self, request):
            # 在获取上下文前配置

            self.configure_for_request(request)

            context = super().get_context_data(request)

            # 添加上下文

            context['fullscreen_config'] = {
                'hide_in_fullscreen': self.hide_others_in_fullscreen,
                'force_hide': self.force_hide_others,
                'selectors': self.fullscreen_hide_selectors,
                'is_active': self.hide_others_in_fullscreen or self.force_hide_others,
            }

            return context

配置验证

    class ValidatedFullscreenDashboard(Dashboard):
        """带有验证的全屏配置数据看板"""

        hide_others_in_fullscreen = True
        force_hide_others = False

        def validate_fullscreen_config(self):
            """验证全屏配置"""
            errors = []
            warnings = []

            # 检查冲突设置

            if self.hide_others_in_fullscreen and self.force_hide_others:
                warnings.append(
                    "hide_others_in_fullscreen 和 force_hide_others 同时启用。"
                    "force_hide_others 将优先。"
                )

            # 验证选择器

            if not hasattr(self, 'fullscreen_hide_selectors'):
                errors.append("未定义 fullscreen_hide_selectors")
            elif not isinstance(self.fullscreen_hide_selectors, (list, tuple, dict)):
                errors.append("fullscreen_hide_selectors 必须是列表、元组或字典")
            elif len(self.fullscreen_hide_selectors) == 0:
                warnings.append("fullscreen_hide_selectors 为空")

            # 检查危险选择器

            dangerous_selectors = ['body', 'html', '.dashboard', '#content']
            for selector in self.fullscreen_hide_selectors:
                if selector in dangerous_selectors:
                    errors.append(f"危险选择器: {selector} 会隐藏数据看板本身")

            return {
                'valid': len(errors) == 0,
                'errors': errors,
                'warnings': warnings,
            }

        def get_context_data(self, request):
            context = super().get_context_data(request)

            # 添加验证结果

            validation = self.validate_fullscreen_config()
            context['fullscreen_validation'] = validation

            if not validation['valid']:
                # 记录错误

                import logging
                logger = logging.getLogger(__name__)
                for error in validation['errors']:
                    logger.error(f"全屏配置错误: {error}")

            return context

CSS 实现

基础 CSS 类

全屏模式使用 CSS 类隐藏元素:

    /* dashboard.css - 全屏部分 */

    /* 全屏模式类进入全屏时添加 */
    .dashboard-fullscreen-mode #header,
    .dashboard-fullscreen-mode #footer,
    .dashboard-fullscreen-mode .sidebar,
    .dashboard-fullscreen-mode .breadcrumbs,
    .dashboard-fullscreen-mode .object-tools {
        display: none !important;
    }

    /* 强制隐藏类启用强制隐藏时添加 */
    .dashboard-force-hide-others #header,
    .dashboard-force-hide-others #footer,
    .dashboard-force-hide-others .sidebar,
    .dashboard-force-hide-others .breadcrumbs,
    .dashboard-force-hide-others .object-tools {
        display: none !important;
    }

    /* 确保数据看板保持可见 */
    .dashboard-fullscreen-mode .dashboard,
    .dashboard-force-hide-others .dashboard {
        display: block !important;
        width: 100% !important;
        height: 100vh !important;
        margin: 0 !important;
        padding: 20px !important;
    }

    /* 改进全屏下的数据看板外观 */
    .dashboard-fullscreen-mode .dashboard {
        background-color: var(--dashboard-bg-color);
        overflow: auto;
    }

    /* 可选添加全屏指示器 */
    .dashboard-fullscreen-mode::before {
        content: '全屏模式';
        position: fixed;
        top: 10px;
        right: 10px;
        background: rgba(0, 0, 0, 0.7);
        color: white;
        padding: 5px 10px;
        border-radius: 3px;
        font-size: 12px;
        z-index: 10000;
        opacity: 0.7;
    }

响应式全屏样式

    /* 针对不同屏幕尺寸的响应式调整 */

    /* 小屏幕 */
    @media (max-width: 768px)

        /* 在小屏幕上隐藏额外元素 */
        .dashboard-fullscreen-mode .desktop-only,
        .dashboard-force-hide-others .desktop-only {
            display: none !important;
        }

        /* 调整组件间距 */
        .dashboard-fullscreen-mode .dashboard-col,
        .dashboard-force-hide-others .dashboard-col {
            margin-bottom: 15px !important;
        }
    }

    /* 大屏幕 */
    @media (min-width: 1200px)

        /* 增大字体以提高可读性 */
        .dashboard-fullscreen-mode .dashboard h1,
        .dashboard-force-hide-others .dashboard h1 {
            font-size: 2.5rem !important;
        }
    }

    /* 打印样式用于全屏类似输出 */
    @media print {
        /* 打印时隐藏非必要元素 */
        #header, #footer, .sidebar, .breadcrumbs, .object-tools {
            display: none !important;
        }

        /* 确保数据看板正确打印 */
        .dashboard {
            width: 100% !important;
            margin: 0 !important;
            padding: 0 !important;
        }

        /* 避免组件内分页 */
        .dashboard-col {
            page-break-inside: avoid !important;
        }
    }

全屏 CSS 变量

    /* 用于全屏自定义的 CSS 变量 */
    :root {
        --fullscreen-padding: 20px;
        --fullscreen-bg-color: var(--dashboard-bg-color);
        --fullscreen-overlay-color: rgba(0, 0, 0, 0.9);
        --fullscreen-transition-duration: 300ms;
    }

    [data-theme="dark"] {
        --fullscreen-bg-color: #000000;
        --fullscreen-overlay-color: rgba(255, 255, 255, 0.1);
    }

    /* 应用 CSS 变量 */
    .dashboard-fullscreen-mode .dashboard,
    .dashboard-force-hide-others .dashboard {
        padding: var(--fullscreen-padding) !important;
        background-color: var(--fullscreen-bg-color) !important;
        transition: all var(--fullscreen-transition-duration) ease !important;
    }

    /* 全屏覆盖效果 */
    .dashboard-fullscreen-mode::after {
        content: '';
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: var(--fullscreen-overlay-color);
        z-index: 9998;
        pointer-events: none;
    }

动画和过渡

    /* 进入/退出全屏的平滑过渡 */

    /* 元素隐藏动画 */
    .dashboard-fullscreen-mode #header,
    .dashboard-fullscreen-mode #footer,
    .dashboard-fullscreen-mode .sidebar,
    .dashboard-force-hide-others #header,
    .dashboard-force-hide-others #footer,
    .dashboard-force-hide-others .sidebar {
        transition: all 0.3s ease !important;
        opacity: 1;
    }

    /* 隐藏时 */
    .dashboard-fullscreen-mode #header,
    .dashboard-fullscreen-mode #footer,
    .dashboard-fullscreen-mode .sidebar,
    .dashboard-force-hide-others #header,
    .dashboard-force-hide-others #footer,
    .dashboard-force-hide-others .sidebar {
        opacity: 0 !important;
        height: 0 !important;
        overflow: hidden !important;
        margin: 0 !important;
        padding: 0 !important;
        border: none !important;
    }

    /* 数据看板展开动画 */
    .dashboard {
        transition: all 0.3s ease;
    }

    .dashboard-fullscreen-mode .dashboard,
    .dashboard-force-hide-others .dashboard {
        animation: dashboardExpand 0.3s ease forwards;
    }

    @keyframes dashboardExpand {
        from {
            transform: scale(0.95);
            opacity: 0.9;
        }
        to {
            transform: scale(1);
            opacity: 1;
        }
    }

    /* 全屏指示器动画 */
    .dashboard-fullscreen-mode::before {
        animation: slideIn 0.3s ease forwards;
    }

    @keyframes slideIn {
        from {
            transform: translateX(100%);
            opacity: 0;
        }
        to {
            transform: translateX(0);
            opacity: 0.7;
        }
    }

JavaScript API

全屏检测与控制

        // 全屏管理器类
    class DashboardFullscreenManager {

        constructor() {
            this.isFullscreen = false;
            this.fullscreenModeEnabled = false;
            this.forceHideEnabled = false;
            this.initialize();
        }

        initialize() {
            // 检查 URL 参数
            this.checkUrlParameters();

            // 设置事件监听器
            this.setupEventListeners();

            // 应用初始状态
            this.applyFullscreenState();

            // 如果需要添加控制按钮
            this.addControlButtons();
        }

        checkUrlParameters() {
            // 检查全屏隐藏参数
            const hideInFs = this.getUrlParameter('_hide_others_in_fullscreen');
            this.fullscreenModeEnabled = ['true', '1', 'yes'].includes(hideInFs);

            // 检查强制隐藏参数
            const forceHide = this.getUrlParameter('_force_hide_others');
            this.forceHideEnabled = ['true', '1', 'yes'].includes(forceHide);
        }

        getUrlParameter(name) {
            const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
            const results = regex.exec(window.location.href);
            return results ? decodeURIComponent(results[2].replace(/\+/g, ' ')) : null;
        }

        setupEventListeners() {
            // 跨浏览器全屏事件监听器
            document.addEventListener('fullscreenchange', this.handleFullscreenChange.bind(this));
            document.addEventListener('webkitfullscreenchange', this.handleFullscreenChange.bind(this));
            document.addEventListener('mozfullscreenchange', this.handleFullscreenChange.bind(this));
            document.addEventListener('MSFullscreenChange', this.handleFullscreenChange.bind(this));

            // 监听参数变化
            window.addEventListener('urlparameterschanged', (event) => {
                const { param, value } = event.detail;

                if (param === '_hide_others_in_fullscreen') {
                    this.fullscreenModeEnabled = ['true', '1', 'yes'].includes(value);
                    this.applyFullscreenState();
                } else if (param === '_force_hide_others') {
                    this.forceHideEnabled = ['true', '1', 'yes'].includes(value);
                    this.applyFullscreenState();
                }
            });
        }

        handleFullscreenChange() {
            this.isFullscreen = this.checkFullscreenState();
            this.applyFullscreenState();

            // 派发自定义事件
            this.dispatchFullscreenChangeEvent();
        }

        checkFullscreenState() {
            return !!(
                document.fullscreenElement ||
                document.webkitFullscreenElement ||
                document.mozFullScreenElement ||
                document.msFullscreenElement
            );
        }

        applyFullscreenState() {
            // 移除现有类
            document.documentElement.classList.remove('dashboard-fullscreen-mode');
            document.body.classList.remove('dashboard-force-hide-others');

            // 应用强制隐藏最高优先级
            if (this.forceHideEnabled) {
                document.body.classList.add('dashboard-force-hide-others');
            }
            // 应用全屏隐藏仅在全屏时
            else if (this.fullscreenModeEnabled && this.isFullscreen) {
                document.documentElement.classList.add('dashboard-fullscreen-mode');
            }

            // 更新 UI 指示器
            this.updateIndicators();
        }

        updateIndicators() {
            // 更新 UI 指示器
            const indicator = document.querySelector('.fullscreen-indicator');
            if (indicator) {
                if (this.forceHideEnabled) {
                    indicator.textContent = 'Force Hide Active';
                    indicator.classList.add('force-hide');
                } else if (this.fullscreenModeEnabled && this.isFullscreen) {
                    indicator.textContent = 'Fullscreen Mode';
                    indicator.classList.add('fullscreen');
                } else {
                    indicator.textContent = 'Normal Mode';
                    indicator.classList.remove('force-hide', 'fullscreen');
                }
            }
        }

        dispatchFullscreenChangeEvent() {
            window.dispatchEvent(new CustomEvent('dashboardfullscreenchange', {
                detail: {
                    isFullscreen: this.isFullscreen,
                    fullscreenModeEnabled: this.fullscreenModeEnabled,
                    forceHideEnabled: this.forceHideEnabled,
                    forceHideActive: this.forceHideEnabled,
                    fullscreenHideActive: this.fullscreenModeEnabled && this.isFullscreen,
                }
            }));
        }

        addControlButtons() {
            // 添加全屏切换按钮
            const button = document.createElement('button');
            button.className = 'fullscreen-toggle-btn';
            button.innerHTML = '📺 切换全屏';
            button.title = '切换浏览器全屏模式';

            button.addEventListener('click', () => {
                this.toggleFullscreen();
            });

            // 添加到数据看板工具栏如果存在
            const toolbar = document.querySelector('.dashboard-toolbar') ||
                           document.querySelector('.dashboard') ||
                           document.body;

            if (toolbar) {
                toolbar.appendChild(button);
            }
        }

        toggleFullscreen() {
            if (!this.isFullscreen) {
                this.enterFullscreen();
            } else {
                this.exitFullscreen();
            }
        }

        enterFullscreen() {
            const element = document.documentElement;

            if (element.requestFullscreen) {
                element.requestFullscreen();
            } else if (element.webkitRequestFullscreen) {
                element.webkitRequestFullscreen();
            } else if (element.mozRequestFullScreen) {
                element.mozRequestFullScreen();
            } else if (element.msRequestFullscreen) {
                element.msRequestFullscreen();
            }
        }

        exitFullscreen() {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.msExitFullscreen) {
                document.msExitFullscreen();
            }
        }

        // 公共 API 方法
        enableFullscreenMode(enable = true) {
            this.fullscreenModeEnabled = enable;
            this.applyFullscreenState();
            this.updateUrlParameter('_hide_others_in_fullscreen', enable ? 'true' : 'false');
        }

        enableForceHide(enable = true) {
            this.forceHideEnabled = enable;
            this.applyFullscreenState();
            this.updateUrlParameter('_force_hide_others', enable ? 'true' : 'false');
        }

        updateUrlParameter(param, value) {
            const url = new URL(window.location);

            if (value === null || value === 'false' || value === '') {
                url.searchParams.delete(param);
            } else {
                url.searchParams.set(param, value);
            }

            window.history.replaceState({}, '', url);

            // 派发参数变化事件
            window.dispatchEvent(new CustomEvent('urlparameterschanged', {
                detail: { param, value }
            }));
        }
    }

    // 初始化全屏管理器
    document.addEventListener('DOMContentLoaded', () => {
        window.dashboardFullscreenManager = new DashboardFullscreenManager();
    });

事件处理

    // 监听全屏事件
    window.addEventListener('dashboardfullscreenchange', (event) => {
        const {
            isFullscreen,
            fullscreenModeEnabled,
            forceHideEnabled,
            forceHideActive,
            fullscreenHideActive
        } = event.detail;

        console.log('全屏状态变化:', event.detail);

        // 基于全屏状态更新 UI
        updateUIForFullscreenState(event.detail);

        // 调整图表和可视化
        if (fullscreenHideActive || forceHideActive) {
            resizeChartsForFullscreen();
        }

        // 保存状态到 localStorage
        saveFullscreenState(event.detail);
    });

    function updateUIForFullscreenState(state) {
        // 更新依赖于全屏的 UI 元素
        const dashboard = document.querySelector('.dashboard');

        if (dashboard) {
            if (state.forceHideActive) {
                dashboard.classList.add('force-hide-active');
                dashboard.classList.remove('fullscreen-active');
            } else if (state.fullscreenHideActive) {
                dashboard.classList.add('fullscreen-active');
                dashboard.classList.remove('force-hide-active');
            } else {
                dashboard.classList.remove('force-hide-active', 'fullscreen-active');
            }
        }

        // 更新状态指示器
        updateStatusIndicator(state);
    }

    function updateStatusIndicator(state) {
        let indicator = document.getElementById('fullscreen-status-indicator');

        if (!indicator) {
            indicator = document.createElement('div');
            indicator.id = 'fullscreen-status-indicator';
            indicator.style.cssText = `
                position: fixed;
                bottom: 10px;
                right: 10px;
                padding: 5px 10px;
                background: rgba(0,0,0,0.7);
                color: white;
                border-radius: 3px;
                font-size: 12px;
                z-index: 10000;
            `;
            document.body.appendChild(indicator);
        }

        if (state.forceHideActive) {
            indicator.textContent = 'Force Hide Mode';
            indicator.style.background = '#dc2626';
        } else if (state.fullscreenHideActive) {
            indicator.textContent = 'Fullscreen Mode';
            indicator.style.background = '#059669';
        } else {
            indicator.textContent = 'Normal Mode';
            indicator.style.background = '#6b7280';
        }
    }

    function resizeChartsForFullscreen() {
        // 调整图表以利用全屏空间
        const charts = document.querySelectorAll('.chart-container canvas');

        charts.forEach(canvas => {
            const chart = window.Chart.getChart(canvas);
            if (chart) {
                chart.resize();
            }
        });

        // 触发窗口调整大小事件以供其他组件使用
        window.dispatchEvent(new Event('resize'));
    }

    function saveFullscreenState(state) {
        // 保存到 localStorage 以实现持久化
        localStorage.setItem('dashboard_fullscreen_state', JSON.stringify({
            timestamp: new Date().toISOString(),
            state: state
        }));
    }

实用函数

    // 全屏实用函数
    const DashboardFullscreenUtils = {

        // 检查是否支持全屏
        isFullscreenSupported() {
            return !!(
                document.fullscreenEnabled ||
                document.webkitFullscreenEnabled ||
                document.mozFullScreenEnabled ||
                document.msFullscreenEnabled
            );
        },

        // 获取当前全屏元素
        getFullscreenElement() {
            return (
                document.fullscreenElement ||
                document.webkitFullscreenElement ||
                document.mozFullScreenElement ||
                document.msFullscreenElement
            );
        },

        // 检查数据看板是否处于全屏模式
        isDashboardFullscreen() {
            const element = this.getFullscreenElement();
            return element === document.documentElement;
        },

        // 切换特定元素的全屏状态
        toggleElementFullscreen(element = document.documentElement) {
            if (!this.isFullscreenSupported()) {
                console.warn('此浏览器不支持全屏');
                return false;
            }

            if (this.getFullscreenElement()) {
                // 退出全屏
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.webkitExitFullscreen) {
                    document.webkitExitFullscreen();
                } else if (document.mozCancelFullScreen) {
                    document.mozCancelFullScreen();
                } else if (document.msExitFullscreen) {
                    document.msExitFullscreen();
                }
                return false;
            } else {
                // 进入全屏
                if (element.requestFullscreen) {
                    element.requestFullscreen();
                } else if (element.webkitRequestFullscreen) {
                    element.webkitRequestFullscreen();
                } else if (element.mozRequestFullScreen) {
                    element.mozRequestFullScreen();
                } else if (element.msRequestFullscreen) {
                    element.msRequestFullscreen();
                }
                return true;
            }
        },

        //  URL 获取全屏状态
        getFullscreenStateFromUrl() {
            const params = new URLSearchParams(window.location.search);

            return {
                hideInFullscreen: ['true', '1', 'yes'].includes(params.get('_hide_others_in_fullscreen')),
                forceHide: ['true', '1', 'yes'].includes(params.get('_force_hide_others')),
                rawParams: {
                    hideInFullscreen: params.get('_hide_others_in_fullscreen'),
                    forceHide: params.get('_force_hide_others'),
                }
            };
        },

        // 生成全屏 URL
        generateFullscreenUrl(options = {}) {
            const url = new URL(window.location);

            // 设置或清除参数
            if (options.hideInFullscreen !== undefined) {
                if (options.hideInFullscreen) {
                    url.searchParams.set('_hide_others_in_fullscreen', 'true');
                } else {
                    url.searchParams.delete('_hide_others_in_fullscreen');
                }
            }

            if (options.forceHide !== undefined) {
                if (options.forceHide) {
                    url.searchParams.set('_force_hide_others', 'true');
                } else {
                    url.searchParams.delete('_force_hide_others');
                }
            }

            return url.toString();
        },

        // 创建全屏控制 UI
        createFullscreenControls() {
            const container = document.createElement('div');
            container.className = 'fullscreen-controls';
            container.innerHTML = `
                <div class="btn-group">
                    <button class="btn-toggle-fullscreen" title="切换全屏">
                        <span class="icon">📺</span>
                        <span class="text">全屏</span>
                    </button>
                    <button class="btn-toggle-force-hide" title="切换强制隐藏">
                        <span class="icon">👁️</span>
                        <span class="text">强制隐藏</span>
                    </button>
                    <button class="btn-exit-fullscreen" title="退出全屏" style="display: none;">
                        <span class="icon">🚪</span>
                        <span class="text">退出</span>
                    </button>
                </div>
                <div class="status"></div>
            `;

            // 添加样式
            const styles = document.createElement('style');
            styles.textContent = `
                .fullscreen-controls {
                    position: fixed;
                    bottom: 20px;
                    right: 20px;
                    z-index: 9999;
                }
                .fullscreen-controls .btn-group {
                    display: flex;
                    gap: 5px;
                    background: rgba(0,0,0,0.8);
                    padding: 10px;
                    border-radius: 5px;
                }
                .fullscreen-controls button {
                    background: #4b5563;
                    color: white;
                    border: none;
                    padding: 8px 12px;
                    border-radius: 3px;
                    cursor: pointer;
                    display: flex;
                    align-items: center;
                    gap: 5px;
                }
                .fullscreen-controls button:hover {
                    background: #6b7280;
                }
                .fullscreen-controls .status {
                    margin-top: 5px;
                    font-size: 12px;
                    color: #9ca3af;
                    text-align: center;
                }
            `;
            document.head.appendChild(styles);

            // 添加事件监听器
            const toggleFsBtn = container.querySelector('.btn-toggle-fullscreen');
            const toggleForceBtn = container.querySelector('.btn-toggle-force-hide');
            const exitBtn = container.querySelector('.btn-exit-fullscreen');
            const status = container.querySelector('.status');

            toggleFsBtn.addEventListener('click', () => {
                const current = this.getFullscreenStateFromUrl();
                const newUrl = this.generateFullscreenUrl({
                    hideInFullscreen: !current.hideInFullscreen,
                    forceHide: false, // 启用全屏时禁用强制隐藏
                });
                window.location.href = newUrl;
            });

            toggleForceBtn.addEventListener('click', () => {
                const current = this.getFullscreenStateFromUrl();
                const newUrl = this.generateFullscreenUrl({
                    forceHide: !current.forceHide,
                    hideInFullscreen: false, // 启用强制隐藏时禁用全屏隐藏
                });
                window.location.href = newUrl;
            });

            exitBtn.addEventListener('click', () => {
                window.dashboardFullscreenManager?.exitFullscreen();
            });

            // 基于状态更新 UI
            const updateUI = () => {
                const state = this.getFullscreenStateFromUrl();
                const isFullscreen = this.getFullscreenElement();

                toggleFsBtn.classList.toggle('active', state.hideInFullscreen);
                toggleForceBtn.classList.toggle('active', state.forceHide);
                exitBtn.style.display = isFullscreen ? 'flex' : 'none';

                if (state.forceHide) {
                    status.textContent = '强制隐藏激活';
                } else if (state.hideInFullscreen && isFullscreen) {
                    status.textContent = '全屏模式';
                } else if (state.hideInFullscreen) {
                    status.textContent = '全屏就绪(按 F11)';
                } else {
                    status.textContent = '普通模式';
                }
            };

            // 初始更新
            updateUI();

            // 监听变化
            window.addEventListener('dashboardfullscreenchange', updateUI);
            window.addEventListener('resize', updateUI);

            return container;
        }
    };

    // 向页面添加控件
    document.addEventListener('DOMContentLoaded', () => {
        if (DashboardFullscreenUtils.isFullscreenSupported()) {
            const controls = DashboardFullscreenUtils.createFullscreenControls();
            document.body.appendChild(controls);
        }
    });

浏览器兼容性

支持的浏览器

跨浏览器的 Fullscreen API 支持:

浏览器 版本 Fullscreen API 前缀 备注
Chrome 15+ webkit 完全支持
Firefox 10+ moz 完全支持
Safari 5.1+ webkit 完全支持
Edge 12+ ms 完全支持
Opera 12.1+ - 完全支持
IE 11 ⚠️ ms 部分支持,已弃用

功能检测

    // 全面的功能检测
    const FullscreenSupport = {

        // 检查全屏支持
        supported: !!(document.fullscreenEnabled ||
                     document.webkitFullscreenEnabled ||
                     document.mozFullScreenEnabled ||
                     document.msFullscreenEnabled),

        // 检查特定供应商API
        vendors: {
            standard: 'fullscreenEnabled' in document,
            webkit: 'webkitFullscreenEnabled' in document,
            moz: 'mozFullScreenEnabled' in document,
            ms: 'msFullscreenEnabled' in document
        },

        // 获取适当的方法名称
        methods: {
            requestFullscreen: (
                document.documentElement.requestFullscreen ||
                document.documentElement.webkitRequestFullscreen ||
                document.documentElement.mozRequestFullScreen ||
                document.documentElement.msRequestFullscreen
            ),
            exitFullscreen: (
                document.exitFullscreen ||
                document.webkitExitFullscreen ||
                document.mozCancelFullScreen ||
                document.msExitFullscreen
            ),
            fullscreenElement: (
                document.fullscreenElement ||
                document.webkitFullscreenElement ||
                document.mozFullScreenElement ||
                document.msFullscreenElement
            ),
            fullscreenEnabled: (
                document.fullscreenEnabled ||
                document.webkitFullscreenEnabled ||
                document.mozFullScreenEnabled ||
                document.msFullscreenEnabled
            ),
            fullscreenchange: (
                'onfullscreenchange' in document ? 'fullscreenchange' :
                'onwebkitfullscreenchange' in document ? 'webkitfullscreenchange' :
                'onmozfullscreenchange' in document ? 'mozfullscreenchange' :
                'onMSFullscreenChange' in document ? 'MSFullscreenChange' : null
            )
        },

        // 测试全屏功能
        test() {
            if (!this.supported) {
                return {
                    supported: false,
                    message: 'Fullscreen API 不支持'
                };
            }

            const tests = {
                canEnter: typeof this.methods.requestFullscreen === 'function',
                canExit: typeof this.methods.exitFullscreen === 'function',
                canDetect: typeof this.methods.fullscreenElement !== 'undefined',
                events: !!this.methods.fullscreenchange
            };

            const allPassed = Object.values(tests).every(Boolean);

            return {
                supported: this.supported,
                tests: tests,
                allPassed: allPassed,
                vendor: Object.entries(this.vendors).find(([_, v]) => v)?.[0] || 'unknown'
            };
        }
    };

    // 用法
    console.log('Fullscreen support:', FullscreenSupport.test());

旧版浏览器 Polyfill

    // 旧版浏览器简单 polyfill
    if (!FullscreenSupport.supported) {
        console.warn('全屏 API 不支持,使用回退方案');

        // 回退方案使用 CSS zoom/transform 模拟全屏
        document.addEventListener('DOMContentLoaded', () => {
            // 添加回退样式
            const style = document.createElement('style');
            style.textContent = `
                .dashboard-fullscreen-fallback {
                    position: fixed !important;
                    top: 0 !important;
                    left: 0 !important;
                    right: 0 !important;
                    bottom: 0 !important;
                    width: 100vw !important;
                    height: 100vh !important;
                    z-index: 99999 !important;
                    background: white !important;
                    overflow: auto !important;
                    margin: 0 !important;
                    padding: 20px !important;
                }

                .dashboard-fullscreen-fallback #header,
                .dashboard-fullscreen-fallback #footer,
                .dashboard-fullscreen-fallback .sidebar {
                    display: none !important;
                }

                @media (prefers-color-scheme: dark)
                }
            `;
            document.head.appendChild(style);

            // 覆盖全屏管理器方法
            const originalEnterFullscreen = window.dashboardFullscreenManager?.enterFullscreen;
            const originalExitFullscreen = window.dashboardFullscreenManager?.exitFullscreen;

            if (window.dashboardFullscreenManager) {
                window.dashboardFullscreenManager.enterFullscreen = function() {
                    console.log('使用回退全屏');
                    document.documentElement.classList.add('dashboard-fullscreen-fallback');
                    this.isFullscreen = true;
                    this.applyFullscreenState();
                    this.dispatchFullscreenChangeEvent();
                };

                window.dashboardFullscreenManager.exitFullscreen = function() {
                    console.log('退出回退全屏');
                    document.documentElement.classList.remove('dashboard-fullscreen-fallback');
                    this.isFullscreen = false;
                    this.applyFullscreenState();
                    this.dispatchFullscreenChangeEvent();
                };
            }
        });
    }

移动浏览器注意事项

    // 移动设备特定的全屏处理
    if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
        console.log('检测到移动浏览器,调整全屏行为');

        // 移动浏览器有不同全屏行为
        document.addEventListener('DOMContentLoaded', () => {
            // 在移动设备上禁用某些功能
            const manager = window.dashboardFullscreenManager;
            if (manager) {
                // 在移动设备上强制隐藏可能比全屏更有用
                manager.fullscreenModeEnabled = false;

                // 添加移动设备特定的控件
                const mobileNotice = document.createElement('div');
                mobileNotice.className = 'mobile-fullscreen-notice';
                mobileNotice.innerHTML = `
                    <p>📱 检测到移动浏览器</p>
                    <p>使用"强制隐藏"获得最佳体验</p>
                    <button class="enable-force-hide">启用强制隐藏</button>
                `;
                mobileNotice.style.cssText = `
                    position: fixed;
                    bottom: 10px;
                    left: 10px;
                    right: 10px;
                    background: rgba(0,0,0,0.9);
                    color: white;
                    padding: 15px;
                    border-radius: 5px;
                    z-index: 10000;
                    text-align: center;
                `;

                document.body.appendChild(mobileNotice);

                // 为按钮添加事件监听器
                mobileNotice.querySelector('.enable-force-hide').addEventListener('click', () => {
                    manager.enableForceHide(true);
                    mobileNotice.style.display = 'none';
                });

                // 10 秒后自动隐藏通知
                setTimeout(() => {
                    mobileNotice.style.opacity = '0';
                    setTimeout(() => {
                        mobileNotice.style.display = 'none';
                    }, 500);
                }, 10000);
            }
        });
    }

使用场景

演示模式

    # 演示模式配置

    class PresentationDashboard(Dashboard):
        """为演示优化的数据看板"""

        hide_others_in_fullscreen = True
        force_hide_others = False

        # 演示特定设置

        presentation_settings = {
            'large_fonts': True,
            'high_contrast': True,
            'simple_layout': True,
            'auto_advance': False,
            'show_timer': True,
        }

        def get_layout(self):
            layout = super().get_layout()

            # 简化演示布局

            if self.presentation_settings['simple_layout']:
                layout = self.get_simple_presentation_layout()

            # 添加演示控件

            if self.presentation_settings['show_timer']:
                layout.add_component(self.create_timer_component())

            return layout

        def get_context_data(self, request):
            context = super().get_context_data(request)

            # 添加演示上下文

            context['presentation_mode'] = True
            context['presentation_settings'] = self.presentation_settings

            # 生成演示 URL

            from urllib.parse import urlencode
            context['presentation_url'] = (
                request.build_absolute_uri('/admin/') + '?' + urlencode({
                    '_hide_others_in_fullscreen': 'true',
                    '_dark_mode_on': 'true',
                    '_view': 'presentation',
                })
            )

            return context

数据看板

    # 用于 TV/监视器显示的监控数据看板

    class MonitoringDashboard(Dashboard):
        """用于持续监控的数据看板"""

        force_hide_others = True  # 始终隐藏界面

        hide_others_in_fullscreen = False

        # 监控设置

        monitoring_settings = {
            'refresh_interval': 30,  # 秒

            'show_status': True,
            'alert_threshold': 90,   # 百分比

            'auto_refresh': True,
        }

        def get_layout(self):
            layout = super().get_layout()

            # 添加监控特定组件

            layout.add_component(self.create_uptime_component())
            layout.add_component(self.create_performance_component())
            layout.add_component(self.create_alerts_component())

            # 设置自动刷新

            if self.monitoring_settings['auto_refresh']:
                layout.meta_refresh = self.monitoring_settings['refresh_interval']

            return layout

        def get_context_data(self, request):
            context = super().get_context_data(request)

            # 添加监控上下文

            context['monitoring_mode'] = True
            context['refresh_interval'] = self.monitoring_settings['refresh_interval']

            # 生成监控 URL

            context['monitoring_url'] = self.generate_monitoring_url(request)

            return context

        def generate_monitoring_url(self, request):
            """为监控显示生成 URL"""
            from urllib.parse import urlencode

            params = {
                '_force_hide_others': 'true',
                '_dark_mode_on': 'true',
                '_refresh': str(self.monitoring_settings['refresh_interval']),
                '_view': 'monitoring',
            }

            return request.build_absolute_uri('/admin/') + '?' + urlencode(params)

信息亭模式

    # 公共显示的信息亭模式

    class KioskDashboard(Dashboard):
        """用于信息亭/公共显示的数据看板"""

        force_hide_others = True
        hide_others_in_fullscreen = False

        # 信息亭安全设置

        kiosk_settings = {
            'disable_input': True,
            'disable_right_click': True,
            'auto_logout': 300,  # 5 分钟

            'restricted_access': True,
            'rotation_interval': 60,  # 数据看板轮换间隔(秒)

        }

        def get_layout(self):
            layout = super().get_layout()

            # 添加信息亭通知

            layout.add_component(self.create_kiosk_notice_component())

            # 如果启用,设置轮换

            if self.kiosk_settings['rotation_interval'] > 0:
                layout.meta_refresh = self.kiosk_settings['rotation_interval']

            return layout

        def dispatch(self, request, *args, **kwargs):
            # 信息亭安全检查

            if self.kiosk_settings['restricted_access']:
                # 仅允许特定 IP 或网络

                allowed_ips = getattr(settings, 'KIOSK_ALLOWED_IPS', []);
                client_ip = request.META.get('REMOTE_ADDR')

                if allowed_ips and client_ip not in allowed_ips:
                    from django.http import HttpResponseForbidden
                    return HttpResponseForbidden("信息亭访问受限")

            return super().dispatch(request, *args, **kwargs)

        def get_context_data(self, request):
            context = super().get_context_data(request)

            # 添加用于禁用输入的信息亭 JavaScript

            if self.kiosk_settings['disable_input'] or self.kiosk_settings['disable_right_click']:
                context['kiosk_js'] = self.get_kiosk_javascript()

            # 添加自动注销计时器

            if self.kiosk_settings['auto_logout']:
                context['auto_logout_seconds'] = self.kiosk_settings['auto_logout']

            return context

        def get_kiosk_javascript(self):
            """为信息亭模式生成 JavaScript"""
            js = [];

            if self.kiosk_settings['disable_right_click']:
                js.append('''
                    document.addEventListener('contextmenu', function(e) {
                        e.preventDefault();
                        return false;
                    });
                ''')

            if self.kiosk_settings['disable_input']:
                js.append('''
                    // 禁用退出全屏的键盘快捷键
                    document.addEventListener('keydown', function(e) {
                        if (e.key === 'F11' ||
                            (e.ctrlKey && e.key === 'f') ||
                            (e.key === 'Escape')) {
                            e.preventDefault();
                            return false;
                        }
                    });
                ''')

            if self.kiosk_settings['disable_input']:
                js.append('''
                    // Disable keyboard shortcuts for exiting fullscreen
                    document.addEventListener('keydown', function(e) {
                        if (e.key === 'F11' ||
                            (e.ctrlKey && e.key === 'f') ||
                            (e.key === 'Escape')) {
                            e.preventDefault();
                            return false;
                        }
                    });
                ''')

            return '\n'.join(js)

故障排除

常见问题与解决方案

1. 全屏无法工作

症状: 浏览器未进入全屏,或元素未隐藏。

解决方案: - Check browser support using FullscreenSupport.测试() - Ensure 数据看板 has hide_others_in_fullscreen = True or force_hide_others = True - Check JavaScript console for errors - Verify URL parameters are correct (case-sensitive)

    // Debug fullscreen
    console.log('Fullscreen support:', FullscreenSupport.test());
    console.log('URL params:', new URLSearchParams(window.location.search).toString());
    console.log('Dashboard config:', window.dashboardFullscreenManager);

2. 元素未隐藏

症状: URL 参数有效但元素仍然可见。

解决方案: - Check CSS selectors match your Django Admin 主题 - 验证 CSS 已加载(检查 Network 标签页) - 检查 CSS 特异性问题 - 尝试向 CSS 规则添加 !重要

    /* 调试高亮应隐藏的元素 */
    #header, #footer, .sidebar {
        border: 3px solid red !important;
    }

3. 可见元素闪烁 (FOVE)

症状: 元素在被隐藏前短暂出现。

解决方案: - 通过内联样式初始隐藏 - 使用不依赖 JavaScript 的 CSS - 在模板中为关键元素添加 显示: none

    <style>
        /* 如果存在全屏参数立即隐藏关键元素 */
        {% if request.GET._hide_others_in_fullscreen == 'true' or request.GET._force_hide_others == 'true' %}
        #header, #footer, .sidebar {
            display: none !important;
        }
        {% endif %}
    </style>

4. 浏览器兼容性问题

症状: 在一个浏览器中工作,但在另一个中不工作。

解决方案: - 对旧版浏览器使用 polyfill - 检查供应商前缀 - 在不同浏览器中测试

    // 检查正在使用哪个供应商 API
    console.log('活跃供应商:', FullscreenSupport.test().vendor);

5. 性能问题

症状: 全屏过渡缓慢或卡顿。

解决方案: - 减少隐藏的元素数量 - 简化 CSS 选择器 - 使用 CSS transforms 代替布局属性 - 对快速全屏变化进行防抖处理

调试工具

浏览器开发工具

  1. Elements Panel: Check for dashboard-fullscreen-mode and dashboard-force-hide-others classes
  2. Console: Check for JavaScript errors from fullscreen manager
  3. Network Panel: Verify CSS and JS files are loading
  4. 应用程序 Panel: Check localStorage for saved state

调试 CSS

    /* 添加到 dashboard.css 进行调试 */
    .dashboard-fullscreen-mode::after {
        content: '全屏模式激活';
        position: fixed;
        top: 10px;
        left: 10px;
        background: red;
        color: white;
        padding: 5px;
        z-index: 9999;
        font-size: 12px;
    }

    .dashboard-force-hide-others::after {
        content: '强制隐藏激活';
        position: fixed;
        top: 10px;
        left: 10px;
        background: blue;
        color: white;
        padding: 5px;
        z-index: 9999;
        font-size: 12px;
    }

    /* Highlight hidden elements */
    #header, #footer, .sidebar {
        transition: outline 0.3s ease;
    }

    .dashboard-fullscreen-mode #header,
    .dashboard-fullscreen-mode #footer,
    .dashboard-fullscreen-mode .sidebar,
    .dashboard-force-hide-others #header,
    .dashboard-force-hide-others #footer,
    .dashboard-force-hide-others .sidebar {
        outline: 3px dashed red !important;
    }

JavaScript 调试助手

    // 添加到浏览器控制台进行调试
    window.debugFullscreen = function() {
        console.group('全屏调试');

        // 检查管理器
        const manager = window.dashboardFullscreenManager;
        if (manager) {
            console.log('Manager state:', {
                isFullscreen: manager.isFullscreen,
                fullscreenModeEnabled: manager.fullscreenModeEnabled,
                forceHideEnabled: manager.forceHideEnabled
            });
        }

        // 检查 DOM 
        console.log('DOM 类 - html:', document.documentElement.className);
        console.log('DOM 类 - body:', document.body.className);

        // 检查 URL 参数
        const params = new URLSearchParams(window.location.search);
        console.log('URL parameters:', {
            hideInFullscreen: params.get('_hide_others_in_fullscreen'),
            forceHide: params.get('_force_hide_others')
        });

        // 检查元素可见性
        const elements = ['#header', '#footer', '.sidebar'];
        elements.forEach(selector => {
            const el = document.querySelector(selector);
            console.log(`${selector}:`, el ? {
                exists: true,
                display: getComputedStyle(el).display,
                visible: el.offsetParent !== null
            } : { exists: false });
        });

        console.groupEnd();
    };

获取帮助

如果仍有问题:

  1. 检查文档:查看本指南和 URL 控制文档
  2. 使用基础设置测试:创建最小测试用例以隔离问题
  3. 检查浏览器控制台:查找错误消息
  4. 与示例比较:检查示例在您的环境中是否工作
  5. 报告问题:包括浏览器版本、Django 版本和重现步骤

后续步骤