Today is to introduce you to a right-click menu on the web page, the original author of the web site is: http://51jsr.javaeye.com/blog/305517
This right-click menu is already excellent. It is IE Only, and in the DTD Mode
<! DOCTYPE html PUBLIC "-// W3C // dtd xhtml 1.0 Transitional // EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd%22>
Even IE display is problematic, so I only need to do it myself. In addition, I will transform it into a jQuery control and analyze the code by the way.
Let's take a look at the effect.
Controls:
Optional Windows Se7en system email menu
In fact, my final goal is to provide an ASP. net mvc Framework front-end UI Controls solution, because the following Controls will use this right-click menu, so let's talk about it.
First, analyze HTML.
1: A level-1 menu (each set of menus) is an independent div container.
2: each item is a div, nested with a nobr (instead of a div, but an additional class) label, which contains the position content of the icon and span package.
Menu item/menu group split line
The note here is that the multi-level menu is actually separated in the HTMl structure, but is visually serialized by the displayed position (the arrow icon is also used)
The second step is CSS (modified)
CSS is very simple, because the HTML structure is not complex.
.b-m-mpanel { background: #F0F0F0 url(images/contextmenu/menu_bg.gif) left repeat-y; border: 1px solid #718BB7; padding: 2px 0; position: absolute; z-index: 99997;}.b-m-split { height: 6px; background: url(images/contextmenu/m_splitLine.gif) center repeat-x; font-size: 0px; margin: 0 2px;}.b-m-item, .b-m-idisable{ padding: 4px 2px; margin: 0 2px 0 3px; cursor: normal; line-height:100%;}.b-m-idisable{ color:#808080;}.b-m-ibody, .b-m-arrow { overflow: hidden; text-overflow: ellipsis; }.b-m-arrow { background: url(images/contextmenu/m_arrow.gif) right no-repeat; }.b-m-idisable .b-m-arrow{ background:none;}.b-m-item img, .b-m-ifocus img, .b-m-idisable img { margin-right: 8px;}.b-m-ifocus { background: url(images/contextmenu/m_item.gif) repeat-x bottom; border: 1px solid #AACCF6; padding: 3px 1px ; margin: 0 2px 0 3px; cursor: normal; line-height:100%;}.b-m-idisable img { visibility:hidden;}
Pay attention to the four images used in CSS ..
Third, javascript.
Let's take a look at the complete one.
; (Function ($) {function returnfalse () {return false ;}; $. fn. contextmenu = function (option) {option = $. extend ({alias: "cmroot", width: 150}, option); var ruleName = null, target = null, groups = {}, mitems = {}, actions = {}, showGroups = [], itemTpl = "<div class = 'B-m-$ [type] 'unselectable = on> <nobr unselectable = on> <span unselectable = on> $ [text] </span> </no Br> </div> "; var gTemplet = $ (" <div/> "). addClass ("B-m-mpanel "). attr ("unselectable", "on" detail .css ("display", "none"); var iTemplet = $ ("<div/> "). addClass ("B-m-item "). attr ("unselectable", "on"); var sTemplet =$ ("<div/> "). addClass ("B-m-split"); // create a menu group var buildGroup = function (obj) {groups [obj. alias] = this; this. gidx = obj. alias; this. id = obj. alias; if (obj. disable) {this. disable = obj. disable; thi S. className = "B-m-idisable";} $ (this ). width (obj. width ). click (returnfalse ). mousedown (returnfalse ). appendTo ($ ("body"); obj = null; return this ;}; var buildItem = function (obj) {var T = this; T. title = obj. text; T. idx = obj. alias; T. gidx = obj. gidx; T. data = obj; T. innerHTML = itemTpl. replace (/\ $ \ [([^ \] +) \]/g, function () {return obj [arguments [1];}); if (obj. disable) {T. disable = obj. disable; T. className = "B-m-idisable";} obj. items & (T. group = true); obj. action & (actions [obj. alias] = obj. action); mitems [obj. alias] = T; T = obj = null; return this ;}; // Add the menu item var addItems = function (gidx, items) {var tmp = null; for (var I = 0; I <items. length; I ++) {if (items [I]. type = "splitLine") {// menu separator tmp = sTemplet. clone () [0];} else {items [I]. gidx = gidx; if (items [I]. type = "gro Up ") {// menu group buildGroup. apply (gTemplet. clone () [0], [items [I]); arguments. callee (items [I]. alias, items [I]. items); items [I]. type = "arrow"; tmp = buildItem. apply (iTemplet. clone () [0], [items [I]);} else {// menu item items [I]. type = "ibody"; tmp = buildItem. apply (iTemplet. clone () [0], [items [I]); $ (tmp ). click (function (e) {if (! This. disable) {if ($. isFunction (actions [this. idx]) {actions [this. idx]. call (this, target) ;}hidemenupane () ;}return false ;}) ;}// Endif $ (tmp ). bind ("contextmenu", returnfalse ). hover (overItem, outItem);} // Endif groups [gidx]. appendChild (tmp); tmp = items [I] = items [I]. items = null;} // Endfor gidx = items = null;}; var overItem = function (e) {// if the menu item is unavailable if (this. disable) return false; hideMe NuPane. call (groups [this. gidx]); // if it is a menu group if (this. group) {var pos = $ (this ). offset (); var width = $ (this ). outerWidth (); showMenuGroup. apply (groups [this. idx], [pos, width]);} this. className = "B-m-ifocus"; return false ;}; // The menu item loses focus var outItem = function (e) {// if the menu item is unavailable if (this. disable) return false; if (! This. group) {// menu item this. className = "B-m-item" ;}// Endif return false ;}; // display the specified menu group var showMenuGroup = function (pos, width) at the specified position) {var bwidth = $ ("body "). width (); var bheight = document.doc umentElement. clientHeight; var mwidth = $ (this ). outerWidth (); var mheight = $ (this ). outerHeight (); pos. left = (pos. left + width + mwidth> bwidth )? (Pos. left-mwidth <0? 0: pos. left-mwidth): pos. left + width; pos. top = (pos. top + mheight> bheight )? (Pos. top-mheight + (width> 0? 25: 0) <0? 0: pos. top-mheight + (width> 0? 25: 0): pos. top; CSS (pos ). show (); showGroups. push (this. gidx) ;}; // hide the menu group var hideMenuPane = function () {var alias = null; for (var I = showGroups. length-1; I> = 0; I --) {if (showGroups [I] = this. gidx) break; alias = showGroups. pop (); groups [alias]. style. display = "none"; mitems [alias] & (mitems [alias]. className = "B-m-item");} // Endfor // CollectGarbage () ;}; function applyRule (ru Le) {if (ruleName & ruleName = rule. name) return false; for (var I in mitems) disable (I ,! Rule. disable); for (var I = 0; I <rule. items. length; I ++) disable (rule. items [I], rule. disable); ruleName = rule. name ;}; function disable (alias, disabled) {var item = mitems [alias]; item. className = (item. disable = item. lastChild. disabled = disabled )? "B-m-idisable": "B-m-item" ;};/** right-click the menu to display */function showMenu (e, menutarget) {target = menutarget; showMenuGroup. call (groups. cmroot, {left: e. pageX, top: e. pageY}, 0); $ (document ). one ('mousedown', hideMenuPane);} var $ root = $ ("#" + option. alias); var root = null; if ($ root. length = 0) {root = buildGroup. apply (gTemplet. clone () [0], [option]); root. applyrule = applyRule; root. showMenu = show Menu; addItems (option. alias, option. items);} else {root = $ root [0];} var me = $ (this ). each (function () {return $ (this ). bind ('textmenu ', function (e) {var bShowContext = (option. onContextMenu & $. isFunction (option. onContextMenu ))? Option. onContextMenu. call (this, e): true; if (bShowContext) {if (option. onShow & $. isFunction (option. onShow) {option. onShow. call (this, root);} root. showMenu (e, this) ;}return false ;}); // set the display Rule if (option. rule) {applyRule (option. rule);} gTemplet = iTemplet = sTemplet = itemTpl = buildGroup = buildItem = null; addItems = overItem = outItem = null; // CollectGarbage (); return me ;}}) (jQuery );
Next, let's analyze it step by step. First, since it is transformed into a jQuery control, it is naturally still an old shelf.
;(function($) { $.fn.contextmenu = function(option) { }})(jQuery);
The default parameter is displayed.
// Alias: "unique identifier" (This identifier is very important. You can generate only one menu for multiple calls), // width menu width option = $. extend ({alias: "cmroot", width: 150}, option );
There are only two default parameters, and the others have no default values.
/* Parameter description option: {width: Number, items: Array, onShow: Function, rule: JSON} member syntax (three forms) -- para. items-> {text: String, icon: String, type: String, alias: String, width: Number, items: Array} -- menu group-> {text: String, icon: string, type: String, alias: String, action: Function} -- menu item-> {type: String} -- split line */
Detailed description:
Items: The content definition of the right-click menu of Array. The element format of the Array is as follows:
{Text: String, icon: String, alias: String, type: "group" | "item" | "splitLine", width: int, items: Array, action: Funtion}
Where:
Text: text description of the String menu item.
Icon: String map: Specifies the srcaddress. If no icon exists, set it to none.gif (available in images/icons/) If itemdoes not ).
Alias: String uniquely identifies a menu item.
Type: "group" | "item" | "splitLine" is a group, item, and split line respectively. If "splitLine" is selected, no other settings are required.
Width: int, which is valid only when type = "group". Set the width of the new group container.
Items: An Array sub-element can be infinitely layered.
Action: Function is used when a menu item is clicked.
Alias: Unique Identifier of String (optional parameter). It can be omitted when there is only one right-click menu on the page.
Width: (optional) the width of the right-click menu root. Default Value: 150px.
OnContextMenu: Function (optional) the Function that is called in advance when the right-click menu is triggered. The return parameter is Boolean to indicate whether to display the menu.
OnShow: Function (optional parameter) triggered when the menu is displayed. Generally, rules are applied to this Function.
Rule: Json (optional parameter) default rule, which is set to disabled by default, format: {name: String, disable: Boolean, items: Array}
Name: String rule name disable: Specifies whether to disable or enable the items rule. Array indicates the set of items alias that need to apply the rule.
It's a bit complicated. If you still don't understand it, see the example.
Define a bunch of temporary variables and four temporary template Variables
Var ruleName = null, target = null, groups = {}, mitems = {}, actions = {}, showGroups = [], // define internal temporary variables. Analyze the template of a menu item, container and item, split line template itemTpl = "<div class = 'B-m-$ [type] 'unselectable = on> <nobr unselectable = on> <span unselectable = on> $ [text] </span> </nobr> </div> "; var gTemplet = $ ("<div/> "). addClass ("B-m-mpanel "). attr ("unselectable", "on" detail .css ("display", "none"); var iTemplet = $ ("<div/> "). addClass ("B-m-item "). attr ("unselectable", "on"); var sTemplet =$ ("<div/> "). addClass ("B-m-split ");
Next, let's skip some function definitions and look at the HTML part.
// Obtain the menu and var $ root =$ ("#" + option. alias); var root = null; if ($ root. length = 0) {// if the top menu does not exist, create a top menu. root = buildGroup. apply (gTemplet. clone () [0], [option]); root. applyrule = applyRule; // register a method to the dom root. showMenu = showMenu; // addItems (option. alias, option. items); // Add menu item} else {root = $ root [0]; // otherwise this is used}
This code is very mysterious. It seems that nothing has been done. In fact, you only need to look at the buildGroup method and addItems to know what you have done.
Var buildGroup = function (obj) {// create a menu container groups [obj. alias] = this; // The menu item is registered to the Temporary Variable this. gidx = obj. alias; this. id = obj. alias; if (obj. disable) {// if it is disabled this. disable = obj. disable; this. className = "B-m-idisable";} // set the menu width, set the event blocking event to bubble, and add it to the body $ (this ). width (obj. width ). click (returnfalse ). mousedown (returnfalse ). appendTo ($ ("body"); obj = null; return this; // return menu itself };
With the container, you can add menu items to it. I added a detailed comment in the Code, which should be easy to understand.
// Add the menu item var addItems = function (gidx, items) {var tmp = null; for (var I = 0; I <items. length; I ++) {if (items [I]. type = "splitLine") {// if it is a split line // The Menu separator line tmp = sTemplet. clone () [0];} else {items [I]. gidx = gidx; // assign the group ID to if (items [I] on the item. type = "group") {// menu group buildGroup. apply (gTemplet. clone () [0], [items [I]); // each menu group is an independent div, so the top-level method of the production group is called arguments. callee (items [I]. alias, items [I]. item S); // recursively generate menu item items [I]. type = "arrow"; // if it is a group, the arrow tmp = buildItem is generated. apply (iTemplet. clone () [0], [items [I]); // generate the html} else {// menu item items [I]. type = "ibody"; tmp = buildItem. apply (iTemplet. clone () [0], [items [I]); // generate the html $ (tmp) of the menu item ). click (function (e) {// register the click event if (! This. disable) {if ($. isFunction (actions [this. idx]) {actions [this. idx]. call (this, target) ;}hidemenupane () ;}return false ;}) ;}// Endif // right-click the menu item and block the event, register hover results at the same time $ (tmp ). bind ("contextmenu", returnfalse ). hover (overItem, outItem);} // Endif groups [gidx]. appendChild (tmp); // Add the menu item to the group. tmp = items [I] = items [I]. items = null;} // Endfor gidx = items = null ;};
The builditem method is relatively simple and will not be described in detail. Let's continue to look at the main process.
Var me = $ (this ). each (function () {// Add a right-click event to the element. return $ (this ). bind ('textmenu ', function (e) {// If (option. if onContextMenu exists, call it and determine whether the returned value shows the menu. You can disable the menu var bShowContext = (option. onContextMenu & $. isFunction (option. onContextMenu ))? Option. onContextMenu. call (this, e): true; if (bShowContext) {// triggers the onShow event. You can modify the rule to disable some menu items. if (option. onShow & $. isFunction (option. onShow) {option. onShow. call (this, root);} root. showMenu (e, this); // call the display menu} // block the bubble return false;}); // set the display rule for the first execution, you can also dynamically set rule if (option. rule) {applyRule (option. rule );}
Basically, it's okay. The other several methods are relatively simple, and the highlights are edge processing. The corresponding description logic in the preceding datepicker is almost not described, let's take a look at the demo. For package download, you can save the demo webpage as a complete one.
Http://jscs.cloudapp.net/ControlsSample/CM
Your support is the motivation for my continued writing.
Welcome to reprint, but please keep the original link: http://www.cnblogs.com/xuanye/archive/2009/10/29/1592585.html