Far*_*har 4 css jquery bootstrap-5
我正在创建一个包含多行的表,所有行都有一个“选项”按钮,该按钮应该显示下拉上下文菜单。为了使代码更短,我使用单个代码div,以便将其重用为上下文菜单的通用标记。
我正在使用 Bootstrap 5.1.3 和 jQuery 3.6.0。以下是我的代码:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test Code</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</head>
<body>
<table id="myTable" class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Document</th>
<th>Reference</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>General Policies</td>
<td>GP-01-2022</td>
<td>
<div class="dropdown">
<a href="#" class="btn btn-primary optionsButton" data-bs-toggle="dropdown" aria-expanded="false" id="doc1">Options</a>
</div>
</td>
</tr>
<tr>
<td>2</td>
<td>Training Material</td>
<td>GP-02-2022</td>
<td>
<div class="dropdown">
<a href="#" class="btn btn-primary optionsButton" data-bs-toggle="dropdown" aria-expanded="false" id="doc2">Options</a>
</div>
</td>
</tr>
</tbody>
</table>
<ul id="contextMenu" class="dropdown-menu">
<li><a tabindex="-1" href="#" class="dropdown-item downloadLink">Download</a></li>
<li><a tabindex="-1" href="#" class="dropdown-item propertiesLink">Properties</a></li>
</ul>
<script>
//save the selector so you don't have to do the lookup everytime
var $dropdown = $('#contextMenu');
$('.optionsButton').click(function(event) {
//get document ID
var id = this.id;
//move dropdown menu
$(this).after($dropdown);
//update links
$dropdown.find(".downloadLink").attr("href", "/data/download?id=" + id);
$dropdown.find(".propertiesLink").attr("href", "/data/viewproperties?id=" + id);
//show dropdown
$(this).dropdown();
});
</script>
</body>
</html>Run Code Online (Sandbox Code Playgroud)
在这段代码中我面临两类问题。首先,下拉菜单未打开。当我在开发人员模式下检查代码时,我可以看到 jQuery 脚本成功地将 DIV 传输到contextmenu“选项”按钮下方,以便它按照 Bootstrap 的要求进行嵌套。但随后就$(this).dropdown();没有打开菜单。
第二个错误是,在开发人员模式控制台中,每次单击“选项”按钮时我都会看到此错误:
dropdown.js:285 未捕获类型错误:无法在“Window”上执行“getCompulatedStyle”:参数 1 不是“Element”类型。
并且此错误的堆栈跟踪指向dropdown.js,并没有指定错误在我的代码中的位置。
在尝试诊断问题时需要帮助。我对 Bootstrap 和 jQuery 相当陌生。谢谢。
TL;DR:不要#contextMenu移动到任何地方。阅读:解决方案*
\n您收到的错误
\n\n\ndropdown.js:285 Uncaught TypeError: 无法在“Window”上执行“getCompulatedStyle”:参数 1 不是“Element”类型。
\n
与Bootstrap (v5.1.3): dropdown.js代码相关:
\n// @l62:\nconst SELECTOR_MENU = \'.dropdown-menu\'\n\n// @l103:\n constructor(element, config) {\n super(element);\n //...\n this._menu = this._getMenuElement()\n //...\n }\n\n// @l269:\n _getMenuElement() {\n return SelectorEngine.next(this._element, SELECTOR_MENU)[0]\n }\n\n// @l285:\n _getPlacement() {\n // ...\n const isEnd = getComputedStyle(this._menu).getPropertyValue(\'--bs-position\').trim() === \'end\'\n // ...\n }\nRun Code Online (Sandbox Code Playgroud)\n这里:SelectorEngine.next(this._element,
.menu-dropdown正如您所看到的,除了 BS 硬编码的元素之外,没有办法向构造函数传递另一个元素,而该元素是方法 ~line285 中的下一个同级元素_getMenuElement()。
BS 为每个按钮分配一个“单击”事件,并data-bs-toggle="dropdown"盲目地期望切换下一个同级元素下拉列表 \xe2\x80\x94 ,而该下拉列表实际上并不存在(尚)!
我会:
\nDropdown,或者this._menu作为将任何所需元素作为;传递的一种方式 就像是:
constructor(element, config) {\n //...\n // Fix: allow for custom reusable menu Element\n this._menu = config.menuElement || this._getMenuElement()\n //...\n }\nRun Code Online (Sandbox Code Playgroud)\n免责声明:关于上述剥离代码,主分支中有一些更改,我不确定在撰写本文时这些问题是否已得到解决。
\n与此同时,您可以简单地做些什么,而不使用“mousedown”事件(比 BS 事件领先一步"click"- 就像在这个重复问题的答案中一样),并且不使用愚蠢的Event.stopPropagation()(这永远不应该)使用,除了你真的,真的知道你在做什么,或者仅用于调试目的) \xe2\x80\x94 是:
不要移动UL#contextMenuusing .after()or (with JS) .insertAdjacentElement(),而是在扩展 Popper 实例的实例化时更改预期的 Bootstrapthis._menu属性以指向所需的可重用元素 \xe2\x80\x94 你的体内“#contextMenu”,例如:
<!doctype html>\n<html lang="en">\n\n<head>\n <meta charset="utf-8">\n <meta name="viewport" content="width=device-width, initial-scale=1">\n <title>Test Code</title>\n <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">\n</head>\n\n<body>\n <table id="myTable" class="table table-hover">\n <thead>\n <tr>\n <th>#</th>\n <th>Document</th>\n <th>Reference</th>\n <th>Action</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>1</td>\n <td>General Policies</td>\n <td>GP-01-2022</td>\n <td>\n <div class="dropdown">\n <button type="button" class="btn btn-primary optionsButton" data-bs-toggle="dropdown" aria-expanded="false" id="doc1">Options</button>\n </div>\n </td>\n </tr>\n <tr>\n <td>2</td>\n <td>Training Material</td>\n <td>GP-02-2022</td>\n <td>\n <div class="dropdown">\n <button type="button" class="btn btn-primary optionsButton" data-bs-toggle="dropdown" aria-expanded="false" id="doc2">Options</button>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n\n <ul id="contextMenu" class="dropdown-menu">\n <li><button type="button" tabindex="-1" class="dropdown-item downloadLink">Download</button></li>\n <li><button type="button" tabindex="-1" class="dropdown-item propertiesLink">Properties</button></li>\n </ul>\n\n <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>\n\n <script>\n // DOM utility functions:\n const el = (sel, par) => (par || document).querySelector(sel);\n const els = (sel, par) => (par || document).querySelectorAll(sel);\n\n // Task: BS5 Popper fix for single static dropdown menu:\n const elDropdown = el(\'#contextMenu\');\n const elsBtns = els(".optionsButton");\n const dropdownList = [...elsBtns].map(function(elBtn) {\n const instance = new bootstrap.Dropdown(elBtn);\n instance._menu = elDropdown;\n return instance;\n });\n // console.log(dropdownList); \n </script>\n\n</body>\n\n</html>Run Code Online (Sandbox Code Playgroud)\r\n上面的好处是 DOM 中没有任何会触发回流的更改。Popper 代码将计算浮动 contextMenu 的最佳位置并称其为工作完成。
\n不太好的事情是,在动态添加 TR 元素到表的情况下应该特别小心;这意味着每个新添加的 Button 应在创建时实例化为new bootstrap.Dropdown(elBtn)
针对您最初想法的另一个(不太好的)解决方案是(不必要地)移动 DOM 中的下拉菜单。它可以使用"mousedown"事件来实现,以便在 BS 的事件触发之前“提前”移动下拉列表 \xe2\x80\x94 "click"(如此相关问题的答案中所建议的)。但这样将无法正常工作。单击一个又一个按钮,可以看到一闪而过的内容/故障(实际的下拉列表)。可能有一些方法可以缓解这个问题\xe2\x80\xa6 但是,为什么。无论如何,FYEO 这是代码:
<!doctype html>\n<html lang="en">\n\n<head>\n <meta charset="utf-8">\n <meta name="viewport" content="width=device-width, initial-scale=1">\n <title>Test Code</title>\n\n <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">\n</head>\n\n<body>\n <table id="myTable" class="table table-hover">\n <thead>\n <tr>\n <th>#</th>\n <th>Document</th>\n <th>Reference</th>\n <th>Action</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>1</td>\n <td>General Policies</td>\n <td>GP-01-2022</td>\n <td>\n <div class="dropdown">\n <button type="button" class="btn btn-primary optionsButton" data-bs-toggle="dropdown" aria-expanded="false" id="doc1">Options</button>\n </div>\n </td>\n </tr>\n <tr>\n <td>2</td>\n <td>Training Material</td>\n <td>GP-02-2022</td>\n <td>\n <div class="dropdown">\n <button type="button" class="btn btn-primary optionsButton" data-bs-toggle="dropdown" aria-expanded="false" id="doc2">Options</button>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n\n <ul id="contextMenu" class="dropdown-menu">\n <li><button type="button" tabindex="-1" class="dropdown-item downloadLink">Download</button></li>\n <li><button type="button" tabindex="-1" class="dropdown-item propertiesLink">Properties</button></li>\n </ul>\n\n <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>\n\n <script>\n // DOM utility functions:\n const el = (sel, par) => (par || document).querySelector(sel);\n const els = (sel, par) => (par || document).querySelectorAll(sel);\n\n // Task: BS5 Popper fix for single static dropdown menu:\n const elDropdown = el(\'#contextMenu\');\n const elsBtns = els(".optionsButton");\n\n const prepareDropdown = (evt) => {\n const elBtn = evt.currentTarget;\n elBtn.insertAdjacentElement("afterend", elDropdown);\n };\n\n elsBtns.forEach(elBtn => elBtn.addEventListener("mousedown", prepareDropdown));\n </script>\n\n\n</body>\n\n</html>Run Code Online (Sandbox Code Playgroud)\r\nPS:<button type="button">如果您不需要导航,而只是一个简单的 UI 交互按钮元素,请使用always 而不是 Anchors(如上面的示例)。
无论如何,BS 使用和实现弹出窗口、选择等的方式有点被破坏。如果弹出窗口(或模态窗口)已打开,则通过单击另一个按钮 \xe2\x80\x94 应立即显示第二个(或相同的)弹出窗口(而不是在第二次单击后)。这是设计中的 UI/UX 缺陷。Bootstrap 通常会非常奇怪地实现想法,但不要忘记您始终可以通过提供Pull Request来帮助开源社区。
\n如果您对如何使用 JavaScript \xe2\x80\x94 从头开始创建(类似)弹出窗口感兴趣,您可以在此处了解更多信息:在鼠标位置显示自定义弹出窗口。
\n