您的位置:

首页 >

网络编程 >

最佳6款用于移动网站开发的jQuery 图片滑块插件小结 >

最佳6款用于移动网站开发的jQuery 图片滑块插件小结

2016-03-07 11:38:01

分类:网络编程

随着智能手机的普及,越来越多的用户喜欢通过手机中浏览网页。今天这篇文章为大家推荐最佳6款用于移动应用的 jQuery 图片滑块插件,这些插件很好的处理了触屏事件,效果平滑,帮助你构建用户体验良好的移动网站。PhotoSwipe PhotoSwipe 是一款免费的 jQuery 图片库插件,支持 iPhone, iPad, Android, Blackberry 等各种移动设备。Mobile Photo Album Mobile Photo Album 是一款非常易用的相册插件,帮助你在移动网站中构建优秀的相册功能。Unoslider 特别推荐 unoslider 这款幻灯片插件,基于响应式设计,拥有众多切换效果,支持触屏。Touch Gallery Touch Gallery 帮助你在移动浏览器中实现类似原生的照片浏览应用的效果。swipejs Swipe 是一款轻量的,用于移动网站开发的 jQuery 图片滑块插件,简单易用。TN3 Gallery 压轴的这款 jQuery 相册插件是这里面功能最丰富的,支持幻灯片展示、不同的布局方式以及多样的切换效果。

