Flask Jinja模板中Bootstrap5 Popover报错不生效问题
问题根因
bootstrap is not defined报错有三个核心诱因:一是自定义初始化脚本放在了content块中,该块渲染位置早于Bootstrap JS bundle的引入位置,浏览器执行初始化代码时Bootstrap全局对象还未加载;二是page_2.jinja开头的模板继承标签语法错误,缺失左大括号,会导致模板渲染顺序异常;三是原基础模板未引入Bootstrap CSS文件,组件样式本身无法正常加载。- 弹出层默认常驻显示:手动编写了带
show类、固定定位内联样式的Popover DOM结构,Bootstrap Popover组件会自动生成弹出层DOM,无需手动预写,手动添加的结构默认就会展示在页面上。同时原配置中data-bs-content传的是字符串nav_dropdown,Bootstrap会默认将其作为纯文本渲染,不会自动匹配对应id的DOM内容;且img标签默认不可聚焦,data-bs-trigger="focus"配置无法正常生效。
修复步骤
- 调整基础模板结构:在head标签中补充Bootstrap CSS引入,在Bootstrap JS引入语句后新增专属的
scripts块,所有页面自定义JS都放到该块中,保证Bootstrap加载完成后再执行自定义逻辑。 - 修正子模板语法:补全page_2.jinja开头继承标签缺失的左大括号,使用标准Jinja2继承语法。
- 移除手动编写的常驻Popover DOM结构,将自定义下拉内容存入
<template>标签中,该标签内的内容默认不会渲染到页面上。 - 调整触发元素配置:给头像img标签添加
tabindex="0"属性保证元素可被聚焦,初始化Popover时开启HTML内容渲染,将content指向自定义模板的内容,固定弹出位置。 - 将Popover初始化代码挪到基础模板预留的
scripts块中。
修正后代码示例
基础模板 layout.jinja2
<!DOCTYPE html> <html lang="en"> <head> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.png') }}"> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <!-- 补充Bootstrap CSS引入 --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous"> <title>{{ title }}</title> </head> <body class="{{template}}"> <div class="container"> {% block content %} {% endblock %} </div> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script> <!-- 新增自定义脚本块,放在Bootstrap加载之后 --> {% block scripts %}{% endblock %} </body> </html>
子模板 page_2.jinja
{# 修正继承标签语法错误 #} {% extends "layout.jinja2" %} {% block content %} <nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <div class="container-fluid"> <a class="navbar-brand" href="/">My Page</a> <div class="collapse navbar-collapse" id="navbarColor01"> <ul class="navbar-nav me-auto"> {% if current_user.is_authenticated %} {% for app in current_user.app_permissions %} {% if app == 'settings' %} {% continue %} {% endif %} <li class="nav-item"> <a class="nav-link active" href="{{ url_for(get_app_url(app)) }}">{{ app.capitalize() }}</a> </li> {% endfor %} {% endif %} </ul> <ul class="navbar-nav me-right"> {% if current_user.is_authenticated %} <div> {# 补充tabindex属性,移除错误的data-bs-content配置 #} <img id="menu" src="/assets/user_icon.png" data-bs-toggle="popover" data-bs-trigger="focus" tabindex="0" style="width: 32px; height: 32px; cursor: pointer;"> </div> {% else %} <form class="d-flex" method="POST" action="/login"> <input class="form-control me-sm-2" type="email" name="email" placeholder="email"> <input class="form-control me-sm-2" type="password" name="password" placeholder="password"> <button class="btn btn-secondary my-2 my-sm-0" type="submit">Login</button> </form> {% endif %} </ul> </div> </div> </nav> {# 自定义弹出内容放到template标签内,默认不显示 #} <template id="nav_dropdown_content"> <ul class="list-group" style="min-width: 120px;"> <a href="/settings" class="list-group-item list-group-item-action">Settings</a> <a href="/logout" class="list-group-item list-group-item-action">Logout</a> </ul> </template> {% endblock %} {% block scripts %} <script type="text/javascript"> var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')) var popoverList = popoverTriggerList.map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl, { html: true, // 允许渲染HTML内容 content: document.getElementById('nav_dropdown_content').innerHTML, // 加载自定义内容 placement: 'bottom' // 固定在触发元素下方弹出 }) }) </script> {% endblock %}
效果说明
修复后页面加载时不会再弹出JS报错,下拉菜单默认隐藏,点击用户头像会正常弹出Popover菜单,点击页面其他区域时菜单自动收起,全程无需引入jQuery,不会和现有React代码产生冲突。
内容的提问来源于stack exchange,提问作者user1772250
相关产品推荐
相关产品推荐

