首页 > 解决方案 > 使用 css 在单击更多按钮时带来上下文菜单

问题描述

我的要求是在单击树节点上的更多按钮时显示一个菜单。它应该靠近单击的节点。您可以看到更多选项图标仅悬停在树节点上。以下是我现在使用的 HTML 和 CSS 代码。

.tree ul {
    margin-left: 20px;
}

.tree li {
    list-style-type: none;
    margin:15px;
    position: relative;
    cursor: pointer;
}

.tree li .submenuBtn{
    margin-left:8px;
    display: none;
    font-weight:bolder;
}

.tree li a:hover .submenuBtn{
    display: inline-block;
}

.tree li img::clicked + #contextMenu{
    display: inline-block;
}

.tree li::before {
    content: "";
    position: absolute;
    top:-7px;
    left:-20px;
    border-left: 1px solid #ccc;
    border-bottom:1px solid #ccc;
    border-radius:0 0 0 0px;
    width:20px;
    height:15px;
}

.tree li::after {
    position:absolute;
    content:"";
    top:8px;
    left:-20px;
    border-left: 1px solid #ccc;
    border-top:1px solid #ccc;
    border-radius:0px 0 0 0;
    width:20px;
    height:100%;
}

.tree li:last-child::after  {
    display:none;
}

.tree li:last-child:before{
    border-radius: 0 0 0 5px;
}

ul.tree>li:first-child::before {
    display:none;
}

ul.tree>li:first-child::after {
    border-radius:5px 0 0 0;
}

.tree li a {
    border: 1px #ccc solid;
    border-radius: 5px;
    padding:5px 10px;
}

.tree li a:hover, .tree li a:hover+ul li a,
.tree li a:focus, .tree li a:focus+ul li a {
    background: #ccc; color: #000; 
    /*border: 1px solid #000;*/
    text-decoration: none;
}

.tree li a:hover+ul li::after, .tree li a:focus+ul li::after,
.tree li a:hover+ul li::before, .tree li a:focus+ul li::before 
.tree li a:hover+ul::before, .tree li a:focus+ul::before 
.tree li a:hover+ul ul::before, .tree li a:focus+ul ul::before{
    /*border-color:  #000; */
    /*connector color on hover*/
}
<ul class="tree">
            <li><a>Parent 1 <div class="submenuBtn">:</div></a></li>
            <li><a>Parent 2<div class="submenuBtn">:</div></a></li>
            <li>
                <a>Parent 3<div class="submenuBtn">:</div></a>
                <ul>
                    <li>
                        <a>1st Child of 3<div class="submenuBtn">:</div></a>
                        <ul>
                            <li><a>1st grandchild<div class="submenuBtn">:</div></a></li>
                            <li><a>2nd grandchild<div class="submenuBtn">:</div></a></li>
                        </ul>
                    </li>
                    <li><a>2nd Child of 3<div class="submenuBtn">:</div></a></li>
                    <li><a>3rd Child of 3<div class="submenuBtn">:</div></a></li>
                </ul>
            </li>
            <li>
                <a>Parent 4<div class="submenuBtn">:</div></a>
                <ul><li><a>Parent 4's only child<div class="submenuBtn">:</div></a></li></ul>
            </li>
        </ul>

是否可以为此目的重用单个上下文菜单,或者我需要将菜单与每个节点一起添加。

标签: javascripthtmlcss

解决方案


通过模板重用上下文菜单当然更有效,而不是重复菜单作为每个节点的子元素。

Javascript是要走的路。

有很多方法可以在 JS 中进行模板化。您可以查看诸如MustacheHandlebarsUnderscore之类的模板系统,尤其是当您需要在所有地方进行模板时,例如在单页应用程序中。

如果你的模板需求是一次性的,那么你可以做一个简单的 Javascript 解决方案,如下所示:

1.定义模板

选项 1 - 将模板完全存储在 JS 中:

var myTemplate = '<h1>MENU</h1><div class="menu_links"><a href="link1.html" class="menu_link">Link 1</a><a href="link2.html" class="menu_link">Link 2</a></div>';

选项 2 - 将模板存储在页面中:

作为一个 HTML 元素,用 CSS 从视图中隐藏,但仍然在页面 DOM 中......

<div id="template_menu" style="visibility: hidden;"><h1>MENU</h1><div class="menu_links"><a href="link1.html" class="menu_link">Link 1</a><a href="link2.html" class="menu_link">Link 2</a></div></div>

...或者在一个脚本标签中,它完全将它从页面 DOM 中隐藏起来,不需要 CSS,但仍然可以被 JS 访问:

<script id="template_menu" type="x-template">
    <h1>MENU</h1><div class="menu_links"><a href="link1.html" class="menu_link">Link 1</a><a href="link2.html" class="menu_link">Link 2</a></div>
</script>

选项 2 续:在任何一种情况下,如果模板存储在页面中,则需要在 JS 中声明元素:

var myTemplate = document.getElementById("template_menu");

2.在JS中使用菜单模板

最终,除了一堆其他 JS 函数和侦听器之外,您将如何使用模板来获得完整的体验:

function openSubMenu(e) {

    // First, make a new element
    var newElement = document.createElement("div");

    // Apply the contents of the template to your new element
    newElement.innerHTML = myTemplate.innerHTML;  

    // Append the new element into the DOM. Here I'm adding it to the parent of the clicked element, but it's up to you how you want to structure things.
    e.parentElement.appendChild(newElement);
}

最终可能会有一个聪明、笨拙的纯 CSS 解决方案,可能使用 HTML5 数据属性和隐藏的复选框,但会牺牲一些花里胡哨的东西。在模板和弹出窗口方面,相比之下,Javascript 具有相对无限的潜力。

附带说明一下,我会避免任何“悬停”功能,因为任何触摸屏用户都会对此有疑问,并且您将在 JS 中管理更多状态。如果您确实实现了悬停功能,您可能会发现最好在 JS 中与其他侦听器一起管理它,而不是在 CSS :hover 和 JS 之间折腾。


推荐阅读