如果某个一级评分项包含评分子项,则点击该评分项时,再弹出一个新窗口,新窗体中列出了当前评分项的所有评分子项列表,供用户进行操作。用户操作完成后,点击“确定”按钮,则返回到父窗体,在子窗体中所有的操作结果,同时要带到父窗体中。同时,如果用户再次点击该评分项,则在弹出子窗体的同时,要将上次操作的结果绑定到对应的操作项上。   上面描述的例子,就涉及到了一个父子窗体间的数据传递。如何实现这一数据传递,当然有很多方法。这里只是记录一下在这个例子中我使用的方法。我的方法是在子窗体点击“确定”按钮时,将操作结果构造成json格式的字符串,通过调用父窗体上的方法:opener.方法(),将json格式数据传递到父窗体上。   此例中构造的json数据类似如下格式:   {"MyData":[     {"bh":"111","lx":"1","df":"10","bz":"aaa"},     {"bh":"112","lx":"2","df":"20","bz":"bbb"},     {"bh":"113","lx":"2","df":"30","bz":"ccc"}   ]}   此处子项打分需要保持的分别是bh:编号;lx:类型;df:得分;bz:备注。   按照自己的需要,可以再自己增加需要保持的项。构造此json数据可以放在前台,也可以放在后台。   在此例中,我是放置后台的。代码如下: 复制代码 代码如下: StringBuilder jsonBuilder = new StringBuilder(); jsonBuilder.Append("@{\""); jsonBuilder.Append("MyData"); jsonBuilder.Append("\":["); int k = bh.Split(',').Length + 1; for (int i = 0; i < bh.Split(',').Length; i++) { tem += "update KH_PFX set DF = '"+EncriptLib.EncriptLib.EncodeCode(Convert.ToDouble(df.Split(',')[i].ToString().Trim()))+"',"; tem += "BZ = '"+bz.Split(',')[i].ToString().Trim()+"',PFRXM = '"+Session["XM"].ToString()+"',"; tem += "PFRBH = '"+Session["YHBH"].ToString()+"',PFRQ = to_date('"+DateTime.Now.ToShortDateString()+"','yyyy-MM-dd')"; tem += " where BH = '"+bh.Split(',')[i].ToString().Trim()+"'"; tem += "卐"; //此处用此特殊的符号来分隔sql语句 jsonBuilder.Append("{\"bh\":" + "\"" + bh.Split(',')[i].ToString().Trim() + "\"" + ","); jsonBuilder.Append("\"lx\":" + "\"" + lx.Split(',')[i].ToString().Trim() + "\"" + ","); jsonBuilder.Append("\"df\":" + "\"" + df.Split(',')[i].ToString().Trim() + "\"" + ","); jsonBuilder.Append("\"bz\":" + "\"" + bz.Split(',')[i].ToString().Trim() + "\"" + "},"); } if(tem != "") { jsonBuilder.Remove(jsonBuilder.Length - 1, 1); jsonBuilder.Append("]"); jsonBuilder.Append("}"); Page.ClientScript.RegisterClientScriptBlock(GetType(), "cg", "<Script>window.close();opener.GetZXDF('zxdf" + Request.QueryString["bh"].ToString() + "','" + parent_df.Text.Trim() + "','" + jsonBuilder.ToString() + "',\"" + tem + "\");</Script>"); } "@"符号可以防止在jsonBuilder.ToString()后,转义字符“\”的消失。   调用父窗体的GetZXDF()方法,将json数据传递给父窗体。   下面给出子窗体加载时,绑定json数据的代码 复制代码 代码如下: $(function() { //加载时获取json,然后绑定打分结果 var obj = opener.GetJson($("#txt_YCBH").val()); if($.trim(obj) != ""){ obj = "(" + obj + ")"; obj = eval(obj); var data = obj.MyData; $.each(data, function(i, n) { if(n.lx == "1"){ //直接打分类的绑定 $("#lx" + n.bh).siblings("input").eq(0).val(n.df); $("#lx" + n.bh).siblings("input").eq(1).val(n.df); $("#lx" + n.bh).parent().parent().next().children().children("textarea").val(n.bz); } if(n.lx == "2"){ //选项打分类的绑定 $("#lx" + n.bh).siblings("input:text").eq(1).val(n.df); $("#lx" + n.bh).siblings("input:checkbox").each(function(){ if($.trim($(this).val()) == $.trim(n.df)){ $(this).attr("checked",true); } }); $("#lx" + n.bh).parent().parent().parent().next().children().children("textarea").val(n.bz); } }); opener.GetJson()方法是父窗体上用来向子窗体传递json数据的方法,代码如下: 复制代码 代码如下:

1.解决了有些select 美化代码,无法触发原有select 控件的onchange 事件问题。 2.允许多次调用 $("...").selectCss(),以解决Select的options更新后无法同步的问题。 使用方法如下: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <link href="selectCss.css" rel="stylesheet" type="text/css" /> <script src="jquery-1.3.2.min.js" type="text/javascript"></script> <script src="selectCss.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function(){ $("select").selectCss(); }); </script> </head> <body> <select name="" onchange="alert(this.value)" id="select1"> <option value="1" title="选项选项选项选项" >选项1</option> <option value="2">选项2</option> <option value="3">选项3</option> </select> <select name="" id="select2"> <option value="1">选项31</option> <option value="2">选项32</option> <option value="3">选33</option> </select> </body> </html> 主要文件包括 selectCss.css 和 selectCss.js selectCss.js 文件代码: 复制代码 代码如下: (function($){ function hideOptions(speed){ if(speed.data){speed=speed.data} if($(document).data("nowselectoptions")) { $($(document).data("nowselectoptions")).slideUp(speed); $($(document).data("nowselectoptions")).prev("div").removeClass("tag_select_open"); $(document).data("nowselectoptions",null); $(document).unbind("click",hideOptions); $(document).unbind("keyup",hideOptionsOnEscKey); } } function hideOptionsOnEscKey(e){ var myEvent = e || window.event; var keyCode = myEvent.keyCode; if(keyCode==27)hideOptions(e.data); } function showOptions(speed){ $(document).bind("click",speed,hideOptions); $(document).bind("keyup",speed,hideOptionsOnEscKey); $($(document).data("nowselectoptions")).slideDown(speed); $($(document).data("nowselectoptions")).prev("div").addClass("tag_select_open"); } $.fn.selectCss=function(_speed){ $(this).each(function(){ var speed=_speed||"fast"; if($(this).data("cssobj")){ $($(this).data("cssobj")).remove(); } $(this).hide(); var divselect = $("<div></div>").insertAfter(this).addClass("tag_select"); $(this).data("cssobj",divselect); var divoptions = $("<ul></ul>").insertAfter(divselect).addClass("tag_options").hide(); divselect.click(function(e){ if($($(document).data("nowselectoptions")).get(0) != $(this).next("ul").get(0)){ hideOptions(speed); } if(!$(this).next("ul").is(":visible")) { e.stopPropagation(); $(document).data("nowselectoptions",$(this).next("ul")); showOptions(speed); } }); divselect.hover(function(){ $(this).addClass("tag_select_hover"); } , function(){ $(this).removeClass("tag_select_hover"); }); $(this).change(function(){ $(this).nextAll("ul").children("li:eq("+ $(this)[0].selectedIndex +")").addClass("open_selected").siblings().removeClass("open_selected"); $(this).next("div").html($(this).children("option:eq("+ $(this)[0].selectedIndex +")").text()); }); $(this).children("option").each(function(i){ var lioption= $("<li></li>").html($(this).text()).attr("title",$(this).attr("title")).appendTo(divoptions); if($(this).attr("selected")){ lioption.addClass("open_selected"); divselect.html($(this).text()); } lioption.data("option",this); lioption.click(function(){ lioption.data("option").selected=true; $(lioption.data("option")).trigger("change",true) }); lioption.hover( function(){$(this).addClass("open_hover");}, function(){ $(this).removeClass("open_hover"); } ); }); }); } })(jQuery); selectCss.Css 文件代码: 复制代码 代码如下: .tag_select{display:block;color:#000;width:179px;height:23px;background:transparent url("images/index_22.jpg") no-repeat 0 0;padding:0 10px;line-height:23px; color:#7D7D7D; font-size:12px; cursor:pointer} .tag_select_hover{ color:#ff0000; background:transparent url("selectbg.jpg") no-repeat 0 0; } .tag_select_open{ color:#0000ff; background:transparent url("selectbg.jpg") no-repeat 0 0;} ul.tag_options{position:absolute;margin:0;list-style:none;background:#fff;padding:0 0 1px;margin:0;width:162px ; height:100px; overflow:hidden; overflow-y:auto; font-size:12px; margin-left:10px; cursor:pointer; z-index:1000 } ul.tag_options li{background:#fff; display:block;width:140px;padding:0 10px;height:20px;text-decoration:none;line-height:20px;color:#000; font-weight:normal; font-size:12px} ul.tag_options li.open_hover{background:#0000ff;color:#000; font-weight:normal; font-size:12px} ul.tag_options li.open_selected{background:#ccc; font-size:12px;font-weight:bold; } selectbg.jpg 图片:

检测浏览器的方式   1、对象特征检测法:判断浏览器能力的通用方法。如果更关注浏览器的能力而不在乎它的实际身份,就可以使用这种检测方法。常见的原生Ajax写法中就用这种方法来创建XMLHttpRequest: 复制代码 代码如下: IXHR: function(){ if(window.ActiveXObject){ XHR=new ActiveXObject('Microsoft.XMLHTTP'); }else if(window.XMLHttpRequest){ XHR=new XMLHttpRequest(); }else{ return null; } } 2、user-agent字符串检测法:通过能浏览器的user-agent字符串进行解析来判断,判断方法在下文的detect.js中 检测平台/操作系统   通过navigator折platform属性和user-agent字符串来判断,判断方法在下文的detect.js中 检测浏览器和操作系统-detect.js 复制代码 代码如下: var sUserAgent = navigator.userAgent; var fAppVersion = parseFloat(navigator.appVersion); function compareVersions(sVersion1, sVersion2) { var aVersion1 = sVersion1.split("."); var aVersion2 = sVersion2.split("."); if (aVersion1.length > aVersion2.length) { for (var i=0; i < aVersion1.length - aVersion2.length; i++) { aVersion2.push("0"); } } else if (aVersion1.length < aVersion2.length) { for (var i=0; i < aVersion2.length - aVersion1.length; i++) { aVersion1.push("0"); } } for (var i=0; i < aVersion1.length; i++) { if (aVersion1[i] < aVersion2[i]) { return -1; } else if (aVersion1[i] > aVersion2[i]) { return 1; } } return 0; } var isOpera = sUserAgent.indexOf("Opera") > -1; var isMinOpera4 = isMinOpera5 = isMinOpera6 = isMinOpera7 = isMinOpera7_5 = false; if (isOpera) { var fOperaVersion; if(navigator.appName == "Opera") { fOperaVersion = fAppVersion; } else { var reOperaVersion = new RegExp("Opera (//d+//.//d+)"); reOperaVersion.test(sUserAgent); fOperaVersion = parseFloat(RegExp["$1"]); } isMinOpera4 = fOperaVersion >= 4; isMinOpera5 = fOperaVersion >= 5; isMinOpera6 = fOperaVersion >= 6; isMinOpera7 = fOperaVersion >= 7; isMinOpera7_5 = fOperaVersion >= 7.5; } var isKHTML = sUserAgent.indexOf("KHTML") > -1 || sUserAgent.indexOf("Konqueror") > -1 || sUserAgent.indexOf("AppleWebKit") > -1; var isMinSafari1 = isMinSafari1_2 = false; var isMinKonq2_2 = isMinKonq3 = isMinKonq3_1 = isMinKonq3_2 = false; if (isKHTML) { isSafari = sUserAgent.indexOf("AppleWebKit") > -1; isKonq = sUserAgent.indexOf("Konqueror") > -1; if (isSafari) { var reAppleWebKit = new RegExp("AppleWebKit///(//d+(?://.//d*)?)"); reAppleWebKit.test(sUserAgent); var fAppleWebKitVersion = parseFloat(RegExp["$1"]); isMinSafari1 = fAppleWebKitVersion >= 85; isMinSafari1_2 = fAppleWebKitVersion >= 124; } else if (isKonq) { var reKonq = new RegExp("Konqueror///(//d+(?://.//d+(?://.//d)?)?)"); reKonq.test(sUserAgent); isMinKonq2_2 = compareVersions(RegExp["$1"], "2.2") >= 0; isMinKonq3 = compareVersions(RegExp["$1"], "3.0") >= 0; isMinKonq3_1 = compareVersions(RegExp["$1"], "3.1") >= 0; isMinKonq3_2 = compareVersions(RegExp["$1"], "3.2") >= 0; } } var isIE = sUserAgent.indexOf("compatible") > -1 && sUserAgent.indexOf("MSIE") > -1 && !isOpera; var isMinIE4 = isMinIE5 = isMinIE5_5 = isMinIE6 = false; if (isIE) { var reIE = new RegExp("MSIE (//d+//.//d+);"); reIE.test(sUserAgent); var fIEVersion = parseFloat(RegExp["$1"]); isMinIE4 = fIEVersion >= 4; isMinIE5 = fIEVersion >= 5; isMinIE5_5 = fIEVersion >= 5.5; isMinIE6 = fIEVersion >= 6.0; } var isMoz = sUserAgent.indexOf("Gecko") > -1 && !isKHTML; var isMinMoz1 = sMinMoz1_4 = isMinMoz1_5 = false; if (isMoz) { var reMoz = new RegExp("rv:(//d+//.//d+(?://.//d+)?)"); reMoz.test(sUserAgent); isMinMoz1 = compareVersions(RegExp["$1"], "1.0") >= 0; isMinMoz1_4 = compareVersions(RegExp["$1"], "1.4") >= 0; isMinMoz1_5 = compareVersions(RegExp["$1"], "1.5") >= 0; } var isNS4 = !isIE && !isOpera && !isMoz && !isKHTML && (sUserAgent.indexOf("Mozilla") == 0) && (navigator.appName == "Netscape") && (fAppVersion >= 4.0 && fAppVersion < 5.0); var isMinNS4 = isMinNS4_5 = isMinNS4_7 = isMinNS4_8 = false; if (isNS4) { isMinNS4 = true; isMinNS4_5 = fAppVersion >= 4.5; isMinNS4_7 = fAppVersion >= 4.7; isMinNS4_8 = fAppVersion >= 4.8; } var isWin = (navigator.platform == "Win32") || (navigator.platform == "Windows"); var isMac = (navigator.platform == "Mac68K") || (navigator.platform == "MacPPC") || (navigator.platform == "Macintosh"); var isUnix = (navigator.platform == "X11") && !isWin && !isMac; var isWin95 = isWin98 = isWinNT4 = isWin2K = isWinME = isWinXP = false; var isMac68K = isMacPPC = false; var isSunOS = isMinSunOS4 = isMinSunOS5 = isMinSunOS5_5 = false; if (isWin) { isWin95 = sUserAgent.indexOf("Win95") > -1 || sUserAgent.indexOf("Windows 95") > -1; isWin98 = sUserAgent.indexOf("Win98") > -1 || sUserAgent.indexOf("Windows 98") > -1; isWinME = sUserAgent.indexOf("Win 9x 4.90") > -1 || sUserAgent.indexOf("Windows ME") > -1; isWin2K = sUserAgent.indexOf("Windows NT 5.0") > -1 || sUserAgent.indexOf("Windows 2000") > -1; isWinXP = sUserAgent.indexOf("Windows NT 5.1") > -1 || sUserAgent.indexOf("Windows XP") > -1; isWinNT4 = sUserAgent.indexOf("WinNT") > -1 || sUserAgent.indexOf("Windows NT") > -1 || sUserAgent.indexOf("WinNT4.0") > -1 || sUserAgent.indexOf("Windows NT 4.0") > -1 && (!isWinME && !isWin2K && !isWinXP); } if (isMac) { isMac68K = sUserAgent.indexOf("Mac_68000") > -1 || sUserAgent.indexOf("68K") > -1; isMacPPC = sUserAgent.indexOf("Mac_PowerPC") > -1 || sUserAgent.indexOf("PPC") > -1; } if (isUnix) { isSunOS = sUserAgent.indexOf("SunOS") > -1; if (isSunOS) { var reSunOS = new RegExp("SunOS (//d+//.//d+(?://.//d+)?)"); reSunOS.test(sUserAgent); isMinSunOS4 = compareVersions(RegExp["$1"], "4.0") >= 0; isMinSunOS5 = compareVersions(RegExp["$1"], "5.0") >= 0; isMinSunOS5_5 = compareVersions(RegExp["$1"], "5.5") >= 0; } } 作者:

当然我们可以研究js库的源码, 也可以自己去发明轮子试试看, 其过程还是挺有趣的...下面我就来实现下页面元素的拖拽功能 现在就开始着手实现, 让我们从最顶层的方法讲起, 它用于初始化一个drag object, 方法的声明如下 function DragObject(cfg) 这里的cfg我们用一个对象来传入, 有点像Extjs里配置属性 复制代码 代码如下: var dragObj = new DragObject({ el: 'exampleB', attachEl: 'exampleBHandle', lowerBound: new Position(0, 0), //position代表一个点,有属性x,y下面会详细讲到 upperBound: new Position(500, 500), startCallback: ..., // 开始拖拽时触发的回调 这里均省略了 moveCallback: ..., // 拖拽过程中触发的回调 endCallback: ..., // 拖拽结束触发的回调 attachLater: ... // 是否立刻启动拖拽事件的监听 }); 配置参数中el可以是具体元素的id, 也可以直接是个dom对象 attachEl就是例子中的handle元素, 通过拖拽它来拖拽元素, lowerBound和upperBound是用于限定拖拽范围的, 都是Position对象, 关于这个对象的封装和作用我们下面会分析到,不急哈: ), 如果没有传入的话, 拖拽的范围就没有限制. startCallback, moveCallback, endCallback都是些回调函数, attachLater为true或者false. 如果不是很明白看了下面的分析, 我想你肯定很快会清楚的.. 下面就来写Position, 代码如下: 复制代码 代码如下: function Position(x, y) { this.X = x; thix.Y = y; } Position.prototype = { constructor: Position, add : function(val) { var newPos = new Position(this.X, this.Y); if (val) { newPos.X += val.X; newPos.Y += val.Y; } return newPos; }, subtract : function(val) { var newPos = new Position(this.X, this.Y); if (val) { newPos.X -= val.X; newPos.Y -= val.Y; } return newPos; }, min : function(val) { var newPos = new Position(this.X, this.Y); if (val) { newPos.X = this.X > val.X ? val.X : this.X; newPos.Y = this.Y > val.Y ? val.Y : this.Y; return newPos; } return newPos; }, max : function(val) { var newPos = new Position(this.X, this.Y); if (val) { newPos.X = this.X < val.X ? val.X : this.X; newPos.Y = this.Y < val.Y ? val.Y : this.Y; return newPos; } return newPos; }, bound : function(lower, upper) { var newPos = this.max(lower); return newPos.min(upper); }, check : function() { var newPos = new Position(this.X, this.Y); if (isNaN(newPos.X)) newPos.X = 0; if (isNaN(newPos.Y)) newPos.Y = 0; return newPos; }, apply : function(el) { if(typeof el == 'string') el = document.getElementById(el); if(!el) return; el.style.left = this.X + 'px'; el.style.top = this.Y + 'px'; } }; 一个坐标点的简单封装, 它保存两个值: x, y坐标. 我们能够通过add和substract方法跟别的坐标点进行+运算和-运算, 返回一个计算过的新坐标点. min和max函数顾名思义用于跟其他坐标点进行比较,并返回其中较小和教大的值.bound方法返回一个在限定范围内的坐标点. check方法用于确保属性x, y的值是数字类型的, 否则会置0. 最后apply方法就是把属性x,y作用于元素style.left和top上. 接着我把剩下的大部分代码拿出来, 再一点一点看: 复制代码 代码如下: function DragObject(cfg) { var el = cfg.el, attachEl = cfg.attachEl, lowerBound = cfg.lowerBound, upperBound = cfg.upperBound, startCallback = cfg.startCallback, moveCallback = cfg.moveCallback, endCallback = cfg.endCallback, attachLater = cfg.attachLater; if(typeof el == 'string') el = document.getElementById(el); if(!el) return; if(lowerBound != undefined && upperBound != undefined) { var tempPos = lowerBound.min(upperBound); upperBound = lowerBound.max(upperBound); lowerBound = tempPos; } var cursorStartPos, elementStartPos, dragging = false, listening = false, disposed = false; function dragStart(eventObj) { if(dragging || !listening || disposed) return; dragging = true; if(startCallback) startCallback(eventObj, el); cursorStartPos = absoluteCursorPosition(eventObj); elementStartPos = new Position(parseInt(getStyle(el, 'left')), parseInt(getStyle(el, 'top'))); elementStartPos = elementStartPos.check(); hookEvent(document, 'mousemove', dragGo); hookEvent(document, 'mouseup', dragStopHook); return cancelEvent(eventObj); } function dragGo(e) { if(!dragging || disposed) return; var newPos = absoluteCursorPosition(e); newPos = newPos.add(elementStartPos) .subtract(cursorStartPos) .bound(lowerBound, upperBound); newPos.apply(el); if(moveCallback) moveCallback(newPos, el); return cancelEvent(e); } function dragStopHook(e) { dragStop(); return cancelEvent(e); } function dragStop() { if(!dragging || disposed) return; unhookEvent(document, 'mousemove', dragGo); unhookEvent(document, 'mouseup', dragStopHook); cursorStartPos = null; elementStartPos = null; if(endCallback) endCallback(el); dragging = false; } this.startListening = function() { if(listening || disposed) return; listening = true; hookEvent(attachEl, 'mousedown', dragStart); }; this.stopListening = function(stopCurrentDragging) { if(!listening || disposed) return; unhookEvent(attachEl, 'mousedown', dragStart); listening = false; if(stopCurrentDragging && dragging) dragStop(); }; this.dispose = function() { if(disposed) return; this.stopListening(true); el = null; attachEl = null; lowerBound = null; upperBound = null; startCallback = null; moveCallback = null; endCallback = null; disposed = true; }; this.isDragging = function() { return dragging; }; this.isListening = function() { return listening; }; this.isDisposed = function() { return disposed; }; if(typeof attachEl == 'string') attachEl = document.getElementById(attachEl); // 如果没有配置, 或者没找到该Dom对象, 则用el if(!attachEl) attachEl = el; if(!attachLater) this.startListening(); } 其中一些未给出方法, 在往下分析的过程中, 会一一给出.... 我们先通过cfg来使el和attachEl指向实际的Dom对象, 如果attachEl没配置或者没找到对应元素则用el替代. 我们同时设置了一些在拖拽中要用到的变量. cursorStartPos用于保存鼠标按下开始拖拽时鼠标的坐标点. elementStartPos用于保存元素开始拖拽时的起始点. dragging, listening, disposed是一些状态变量. listening: 指drag object是否正在监听拖拽开始事件. dragging: 元素是否正在被拖拽. disposed: drag object被清理, 不能再被拖拽了. 在代码的最后, 我们看到如果attachLater不为true, 那么就调用startListening, 这是一个 public方法定义在drag object中, 让我们看下它的实现 复制代码 代码如下: this.startListening = function() { if(listening || disposed) return; listening = true; hookEvent(attachEl, 'mousedown', dragStart); }; 前两行就是做个判断, 如果已经开始对拖拽事件进行监听或者清理过了, 就什么都不做直接return. 否则把listening状态设为true, 表示我们开始监听啦, 把dragStart函数关联到attachEl的mousedown事件上. 这里碰到个hookEvent函数, 我们来看看它的样子: 复制代码 代码如下: function hookEvent(el, eventName, callback) { if(typeof el == 'string') el = document.getElementById(el); if(!el) return; if(el.addEventListener) el.addEventListener(eventName, callback, false); else if (el.attachEvent) el.attachEvent('on' + eventName, callback); } 其实也没什么, 就是对元素事件的监听做了个跨浏览器的封装, 同样的unhookEvent方法如下 复制代码 代码如下: function unhookEvent(el, eventName, callback) { if(typeof el == 'string') el = document.getElementById(el); if(!el) return; if(el.removeEventListener) el.removeEventListener(eventName, callback, false); else if(el.detachEvent) el.detachEvent('on' + eventName, callback); } 接着我们来看看dragStart函数的实现, 它是drag object的一个私有函数 复制代码 代码如下: function dragStart(eventObj) { if(dragging || !listening || disposed) return; dragging = true; if(startCallback) startCallback(eventObj, el); cursorStartPos = absoluteCursorPosition(eventObj); elementStartPos = new Position(parseInt(getStyle(el, 'left')), parseInt(getStyle(el, 'top'))); elementStartPos = elementStartPos.check(); hookEvent(document, 'mousemove', dragGo); hookEvent(document, 'mouseup', dragStopHook); return cancelEvent(eventObj); } attachEl所指的dom对象捕获到mousedown事件后调用此函数. 首先我们先确定drag object在一个适合拖拽的状态, 如果拖拽正在进行, 或者没有在监听拖拽事件, 再或者已经处理完"后事"了, 那就什么都不做. 如果一切ok, 我们把 dragging状态设为true, 然后"开工了", 如果startCallback定义了, 那我们就调用下它, 以mousedown event和el为参数. 接着我们定位鼠标的绝对位置, 保存到cursorStartPos中. 然后拿到拖拽元素当前的top, left,封装成Position对象保存到elementStartPos中. 保险起见我们检查下elementStartPos中属性是否合法. 再看两个hookEvent的调用, 一个是mousemove事件, 表示正在dragging,调用dragGo函数. 一个是mouseup事件, 代表拖拽的结束, 调用dragStopHook函数.可能你会问,为什么事件绑定在document上, 而不是要拖拽的元素上,比如我们这里的el或者attachEl.因为考虑到直接将事件绑定到元素上,可能由于浏览器的一些延时会影响效果,所以直接把事件绑定到document上. 如果实在不是很理解, 或许影响也不大: P.... 看最后一句话中的cancelEvent(eventObj) 复制代码 代码如下: function cancelEvent(e) { e = e ? e : window.event; if(e.stopPropagation) e.stopPropagation(); if(e.preventDefault) e.preventDefault(); e.cancelBubble = true; e.returnValue = false; return false; } 用于停止冒泡, 阻止默认事件, 可以理解为安全考虑....在dragStart中有些方法需要介绍下,先来 看看absoluteCursorPosition, 再看下getStyle 复制代码 代码如下: function absoluteCursorPosition(e) { e = e ? e : window.event; var x = e.clientX + (document.documentElement || document.body).scrollLeft; var y = e.clientY + (document.documentElement || document.body).scrollTop; return new Position(x, y); } 此方法就只是用于获得鼠标在浏览器中的绝对位置, 把滚动条考虑进去就行了 复制代码 代码如下: function getStyle(el, property) { if(typeof el == 'string') el = document.getElementById(el); if(!el || !property) return; var value = el.style[property]; if(!value) { if(document.defaultView && document.defaultView.getComputedStyle) { var css = document.defaultView.getComputedStyle(el, null); value = css ? css.getPropertyValue(property) : null; } else if (el.currentStyle) { value = el.currentStyle[property]; } } return value == 'auto' ? '' : value; } getStyle方法用于获取元素的css属性值, 这样不管你样式是写成内联形式还是定义在css中, 我们都能拿到正确的值, 当然我们这里只要获取元素的top, left属性即可..下面真正处理拖拽工作的方法dragGo 复制代码 代码如下: function dragGo(e) { if(!dragging || disposed) return; var newPos = absoluteCursorPosition(e); newPos = newPos.add(elementStartPos) .subtract(cursorStartPos) .bound(lowerBound, upperBound); newPos.apply(el); if(moveCallback) moveCallback(newPos, el); return cancelEvent(e); } 这个方法并不复杂, 像其他的方法一样, 我们先查看下状态如何, 如果没有在拖拽中或者已经清理了, 那么什么都不做. 如果一切顺利, 我们利用鼠标当前位置, 元素初始位置, 鼠标初始位置, 和限定范围(如果配置upperBound, lowerBound的话)来计算出一个结果点, 通过apply方法我们把计算的坐标赋给元素style.top和style.left, 让拖拽元素确定其位置. 如果配置了moveCallback, 那么就调用下, 最后来个cancelEvent...这里的新坐标运算,类似于jquery的操作, 因为Position对象的每个方法都返回了一个Position对像...dragStart里还有个方法dragStopHook 复制代码 代码如下: function dragStopHook(e) { dragStop(); return cancelEvent(e); } function dragStop() { if(!dragging || disposed) return; unhookEvent(document, 'mousemove', dragGo); unhookEvent(document, 'mouseup', dragStopHook); cursorStartPos = null; elementStartPos = null; if(endCallback) endCallback(el); dragging = false; } 关键看下dragStop方法, 同样先判断下状态, 一切ok的话, 我们移除事件的绑定mousemove和mouseup, 并把 cursorStartPos和elementStartPos的值释放掉, 一次拖拽结束啦..如果配置了endCallback那就调用下, 最后把dragging状态设置为false......最后给出会用到的public方法 复制代码 代码如下: this.stopListening = function(stopCurrentDragging) { if(!listening || disposed) return; unhookEvent(attachEl, 'mousedown', dragStart); listening = false; if(stopCurrentDragging && dragging) dragStop(); }; this.dispose = function() { if(disposed) return; this.stopListening(true); el = null; attachEl = null; lowerBound = null; upperBound = null; startCallback = null; moveCallback = null; endCallback = null; disposed = true; }; this.isDragging = function() { return dragging; }; this.isListening = function() { return listening; }; this.isDisposed = function() { return disposed; }; stopListening移除监听拖拽的mousedown事件, 把监听状态listening设置为false, 这里有个参数stopCurrentDragging见名知意. dispose方法用于些处理工作, 如果你不想让drag object能被拖拽,那么调用一下dispose就可以了, 至于下面的三个小方法isDragging, isListening, isDisposed一看便知, 返回相关的状态. 最后给个源码的下拉链接 下载点我 欢迎园友留言,

焦点访谈

最新最热的文章

更多 >

COPYRIGHT (©) 2017 Copyright ©2017 888真人 网站地图

联系我们

827570882

扫描二维码分享到微信