惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
小众软件
小众软件
GbyAI
GbyAI
B
Blog RSS Feed
月光博客
月光博客
A
About on SuperTechFans
Microsoft Security Blog
Microsoft Security Blog
Blog — PlanetScale
Blog — PlanetScale
U
Unit 42
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Vercel News
Vercel News
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
博客园_首页
G
Google Developers Blog

博客园 - Xt Idt

ASP.NET MVC 4 RC的JS/CSS打包压缩功能 自定义WCF的配置文件 C#综合揭秘——分部类和分部方法 结合领域驱动设计的SOA分布式软件架构 SOA面向服务架构——SOA的概念 使用WCF实现SOA面向服务编程—— 架构设计 选择HttpHandler还是HttpModule? MVP解读 揭秘Amazon反应速度超快的下拉菜单 SQL注入攻防入门详解 Visual Studio 2010 如何改用 Beyond Compare 作为 TFS 的比较工具 jquery post get 跨域 提交数据 使用HttpContext的User属性来实现用户验证-.NET教程 在Web Service中使用Windows验证的方式 对于表列数据类型选择的一点思考 (转发)有关T-SQL的10个好习惯 jQuery.extend 函数详解 跟我一起学写jQuery插件(附完整实例及下载) 分析URL Routing和URL Rewriting两者之间的不同
jQuery-menu-aim.js
Xt Idt · 2013-03-08 · via 博客园 - Xt Idt

/**

* 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: "*"

*      });

*

* https://github.com/kamens/jQuery-menu-aim

*/

(function($) {

    

$.fn.menuAim = function(opts) {

                

tolerance: 75,  // bigger = more forgivey when entering submenu

        

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) {

         * Cancel possible row activations when leaving the menu entirely

         */

        

var mouseleaveMenu = function() {

         * Trigger a possible row activation whenever entering a new row.

         */

        

var mouseenterRow = function() {

                    

// Cancel any previous activation delays

            

mouseleaveRow = function() {

         * Activate a menu row.

         */

        

var activate = function(row) {

                    

options.deactivate(activeRow);

         * 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();

                    

timeoutId = setTimeout(function() {

         * 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.

                

var offset = $menu.offset(),

                        

x: offset.left + $menu.outerWidth(),

                        

y: offset.top - options.tolerance

                        

x: offset.left + $menu.outerWidth(),

                        

y: offset.top + $menu.outerHeight() + options.tolerance

                    

loc = mouseLocs[mouseLocs.length - 1],

                

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.

                        

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.

                

// Detect if the user is moving towards the currently activated

                

// 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 left corner to decrease over time, not

                

// increase (somewhat counterintuitively).

                    

return (b.y - a.y) / (b.x - a.x);

                

var upperSlope = slope(loc, upperRight),

                    

lowerSlope = slope(loc, lowerRight),

                    

prevUpperSlope = slope(prevLoc, upperRight),

                    

prevLowerSlope = slope(prevLoc, lowerRight);

                

if (upperSlope < prevUpperSlope &&

                        

lowerSlope > prevLowerSlope) {

                    

// 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.

         * Hook up initial menu events

         */

                

.mouseleave(mouseleaveMenu)

                

.find(options.rowSelector)

                    

.mouseenter(mouseenterRow)

                    

.mouseleave(mouseleaveRow);

            

$(document).mousemove(mousemoveDocument);

})(jQuery);