引导下拉菜单/子菜单状态更改



我是站点下拉功能的新手,目前正在开发使用带有子菜单的引导下拉菜单的应用程序。 当前引导菜单/子菜单层次结构有没有办法即使在移动鼠标直到您单击该区域之前也能保持活动状态?

这是我的 css:

<style>
li.dropdown-submenu a#shoppingMenuLabel{
transition-timing-function: ease-in-out 1s;
-moz-transition-timing-function: ease-in-out 1s;
-o-transition-timing-function: ease-in-out 1s;
-webkit-transition-timing-function: ease-in-out 1s;
transition-duration: 1s;
}
.fade {
opacity: 1;
transition: opacity .40s ease-in-out;
-moz-transition: opacity .40s ease-in-out;
-webkit-transition: opacity .40s ease-in-out;
}
#imageContainer img{
width: 427px;            
background-repeat: no-repeat;      
}
.dropdown-submenu {
position: initial;
}
ul.dropdown-menu{
transition-timing-function: ease-in 2s;
-moz-transition-timing-function: ease-in 2s;
-o-transition-timing-function: ease-in 2s;
-webkit-transition-timing-function: ease-in s;
transition-duration: 1s;
}
ul.dropdown-menu li a{
transition-timing-function: ease-out .50s;
-moz-transition-timing-function: ease-out .50s;
-o-transition-timing-function: ease-out .50s;
-webkit-transition-timing-function: ease-out .50s;
transition-duration: .50s;
}
ul.dropdown-menu li.dropdown-submenu{
transition-timing-function: ease-out 3s;
-moz-transition-timing-function: ease-out 3s;
-o-transition-timing-function: ease-out 3s;
-webkit-transition-timing-function: ease-out 3s;
transition-duration: 3s;
}        
ul.dropdown-menu li.dropdown-submenu a:hover{
font-weight: bold;
display:block
}
li.dropdown-submenu a ul.dropdown-menu{
transition: ease-out;
}
.dropdown-content a:hover{
background: transparent;
font-weight: bold;
}
li.dropdown-submenu a:hover{
font-weight: bold !important; 
}
.dropdown-submenu>.dropdown-menu {
top: 0;
left: 95%;
margin-top: -6px;
margin-left: -1px;
padding-left: 10px;
border: 0;
border-left: 2px solid #f1f1f1 !important;
}
.dropdown-submenu:hover>.dropdown-menu {
display: block;
}
.dropdown-submenu>a:after {
display: block;
content: " ";
float: right;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: searchResults.htmlccc;
margin-top: 5px;
margin-right: 0px;
}
.dropdown-submenu:hover>a:after {
border-left-color: searchResults.htmlfff;
}
.dropdown-submenu.pull-left {
float: none;
}
.dropdown-submenu.pull-left>.dropdown-menu {
left: -100%;
margin-left: 10px;
border: 0;
}
ul.mainDropDown {
margin: 0;
padding: 0;
}
ul.mainDropDown li {
list-style: none;
}
ul.dropdown-menu {
width: 285px;
}
li.dropdown-submenu a {
display: block;
}
@media only screen and (max-width: 800px) {
ul.dropdown-menu {
width: 150px;
}
}
ul.dropdown-menu > li > a.maintainHover {
color: white;
background-color: #0081C2;
}
</style>

这是 html

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
.dropdown-submenu {
position: relative;
}
.dropdown-submenu .dropdown-menu {
top: 0;
left: 100%;
margin-top: -1px;
}
</style>
</head>
<body>
<div class="container">
<h2>Multi-Level Dropdowns</h2>
<p>In this example, we have created a .dropdown-submenu class for multi-level dropdowns (see style section above).</p>
<p>Note that we have added jQuery to open the multi-level dropdown on click (see script section below).</p>                                        
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">Tutorials
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="#">HTML</a></li>
<li><a tabindex="-1" href="#">CSS</a></li>
<li class="dropdown-submenu">
<a class="test" tabindex="-1" href="#">New dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="#">2nd level dropdown</a></li>
<li><a tabindex="-1" href="#">2nd level dropdown</a></li>
<li class="dropdown-submenu">
<a class="test" href="#">Another dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">3rd level dropdown</a></li>
<li><a href="#">3rd level dropdown</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
<script>
$(document).ready(function(){
$('.dropdown-submenu a.test').on("click", function(e){
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
});
</script>
</body>
</html>

以下是 html 中的 jQuery 代码:

var $menu = $(".dropdown-menu");
// jQuery-menu-aim: <meaningful part of the example>
// Hook up events to be fired on menu row activation.
$menu.menuAim({
activate: activateSubmenu,
deactivate: deactivateSubmenu
});
// jQuery-menu-aim: </meaningful part of the example>
// jQuery-menu-aim: the following JS is used to show and hide the submenu
// contents. Again, this can be done in any number of ways. jQuery-menu-aim
// doesn't care how you do this, it just fires the activate and deactivate
// events at the right times so you know when to show and hide your submenus.
function activateSubmenu(row) {
var $row = $(row),
submenuId = $row.data("submenuId"),
$submenu = $("#" + submenuId),
height = $menu.outerHeight(),
width = $menu.outerWidth();
// Show the submenu
$submenu.css({
display: "block",
top: -1,
left: width - 3, // main should overlay submenu
height: height - 4 // padding for main dropdown's arrow
});
// Keep the currently activated row's highlighted look
$row.find("a").addClass("maintainHover");
}
function deactivateSubmenu(row) {
var $row = $(row),
submenuId = $row.data("submenuId"),
$submenu = $("#" + submenuId);
// Hide the submenu and remove the row's highlighted look
$submenu.css("display", "none");
$row.find("a").removeClass("maintainHover");
}
// Bootstrap's dropdown menus immediately close on document click.
// Don't let this event close the menu if a submenu is being clicked.
// This event propagation control doesn't belong in the menu-aim plugin
// itself because the plugin is agnostic to bootstrap.
$(".dropdown-menu li").hover(function (e) {
e.stopPropagation();
});
$(document).click(function () {
// Simply hide the submenu on any click. Again, this is just a hacked
// together menu/submenu structure to show the use of jQuery-menu-aim.
$(".popover").css("display", "none");
$("a.maintainHover").removeClass("maintainHover");
});

下面是库 jQuery menuAim 和 url 网址示例:https://rawgit.com/kamens/jQuery-menu-aim/master/example/example.html#

/**
* menu-aim is a jQuery plugin for dropdown menus that can differentiate
* between a user trying hover over a dropdown item vs trying to navigate into
* a submenu's contents.
*
* menu-aim assumes that you have are using a menu with submenus that expand
* to the menu's right. It will fire events when the user's mouse enters a new
* dropdown item *and* when that item is being intentionally hovered over.
*
* __________________________
* | Monkeys  >|   Gorilla  |
* | Gorillas >|   Content  |
* | Chimps   >|   Here     |
* |___________|____________|
*
* In the above example, "Gorillas" is selected and its submenu content is
* being shown on the right. Imagine that the user's cursor is hovering over
* "Gorillas." When they move their mouse into the "Gorilla Content" area, they
* may briefly hover over "Chimps." This shouldn't close the "Gorilla Content"
* area.
*
* This problem is normally solved using timeouts and delays. menu-aim tries to
* solve this by detecting the direction of the user's mouse movement. This can
* make for quicker transitions when navigating up and down the menu. The
* experience is hopefully similar to amazon.com/'s "Shop by Department"
* dropdown.
*
* Use like so:
*
*      $("#menu").menuAim({
*          activate: $.noop,  // fired on row activation
*          deactivate: $.noop  // fired on row deactivation
*      });
*
*  ...to receive events when a menu's row has been purposefully (de)activated.
*
* The following options can be passed to menuAim. All functions execute with
* the relevant row's HTML element as the execution context ('this'):
*
*      .menuAim({
*          // Function to call when a row is purposefully activated. Use this
*          // to show a submenu's content for the activated row.
*          activate: function() {},
*
*          // Function to call when a row is deactivated.
*          deactivate: function() {},
*
*          // Function to call when mouse enters a menu row. Entering a row
*          // does not mean the row has been activated, as the user may be
*          // mousing over to a submenu.
*          enter: function() {},
*
*          // Function to call when mouse exits a menu row.
*          exit: function() {},
*
*          // Selector for identifying which elements in the menu are rows
*          // that can trigger the above events. Defaults to "> li".
*          rowSelector: "> li",
*
*          // You may have some menu rows that aren't submenus and therefore
*          // shouldn't ever need to "activate." If so, filter submenu rows w/
*          // this selector. Defaults to "*" (all elements).
*          submenuSelector: "*",
*
*          // Direction the submenu opens relative to the main menu. Can be
*          // left, right, above, or below. Defaults to "right".
*          submenuDirection: "right"
*      });
*
* https://github.com/kamens/jQuery-menu-aim
*/
(function($) {
$.fn.menuAim = function(opts) {
// Initialize menu-aim for all elements in jQuery collection
this.each(function() {
init.call(this, opts);
});
return this;
};
function init(opts) {
var $menu = $(this),
activeRow = null,
mouseLocs = [],
lastDelayLoc = null,
timeoutId = null,
options = $.extend(
{
rowSelector: "> li",
submenuSelector: "*",
submenuDirection: "right",
tolerance: 75, // bigger = more forgivey when entering submenu
enter: $.noop,
exit: $.noop,
activate: $.noop,
deactivate: $.noop,
exitMenu: $.noop
},
opts
);
var MOUSE_LOCS_TRACKED = 3, // number of past mouse locations to track
DELAY = 300; // ms delay when user appears to be entering submenu
/**
* Keep track of the last few locations of the mouse.
*/
var mousemoveDocument = function(e) {
mouseLocs.push({
x: e.pageX,
y: e.pageY
});
if (mouseLocs.length > MOUSE_LOCS_TRACKED) {
mouseLocs.shift();
}
};
/**
* Cancel possible row activations when leaving the menu entirely
*/
var mouseleaveMenu = function() {
if (timeoutId) {
clearTimeout(timeoutId);
}
// If exitMenu is supplied and returns true, deactivate the
// currently active row on menu exit.
if (options.exitMenu(this)) {
if (activeRow) {
options.deactivate(activeRow);
}
activeRow = null;
}
};
/**
* Trigger a possible row activation whenever entering a new row.
*/
var mouseenterRow = function() {
if (timeoutId) {
// Cancel any previous activation delays
clearTimeout(timeoutId);
}
options.enter(this);
possiblyActivate(this);
},
mouseleaveRow = function() {
options.exit(this);
};
/*
* Immediately activate a row if the user clicks on it.
*/
var hoverRow = function() {
activate(this);
};
/**
* Activate a menu row.
*/
var activate = function(row) {
if (row == activeRow) {
return;
}
if (activeRow) {
options.deactivate(activeRow);
}
options.activate(row);
activeRow = row;
};
/**
* Possibly activate a menu row. If mouse movement indicates that we
* shouldn't activate yet because user may be trying to enter
* a submenu's content, then delay and check again later.
*/
var possiblyActivate = function(row) {
var delay = activationDelay();
if (delay) {
timeoutId = setTimeout(function() {
possiblyActivate(row);
}, delay);
} else {
activate(row);
}
};
/**
* Return the amount of time that should be used as a delay before the
* currently hovered row is activated.
*
* Returns 0 if the activation should happen immediately. Otherwise,
* returns the number of milliseconds that should be delayed before
* checking again to see if the row should be activated.
*/
var activationDelay = function() {
if (!activeRow || !$(activeRow).is(options.submenuSelector)) {
// If there is no other submenu row already active, then
// go ahead and activate immediately.
return 0;
}
var offset = $menu.offset(),
upperLeft = {
x: offset.left,
y: offset.top - options.tolerance
},
upperRight = {
x: offset.left + $menu.outerWidth(),
y: upperLeft.y
},
lowerLeft = {
x: offset.left,
y: offset.top + $menu.outerHeight() + options.tolerance
},
lowerRight = {
x: offset.left + $menu.outerWidth(),
y: lowerLeft.y
},
loc = mouseLocs[mouseLocs.length - 1],
prevLoc = mouseLocs[0];
if (!loc) {
return 0;
}
if (!prevLoc) {
prevLoc = loc;
}
if (
prevLoc.x < offset.left ||
prevLoc.x > lowerRight.x ||
prevLoc.y < offset.top ||
prevLoc.y > lowerRight.y
) {
// If the previous mouse location was outside of the entire
// menu's bounds, immediately activate.
return 0;
}
if (lastDelayLoc && loc.x == lastDelayLoc.x && loc.y == lastDelayLoc.y) {
// If the mouse hasn't moved since the last time we checked
// for activation status, immediately activate.
return 0;
}
// Detect if the user is moving towards the currently activated
// submenu.
//
// If the mouse is heading relatively clearly towards
// the submenu's content, we should wait and give the user more
// time before activating a new row. If the mouse is heading
// elsewhere, we can immediately activate a new row.
//
// We detect this by calculating the slope formed between the
// current mouse location and the upper/lower right points of
// the menu. We do the same for the previous mouse location.
// If the current mouse location's slopes are
// increasing/decreasing appropriately compared to the
// previous's, we know the user is moving toward the submenu.
//
// Note that since the y-axis increases as the cursor moves
// down the screen, we are looking for the slope between the
// cursor and the upper right corner to decrease over time, not
// increase (somewhat counterintuitively).
function slope(a, b) {
return (b.y - a.y) / (b.x - a.x);
}
var decreasingCorner = upperRight,
increasingCorner = lowerRight;
// Our expectations for decreasing or increasing slope values
// depends on which direction the submenu opens relative to the
// main menu. By default, if the menu opens on the right, we
// expect the slope between the cursor and the upper right
// corner to decrease over time, as explained above. If the
// submenu opens in a different direction, we change our slope
// expectations.
if (options.submenuDirection == "left") {
decreasingCorner = lowerLeft;
increasingCorner = upperLeft;
} else if (options.submenuDirection == "below") {
decreasingCorner = lowerRight;
increasingCorner = lowerLeft;
} else if (options.submenuDirection == "above") {
decreasingCorner = upperLeft;
increasingCorner = upperRight;
}
var decreasingSlope = slope(loc, decreasingCorner),
increasingSlope = slope(loc, increasingCorner),
prevDecreasingSlope = slope(prevLoc, decreasingCorner),
prevIncreasingSlope = slope(prevLoc, increasingCorner);
if (
decreasingSlope < prevDecreasingSlope &&
increasingSlope > prevIncreasingSlope
) {
// Mouse is moving from previous location towards the
// currently activated submenu. Delay before activating a
// new menu row, because user may be moving into submenu.
lastDelayLoc = loc;
return DELAY;
}
lastDelayLoc = null;
return 0;
};
/**
* Hook up initial menu events
*/
$menu
.mouseleave(mouseleaveMenu)
.find(options.rowSelector)
.mouseenter(mouseenterRow)
.mouseleave(mouseleaveRow)
.hover(hoverRow);
$(document).mousemove(mousemoveDocument);
}
})(jQuery);

引导菜单项的默认悬停背景是#f8f9fa
因此,只需将其保存到变量中以供以后使用

要在将鼠标悬停在其上时保持悬停颜色,请使用

$('.dropdown-item').mouseover(function(){
$('.dropdown-item').css("background", defaultColor); // reset previously hovered item
$(this).css("background", "#f8f9fa");
});

演示:

$(document).ready(function(){
var defaultColor = $('.dropdown-item').css("background");
$('.dropdown-item').mouseover(function(){
$('.dropdown-item').css("background", defaultColor);
$(this).css("background", "#f8f9fa");
});
$(document).click(function(e){
$('.dropdown-item').css("background", defaultColor); // reset background
});
});
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown button
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>

最新更新