`
literary_fly
  • 浏览: 92577 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

JavaScript相关文章推荐

阅读更多

判断js数组包是否包含某个元素
要判断数组中是否包含某个元素,从原理来来说,就是遍历整个数组,然后判断是否相等,我们来造个轮子,名字就山寨PHP的数组函数in_array()

view sourceprint?
1 Array.prototype.in_array = function(e) 

2 { 

3 for(i=0;i<this.length;i++) 

4 { 

5 if(this[i] == e) 

6 return true; 

7 } 

8 return false; 

9 }
或者

view sourceprint?
1 Array.prototype.in_array = function(e) 

2 { 

3 for(i=0;i<this.length && this[i]!=e;i++); 

4 return !(i==this.length); 

5 }
Filed under: JavaScript Array 发表评论 判断一个元素(对象)是否为另一个元素的子元素
js通过contains和compareDocumentPosition方法来确定DOM节点间的关系,判断一个元素(对象)是否为另一个元素的子元素

首先自己写一个:


view sourceprint?
1 function isParent(obj,pobj){ 

2 do{ 

3 obj = obj.parentNode; 

4 if(obj==pobj){ 

5 return true; 

6 } 

7 }while(obj.tagName!='BODY'); 

8 return false; 

9 }
Filed under: JavaScript 未分类 发表评论 js通过classname来获取元素
原生JS有3种方式来获取元素:

getElementById('id')
getElementsByName('name')
getElementsByTagName('tag')
getElementById是获取元素最快的方式,但我们不能给每个HTML元素都加以ID吧,所以我们需要一个很方便的通过classname来获取元素:

view sourceprint?
01 function getElementsByClassName(className,tagName){ 

02 var ele=[],all=document.getElementsByTagName(tagName||"*"); 

03 for(var i=0;i<all.length;i++){ 

04 if(all[i].className==className){ 

05 ele[ele.length]=all[i]; 

06 } 

07 } 

08 return ele; 

09 } 

10 console.log(getElementsByClassName("entry")); 

11 console.log(getElementsByClassName("entry","div"));
Filed under: JavaScript className 前端开发 发表评论 jQuery hasClass(),jQuery判断元素是否含有className
jQuery中的hasClass(selector)

返回值

Boolean



参数

class (String) : 用于匹配的类名,注意不需要加"."

检查当前的元素是否含有某个特定的类,如果有,则返回true。

这其实就是 is("." + class)。我们看下源代码:

view sourceprint?
1 function (selector) { 

2 return this.is("." + selector); 

3 }
Filed under: jQuery javaScript className 发表评论 返回两个数组中不同的元素,求数组反集
有两个数组

view sourceprint?
1 var a=['1','2','3','4'] 

2 var b=['1','2']
如何比较才能返回两个数组中不同的元素,其实就是求两个数组的反集,得到数组c=['3','4']

基本的算法就是比较两个数组的元素,把不同的挑出来放到一个数组里,最后返回该Array



我在上一篇文章中山寨了一个JS版的in_array函数
Filed under: JavaScript Array 发表评论 jquery.add()追加元素
我们先来看下jQuery官方文档上add()方法的使用

1)add(expr)  在原对象的基础上再附加符合指定表达式的jquery对象

2)add(el)  在匹配对象的基础上再附加指定的dom元素。

3)add(els)  在匹配对象的基础上再附加指定的一组对象,els是一个数组。

4)add(html)在匹配对象的基础上再附加指定的一段HTML片段
Filed under: 前端开发, jQuery add 发表评论 jQuery获得元素位置
jquery 中有两个获取元素位置的方法offset()和position(),这两个方法之间有什么异同

offset():

获取匹配元素在当前视口的相对偏移。

返回的对象包含两个整形属性:top 和 left。此方法只对可见元素有效。

.offset()方法可以让我们重新设置元素的位置。这个元素的位置是相对于document对象的。如果对象原先的position样式属性是 static的话,会被改成relative来实现重定位。

position():

获取匹配元素相对父元素的偏移。
Filed under: jQuery 绝对定位 offset 发表评论 javascript获取Dom节点元素
在前端开发中,经常要通过JavaScript来获取页面中某个DOM元素,然后更新该元素的样式、内容等。如何获取要更新的元素,是首先要解决的问题。令人欣慰的是,使用JavaScript获取DOM节点的方法有很多种,这里简单做一下总结:



       1. 通过顶层document节点获取:
Filed under: JavaScript DOM 发表评论 原生JavaScript给元素增加className
jquery的addClass如何用原生javascript实现?

class是元素的属性,所以我们可以通过setAttribute来获取class

这里需要注意的是class在IE中是保留关键字

所以我们获取某个元素的class时需要用className来代替class

className在所有浏览器中都兼容

view sourceprint?
1 ele.getAttribute("className");//IE 

2 ele.getAttribute("class");//非IE浏览器 

3 ele.setAttribute("className","类名");//IE
Filed under: JavaScript cssClass 发表评论 jQuery替换element元素上已经绑定的事件
jQuery如何重新绑定已经绑定的事件?虽然我们现在推荐行为分离,渐进增强,但在很多遗留系统里还是存在很多这样的代码

view sourceprint?
1 <input type="button" value="ClickMe" id="btn1" onclick="foo()" />
就是直接在DOM元素上绑定事件

这样做有很多缺点

1.代码高度耦合

2.增加HTML大小

3.书写不了逻辑性很强的代码
Filed under: jQuery unbind bind event JavaScript事件 发表评论 JQuery 获取,遍历和操作表单元素Select,checkbox,radio


是的方式的发

Filed under: jQuery 发表评论 magento查看用户是否登录
在magento中有些功能是需要用户登录之后才可以展示给客户看到.在magento中用户登录是放在session中的 如果要查看用户是否登录来控制权限可以这样用

view sourceprint?
1 if (!Mage::getSingleton("customer/session")->isLoggedIn())  { 

2 // 客户没有登录,这里输入处理流程. 

3 }
注意前面有个感叹号。。

我们可以在controller中实现,如果用户没有登录,就跳转到登录页面去

view sourceprint?
1 if (!Mage::getSingleton("customer/session")->isLoggedIn()) 

2 { 

3 $session = Mage::getSingleton("customer/session"); 

4 $customerLoginURL = $this->getBaseUrl() . "customer/account/login"; 

5 Mage::app()->getFrontController()->getResponse()->setRedirect($customerLoginURL)->sendResponse(); 

6 }
Filed under: Magento controller 会员 发表评论 js框架jRaiser源代码



view sourceprint?
0001 /* 

0002 * jRaiser Javascript Library v1.3.3 

0003 * http://code.google.com/p/jraiser/ 

0004 * 

0005 * Copyright 2008-2010 Heero.Luo (http://heeroluo.net/) 

0006 * licensed under a modified MIT license 

0007 * For detail, see http://code.google.com/p/jraiser/wiki/license 

0008 * 

0009 * Creation date: 2008/2/6 

0010 * Modified date: 2010/4/29 

0011 */

0012 (function(window, undefined) { 

0013 var version = "1.3.3 Build 201004291430", // 版本号 

0014 globalName = "jRaiser";  // 全局标识符 

0015 // 防止重复加载 

0016 if (window[globalName] && window[globalName].version >= version) { return; } 

0017 var _$ = window.$,  // 记录当前框架,以便恢复 

0018 document = window.document, 

0019 /// @overload 根据CSS选择器和上下文匹配出HTML元素 

0020 ///  @param {String} CSS选择器 

0021 ///  @param {HTMLElement,Array,HTMLCollection} 上下文 

0022 ///  @return {HTMLElement,Array} 匹配到的经扩展的HTML元素 

0023 /// @overload 扩展HTML元素 

0024 ///  @param {HTMLElement,Array,HTMLCollection} 要扩展的Html元素 

0025 ///  @return {HTMLElement,Array} 经扩展的HTML元素 

0026 jRaiser = window[globalName] = window.$ = function(selector, context) { 

0027 if (!selector) { return selector; } 

0028 "string" === typeof selector && (selector = getElemsBySelector(selector, context)); 

0029 return extendElems(selector); 

0030 }; 

0031 /// 根据上下文及CSS选择器获取结果集中的第一个元素 

0032 /// @param {String} CSS选择器 

0033 /// @param {HTMLElement,Array,HTMLCollection} 上下文 

0034 /// @return {HTMLElement} 匹配到的经扩展的HTML元素 

0035 jRaiser.one = function(selector, context) { 

0036 return extendElems(getElemsBySelector(selector, context, 1)); 

0037 }; 

0038 /// 根据上下文及CSS选择器获取所有元素 

0039 /// @param {String} CSS选择器 

0040 /// @param {HTMLElement,Array,HTMLCollection} 上下文 

0041 /// @return {Array} 匹配到的经扩展的HTML元素数组 

0042 jRaiser.all = function(selector, context) { 

0043 return extendElems(getElemsBySelector(selector, context, 0)); 

0044 }; 

0045 // 根据上下文及CSS选择器获取HTML元素 

0046 // @param {String} CSS选择器 

0047 // @param {HTMLElement,Array,HTMLCollection} 上下文 

0048 // @param {Number} 结果集数量限制:默认返回原结果;为1时只返回第一个元素;为0时把结果按数组形式返回 

0049 // @return {HTMLElement,Array} 匹配到的经扩展的HTML元素 

0050 function getElemsBySelector(selector, context, limit) { 

0051 // 通过选择器解析引擎获取元素 

0052 var result = selectorQuery.exec(selector, context || document); 

0053 if (limit !== undefined) { 

0054 if (result) { 

0055 var isArray = jRaiser.util.isArray(result); 

0056 if (1 === limit && isArray) { 

0057 return result[0]; 

0058 } else if (0 === limit && !isArray) { 

0059 return [result]; 

0060 } 

0061 } else if (0 === limit) { 

0062 return []; 

0063 } 

0064 } 

0065 return result; 

0066 } 

0067 // 扩展HTML元素(数组) 

0068 // @param {HTMLElement,Array,HTMLCollection} 元素(数组) 

0069 // @return {HtmlElement,Array} 扩展后的元素 

0070 function extendElems(elems) { 

0071 if (elems && !elems[globalName]) { 

0072 if (elems.nodeType) { // 扩展Html元素和非IE下的XML元素 

0073 if ("unknown" !== typeof elems.getAttribute) { 

0074 for (var p in jRaiser.element) { 

0075 // 不覆盖原有的属性和方法 

0076 undefined === elems[p] && (elems[p] = jRaiser.element[p]); 

0077 } 

0078 } 

0079 } else { // HTMLCollection Or Array 

0080 elems = jRaiser.util.extend(jRaiser.util.toArray(elems), jRaiser.element); 

0081 } 

0082 } 

0083 return elems; 

0084 } 

0085 /// 标识当前版本 

0086 jRaiser.version = version; 

0087 /// 恢复本类库对$和jRaiser全局变量的占用 

0088 /// @return {Object} jRaiser对象 

0089 jRaiser.resume = function() { 

0090 _$ = window.$; 

0091 window.$ = window[globalName] = jRaiser; 

0092 return jRaiser; 

0093 }; 

0094 /// 恢复最近一次本类库加载前或jRaiser.resume方法调用前的$变量 

0095 /// @return {Mixed} 原$变量 

0096 jRaiser.retire = function() { 

0097 window.$ = _$; 

0098 return _$; 

0099 }; 

0100 // 用于特性检查的元素 

0101 var testElem = document.createElement("div"); 

0102 testElem.innerHTML = "<p class='TEST'></p>"; 

0103 // selectorQuery选择器解析引擎 

0104 var selectorQuery = { 

0105 SPACE : /\s*([\s>~+,])\s*/g, // 用于去空格 

0106 ISSIMPLE : /^#?[\w\u00c0-\uFFFF_-]+$/,  // 判断是否简单选择器(只有id或tagname,不包括*) 

0107 IMPLIEDALL : /([>\s~\+,]|^)([#\.\[:])/g,  // 用于补全选择器 

0108 ATTRVALUES : /=(["'])([^'"]*)\1]/g,   // 用于替换引号括起来的属性值 

0109 ATTR : /\[\s*([\w\u00c0-\uFFFF_-]+)\s*(?:(\S?\=)\s*(.*?))?\s*\]/g, // 用于替换属性选择器 

0110 PSEUDOSEQ : /\(([^\(\)]*)\)$/g,  // 用于匹配伪类选择器最后的序号 

0111 BEGINIDAPART : /^(?:\*#([\w\u00c0-\uFFFF_-]+))/,  // 用于分离开头的id选择器 

0112 STANDARD : /^[>\s~\+:]/,  // 判断是否标准选择器(以空格、>、~或+开头) 

0113 STREAM : /[#\.>\s\[\]:~\+]+|[^#\.>\s\[\]:~\+]+/g, // 用于把选择器表达式分离成操作符/操作数 数组 

0114 ISINT : /^\d+$/, // 判断是否整数 

0115 // 判断是否使用浏览器的querySelectorAll 

0116 enableQuerySelector : testElem.querySelectorAll && testElem.querySelectorAll(".TEST").length > 0, 

0117 tempAttrValues : [], // 临时记录引号/双引号间的属性值 

0118 tempAttrs: [],  // 临时记录属性表达式 

0119 idName : globalName + "UniqueId", 

0120 id : 0, 

0121 // 解析CSS选择器获取元素 

0122 // @param {String} 选择器 

0123 // @param {HTMLElement,Array,HTMLCollection} 上下文 

0124 // @return {HTMLElement,Array,HTMLCollection} 匹配到的元素 

0125 exec : function(selector, context) { 

0126 var result,  // 最后结果 

0127 selectors,  // selector数组 

0128 selCount,  // selector数组长度 

0129 i, j,   // 循环变量 

0130 temp,   // 临时搜索结果 

0131 matchs,  // 操作符/操作数 数组 

0132 streamLen,  // 操作符/操作数 数组长度 

0133 token,   // 操作符 

0134 filter,  // 操作数 

0135 t = this; 

0136 // 清除多余的空白 

0137 selector = selector.trim(); 

0138 if ("" === selector) { return; } 

0139 // 对简单选择符的优化操作 

0140 if (t.ISSIMPLE.test(selector)) { 

0141 if (0 === selector.indexOf("#") && typeof context.getElementById !== "undefined") { 

0142 //alert("simple id: " + selector); // @debug 

0143 return t.getElemById(context, selector.substr(1)); 

0144 } else if (typeof context.getElementsByTagName !== "undefined") { 

0145 //alert("simple tagname: " + selector); // @debug 

0146 return jRaiser.util.toArray(context.getElementsByTagName(selector)); 

0147 } 

0148 } 

0149 // 使用querySelectorAll 

0150 if (t.enableQuerySelector && context.nodeType) { 

0151 try { 

0152 return jRaiser.util.toArray(context.querySelectorAll(selector)); 

0153 } catch (e) { 

0154 } 

0155 } 

0156 // 转换成数组,统一处理 

0157 context = context.nodeType ? [context] : jRaiser.util.toArray(context); 

0158 selectors = selector.replace(t.SPACE, "$1")  // 去空白 

0159 .replace(t.ATTRVALUES, t.analyzeAttrValues) // 替换属性值 

0160 .replace(t.ATTR, t.analyzeAttrs) // 替换属性选择符 

0161 .replace(t.IMPLIEDALL, "$1*$2")  // 添加必要的"*"(例如.class1 => *.class1) 

0162 .split(","); // 分离多个选择器 

0163 selCount = selectors.length; 

0164 i = -1; result = []; 

0165 while (++i < selCount) { 

0166 // 重置上下文 

0167 temp = context; 

0168 selector = selectors[i]; 

0169 if (t.BEGINIDAPART.test(selector)) { // 优化以id选择器开头且上下文是document的情况 

0170 if (typeof context[0].getElementById !== "undefined") { 

0171 //alert("begin with id selector: " + RegExp.$1); // @debug 

0172 temp = [t.getElemById(context[0], RegExp.$1)]; 

0173 //alert("result: " + temp); // @debug 

0174 if (!temp[0]) { 

0175 continue; 

0176 } 

0177 selector = RegExp.rightContext; 

0178 } else { // 上下文不是document, 恢复常规查找 

0179 selector = selectors[i]; 

0180 } 

0181 } 

0182 // 处理后续的部分 

0183 if (selector !== "") { 

0184 if (!t.STANDARD.test(selector)) { 

0185 selector = " " + selector; 

0186 } 

0187 // 分离换成字符串数组,从0开始双数是操作符,单数是操作数(例如 " *.class1" => [" ", "*", ".", "class1"]) 

0188 matchs = selector.match(t.STREAM) || []; streamLen = matchs.length; j = 0; 

0189 //alert("stream: " + matchs); // @debug 

0190 while (j < streamLen) { 

0191 token = matchs[j++]; filter = matchs[j++]; 

0192 //alert(token + (this.operators[token] ? " is " : " is not ") + "exist");  // @debug 

0193 //alert("filter: " + filter); // @debug 

0194 //alert("context: " + temp); // @debug 

0195 temp = t.operators[token] ? t.operators[token](temp, filter) : []; 

0196 if (0 === temp.length) { 

0197 break; 

0198 } 

0199 } 

0200 } 

0201 jRaiser.util.merge(result, temp); 

0202 } 

0203 // 清空临时数组 

0204 t.tempAttrValues.length = t.tempAttrs.length = 0; 

0205 return result.length > 1 ? t.unique(result) : result; 

0206 }, 

0207 // 属性替换处理函数 

0208 analyzeAttrs : function($1, $2, $3, $4) { 

0209 return "[]" + (selectorQuery.tempAttrs.push([$2, $3, $4]) - 1); 

0210 }, 

0211 // 属性值替换处理函数 

0212 analyzeAttrValues : function($1, $2, $3) { 

0213 return "=" + (selectorQuery.tempAttrValues.push($3) - 1) + "]"; 

0214 }, 

0215 // 获取不重复的元素id 

0216 // @param {HTMLElement} 元素 

0217 // @return {Number} id 

0218 generateId : function(elem) { 

0219 var idName = this.idName, id; 

0220 try { 

0221 id = elem[idName] = elem[idName] || new Number(++this.id); 

0222 } catch (e) { 

0223 id = elem.getAttribute(idName); 

0224 if (!id) { 

0225 id = new Number(++this.id); 

0226 elem.setAttribute(idName, id); 

0227 } 

0228 } 

0229 return id.valueOf(); 

0230 }, 

0231 // 去除数组中的重复元素 

0232 // @param {Array} 元素数组 

0233 // @return {Array} 已去重复的元素数组 

0234 unique : function(elems) { 

0235 var result = [], i = 0, flags = {}, elem, id; 

0236 while (elem = elems[i++]) { 

0237 if (1 === elem.nodeType) { 

0238 id = this.generateId(elem); 

0239 if (!flags[id]) { 

0240 flags[id] = true; 

0241 result.push(elem); 

0242 } 

0243 } 

0244 } 

0245 return result; 

0246 }, 

0247 // 属性名映射 

0248 attrMap : { 

0249 "class" : "className", 

0250 "for" : "htmlFor"

0251 }, 

0252 // 获取元素属性 

0253 // @param {HTMLElement} 元素 

0254 // @param {String} 属性名 

0255 // @return {String} 属性值 

0256 getAttribute : function(elem, attrName) { 

0257 var trueName = this.attrMap[attrName] || attrName, attrValue = elem[trueName]; 

0258 if ("string" !== typeof attrValue) { 

0259 if ("undefined" !== typeof elem.getAttributeNode) { 

0260 attrValue = elem.getAttributeNode(attrName); 

0261 attrValue = undefined == attrValue ? attrValue : attrValue.value; 

0262 } else if (elem.attributes) {  // for IE5.5 

0263 attrValue = String(elem.attributes[attrName]); 

0264 } 

0265 } 

0266 return null == attrValue ? "" : attrValue; 

0267 }, 

0268 // 通过id获取元素 

0269 // @param {HTMLElement} 上下文,一般是document 

0270 // @param {String} id 

0271 // @return {HTMLElement} 元素 

0272 getElemById : function(context, id) { 

0273 var result = context.getElementById(id); 

0274 if (result && result.id !== id && context.all) { // 修复IE下的id/name bug 

0275 result = context.all[id]; 

0276 if (result) { 

0277 result.nodeType && (result = [result]); 

0278 for (var i = 0; i < result.length; i++) { 

0279 if (this.getAttribute(result[i], "id") === id) { 

0280 return result[i]; 

0281 } 

0282 } 

0283 } 

0284 } else { 

0285 return result; 

0286 } 

0287 }, 

0288 // 搜索指定位置的某标签名元素 

0289 // @param {Array} 上下文 

0290 // @param {String} 第一个元素相对位置 

0291 // @param {String} 下一个元素相对位置 

0292 // @param {String} 标签名 

0293 // @param {Number} 最多进行多少次查找 

0294 // @return {Array} 搜索结果 

0295 getElemsByTagName : function(context, first, next, tagName, limit) { 

0296 var result = [], i = -1, len = context.length, elem, counter, tagNameUpper; 

0297 tagName !== "*" && (tagNameUpper = tagName.toUpperCase()); 

0298 while (++i < len) { 

0299 elem = context[i][first]; counter = 0; 

0300 while (elem && (!limit || counter < limit)) { 

0301 if (1 === elem.nodeType) { 

0302 (elem.nodeName.toUpperCase() === tagNameUpper || !tagNameUpper) && result.push(elem); 

0303 counter++; 

0304 } 

0305 elem = elem[next]; 

0306 } 

0307 } 

0308 return result; 

0309 }, 

0310 // 根据指定顺序检查上下文父元素的第n个子元素是否该上下文元素 

0311 // @param {Array} 上下文 

0312 // @param {Number} 序号 

0313 // @param {String} 第一个元素相对位置 

0314 // @param {String} 下一个元素相对位置 

0315 // @return {Array} 搜索结果 

0316 checkElemPosition : function(context, seq, first, next) { 

0317 var result = []; 

0318 if (!isNaN(seq)) { 

0319 var len = context.length, i = -1, 

0320 cache = {},  // 节点缓存 

0321 parent, id, current, child; 

0322 while (++i < len) { 

0323 parent = context[i].parentNode;  // 找到父节点 

0324 id = this.generateId(parent);  // 为父节点生成一个id作为缓存键值 

0325 if (undefined === cache[id]) { // 如果缓存中没有,则重新寻找父元素的第N个子元素 

0326 current = 0;   // 重置当前序号 

0327 child = parent[first]; // 第一个元素 

0328 while (child) { 

0329 1 === child.nodeType && current++; // 序号加1 

0330 if (current < seq) { 

0331 child = child[next]; // 还没到指定序号,继续找 

0332 } else { 

0333 break; // 已经到指定序号,中断循环 

0334 } 

0335 } 

0336 cache[id] = child || 0;  // 记下本次搜索结果 

0337 } else { 

0338 child = cache[id]; 

0339 } 

0340 context[i] === child && result.push(context[i]); // 搜索结果与节点相符 

0341 } 

0342 } 

0343 return result; 

0344 }, 

0345 // 获取特定位置的元素 

0346 // @param {Array} 上下文 

0347 // @param {Number} 第一个位置 

0348 // @param {Number} 下一个位置递增量 

0349 // @return {Array} 过滤结果 

0350 getElemsByPosition : function(context, first, next) { 

0351 var i = first, len = context.length, result = []; 

0352 while (i >= 0 && i < len) { 

0353 result.push(context[i]); 

0354 i += next; 

0355 } 

0356 return result; 

0357 }, 

0358 // 根据属性值过滤元素 

0359 // @param {Array} 上下文 

0360 // @param {Array} 属性数组 

0361 // @return {Array} 过滤结果 

0362 getElemsByAttribute : function(context, filter) { 

0363 var result = [], elem, i = 0, 

0364 check = this.attrOperators[filter[1] || ""], 

0365 attrValue = "~=" === filter[1] ? " " + filter[2] + " " : filter[2]; 

0366 if (check) { 

0367 while (elem = context[i++]) { 

0368 check(this.getAttribute(elem, filter[0]), attrValue) && result.push(elem); 

0369 } 

0370 } 

0371 return result; 

0372 }, 

0373 // 操作符 

0374 operators : { 

0375 // id选择符 

0376 "#" : function(context, id) { 

0377 return selectorQuery.getElemsByAttribute(context, ["id", "=", id]); 

0378 }, 

0379 // 后代选择符 

0380 " " : function(context, tagName) { 

0381 var len = context.length; 

0382 if (1 === len) { 

0383 return context[0].getElementsByTagName(tagName); 

0384 } else { 

0385 var result = [], i = -1; 

0386 while (++i < len) { 

0387 jRaiser.util.merge(result, context[i].getElementsByTagName(tagName)); 

0388 } 

0389 return result; 

0390 } 

0391 }, 

0392 // 类名选择器 

0393 "." : function(context, className) { 

0394 return selectorQuery.getElemsByAttribute(context, ["class", "~=", className]); 

0395 }, 

0396 // 子元素选择符 

0397 ">" : function(context, tagName) { 

0398 return selectorQuery.getElemsByTagName(context, "firstChild", "nextSibling", tagName); 

0399 }, 

0400 // 同级元素选择符 

0401 "+" : function(context, tagName) { 

0402 return selectorQuery.getElemsByTagName(context, "nextSibling", "nextSibling", tagName, 1); 

0403 }, 

0404 // 同级元素选择符 

0405 "~" : function(context, tagName) { 

0406 return selectorQuery.getElemsByTagName(context, "nextSibling", "nextSibling", tagName); 

0407 }, 

0408 // 属性选择符 

0409 "[]" : function(context, filter) { 

0410 filter = selectorQuery.tempAttrs[filter]; 

0411 if (filter) { 

0412 if (selectorQuery.ISINT.test(filter[2])) { 

0413 filter[2] = selectorQuery.tempAttrValues[filter[2]]; 

0414 } 

0415 return selectorQuery.getElemsByAttribute(context, filter); 

0416 } else { 

0417 return context; 

0418 } 

0419 }, 

0420 // 伪类选择符 

0421 ":" : function(context, filter) { 

0422 var seq; 

0423 if (selectorQuery.PSEUDOSEQ.test(filter)) { 

0424 seq = parseInt(RegExp.$1); 

0425 filter = RegExp.leftContext; 

0426 } 

0427 return selectorQuery.pseOperators[filter] ? selectorQuery.pseOperators[filter](context, seq) : []; 

0428 } 

0429 }, 

0430 // 属性操作符 

0431 attrOperators : { 

0432 // 是否包含指定属性值 

0433 "" : function(value) { return value !== ""; }, 

0434 // 是否与指定属性值相等 

0435 "=" : function(value, input) { return input === value; }, 

0436 // 是否包含指定属性值 

0437 "~=" : function(value, input) { return (" " + value + " ").indexOf(input) >= 0; }, 

0438 // 是否与指定属性值不等 

0439 "!=" : function(value, input) { return input !== value; }, 

0440 // 属性值是否以某段字符串开头 

0441 "^=" : function(value, input) { return value.indexOf(input) === 0; }, 

0442 // 属性值是否以某段字符串结尾 

0443 "$=" : function(value, input) { return value.substr(value.length - input.length) === input; }, 

0444 // 属性值是否包含某段子字符串 

0445 "*=" : function(value, input) { return value.indexOf(input) >= 0; } 

0446 }, 

0447 // 伪类选择符 

0448 pseOperators : { 

0449 // 获取第一个子元素 

0450 "first-child" : function(context) { 

0451 return selectorQuery.checkElemPosition(context, 1, "firstChild", "nextSibling"); 

0452 }, 

0453 // 获取第n个子元素 

0454 "nth-child" : function(context, seq) { 

0455 return selectorQuery.checkElemPosition(context, seq, "firstChild", "nextSibling"); 

0456 }, 

0457 // 获取最后一个子元素 

0458 "last-child" : function(context) { 

0459 return selectorQuery.checkElemPosition(context, 1, "lastChild", "previousSibling"); 

0460 }, 

0461 // 获取倒数第n个子元素 

0462 "nth-last-child" : function(context, seq) { 

0463 return selectorQuery.checkElemPosition(context, seq, "lastChild", "previousSibling"); 

0464 }, 

0465 // 获取第奇数个元素 

0466 "odd" : function(context) { 

0467 return selectorQuery.getElemsByPosition(context, 0, 2); 

0468 }, 

0469 // 获取第偶数个元素 

0470 "even": function(context) { 

0471 return selectorQuery.getElemsByPosition(context, 1, 2); 

0472 }, 

0473 // 获取第N个元素前的元素 

0474 "lt" : function(context, seq) { 

0475 return selectorQuery.getElemsByPosition(context, seq - 1, -1); 

0476 }, 

0477 // 获取第N个元素后的元素 

0478 "gt" : function(context, seq) { 

0479 return selectorQuery.getElemsByPosition(context, seq + 1, 1); 

0480 } 

0481 } 

0482 }; 

0483 // HTML元素扩展操作,用于继承 

0484 jRaiser.element = { 

0485 /// 获取指定序号的元素 

0486 /// @param {Number} 序号 

0487 /// @return {HTMLElement} 元素 

0488 get : function(i) { 

0489 return this.nodeType === undefined ? this[i] : (0 == i ? this : undefined); 

0490 }, 

0491 /// @overload 获取指定序号并经过扩展的元素 

0492 ///  @param {Number} 序号索引 

0493 ///  @return {HTMLElement} 指定序号并经过扩展的元素 

0494 /// @overload 以当前元素为上下文通过CSS选择器获取元素 

0495 ///  @param {String} CSS选择器 

0496 ///  @return {HTMLElement,Array} 匹配到的经扩展的HTML元素 

0497 $ : function(selector) { 

0498 return jRaiser("number" === typeof selector ? this.get(selector) : selector, this); 

0499 }, 

0500 /// 检查当前元素是否包含某些样式类 

0501 /// @param {String} 样式类名 

0502 /// @return {Boolean} 元素是否包含某个样式类 

0503 hasClass : function(className) { return jRaiser.style.hasClass(this, className); }, 

0504 /// 添加样式 

0505 /// @param {String,Object} 类名或样式,多个类名用空格隔开 

0506 /// @return {HTMLElement,Array} 当前元素 

0507 addCss : function(css) { return jRaiser.style.addCss(this, css); }, 

0508 /// 移除样式 

0509 /// @param {String,Object} 类名或样式,多个类名用空格隔开 

0510 /// @return {HTMLElement,Array} 当前元素 

0511 removeCss : function(css) { return jRaiser.style.removeCss(this, css); }, 

0512 /// 添加事件委托函数 

0513 /// @param {String} 事件名,多个事件用逗号隔开 

0514 /// @param {Function} 事件委托函数 

0515 /// @param {Mixed} 额外数据 

0516 /// @return {HTMLElement,Array} 当前元素 

0517 addEvent : function(eventName, handler, data) { 

0518 return jRaiser.event.addEvent(this, eventName, handler, data); 

0519 }, 

0520 /// 移除事件委托函数 

0521 /// @param {String} 事件名,多个事件用逗号隔开 

0522 /// @param {Function} 事件委托函数 

0523 /// @return {HTMLElement,Array} 当前元素 

0524 removeEvent : function(eventName, handler) { 

0525 return jRaiser.event.removeEvent(this, eventName, handler); 

0526 }, 

0527 /// @overload 获取当前元素的属性值 

0528 ///  @param {String} 属性名 

0529 ///  @return {Mixed} 属性值 

0530 /// @overload 设置当前元素的属性值 

0531 ///  @param {String} 属性名 

0532 ///  @param {String,Function} 属性值或用于计算属性值的函数 

0533 ///  @return {HTMLElement,Array} 当前元素 

0534 attr : function(name, value) { 

0535 var t = this; 

0536 name = selectorQuery.attrMap[name] || name; 

0537 if (value !== undefined) { 

0538 return jRaiser.dom.eachNode(t, function(name, value) { 

0539 this[name] = jRaiser.util.isFunction(value) ? value.call(this) : value; 

0540 }, arguments); 

0541 } else { 

0542 var elem = this.get(0); 

0543 return elem ? elem[name] : undefined; 

0544 } 

0545 }, 

0546 /// 对每个节点执行特定操作 

0547 /// @param {Function} 要执行的操作 

0548 /// @return {HTMLElement, Array} 当前元素 

0549 each : function(callback) { 

0550 return jRaiser.dom.eachNode(this, callback); 

0551 } 

0552 }; 

0553 jRaiser.element[globalName] = jRaiser.element.$; 

0554 // window对象、document对象的添加、移除事件方法 

0555 window.addEvent = document.addEvent = jRaiser.element.addEvent; 

0556 window.removeEvent = document.removeEvent = jRaiser.element.removeEvent; 

0557 var tplCache = {},  // 模板缓存 

0558 slice = Array.prototype.slice, 

0559 toString = Object.prototype.toString; // 简写toString 

0560 /// 工具类、工具函数 

0561 jRaiser.util = { 

0562 /// 检查变量是否Array类型 

0563 /// @param {Mixed} 待测变量 

0564 /// @return {Boolean} 待测变量是否Array类型 

0565 isArray : function(value) { return toString.call(value) === "[object Array]"; }, 

0566 /// 检查变量是否函数类型 

0567 /// @param {Mixed} 待测变量 

0568 /// @return {Boolean} 待测变量是否Function类型 

0569 isFunction : function(value) { return toString.call(value) === "[object Function]"; }, 

0570 /// 把集合转换为数组 

0571 /// @param {Array,Collection} 数组或集合 

0572 /// @return {Array} 数组 

0573 toArray : function(col) { 

0574 if (jRaiser.util.isArray(col)) { return col; } 

0575 var arr; 

0576 try { 

0577 arr = slice.call(col); 

0578 } catch (e) { 

0579 arr = []; 

0580 var i = col.length; 

0581 while (i) { 

0582 arr[--i] = col[i]; 

0583 } 

0584 } 

0585 return arr; 

0586 }, 

0587 /// 合并数组 

0588 /// @param {Array} 目标数组 

0589 /// @param {Array,Collection} 源数组 

0590 /// @return {Array} 混合后的目标数组 

0591 merge : function(first, second) { 

0592 var i = second.length, pos = first.length; 

0593 while (--i >= 0) { 

0594 first[pos + i] = second[i]; 

0595 } 

0596 return first; 

0597 }, 

0598 /// 模板转换 

0599 /// @param {String} 模板代码 

0600 /// @param {Object} 值集合 

0601 /// @param {Boolean} 是否缓存模板,默认为是 

0602 /// @return {String} 转换后的代码 

0603 parseTpl : function(tpl, values, isCached) { 

0604 var func = tplCache[tpl]; 

0605 null == values && (values = {}); 

0606 if (!func) { 

0607 func = new Function("obj", "var _=[];with(obj){_.push('" + 

0608 tpl.replace(/[\r\t\n]/g, " ") 

0609 .replace(/'(?=[^#]*#>)/g, "\t") 

0610 .split("'").join("\\'") 

0611 .split("\t").join("'") 

0612 .replace(/<#=(.+?)#>/g, "',$1,'") 

0613 .split("<#").join("');") 

0614 .split("#>").join("_.push('") 

0615 + "');}return _.join('');"); 

0616 (null == isCached || true === isCached) && (tplCache[tpl] = func); 

0617 } 

0618 return func(values); 

0619 }, 

0620 /// 把源对象的属性和方法扩展到目标对象上 

0621 /// @param {Mixed} 目标对象 

0622 /// @param {Mixed} 源对象 

0623 /// @return {Mixed} 已扩展的目标对象 

0624 extend : function(des, src) { 

0625 for (var p in src) { 

0626 des[p] = src[p]; 

0627 } 

0628 return des; 

0629 }, 

0630 /// 遍历数组或对象,对每个成员执行某个方法 

0631 /// @param {Mixed} 数组或对象 

0632 /// @param {Function} 回调函数 

0633 /// @param {Array} 额外参数 

0634 /// @return {Mixed} 原数组或对象 

0635 each : function(obj, callback, args) { 

0636 var i = -1, len = obj.length, 

0637 isObj = len === undefined || jRaiser.util.isFunction(obj); 

0638 if (args) { 

0639 if (isObj) { 

0640 for (i in obj ) { 

0641 if (false === callback.apply(obj[i], args)) { 

0642 break; 

0643 } 

0644 } 

0645 } else { 

0646 while (++i < len) { 

0647 if (false === callback.apply(obj[i], args)) { 

0648 break; 

0649 } 

0650 } 

0651 } 

0652 } else { 

0653 if (isObj) { 

0654 for (i in obj) { 

0655 if (false === callback.call(obj[i], i, obj[i])) { 

0656 break; 

0657 } 

0658 } 

0659 } else { 

0660 while (++i < len) { 

0661 if (false === callback.call(obj[i], i, obj[i])) { 

0662 break; 

0663 } 

0664 } 

0665 } 

0666 } 

0667 return obj; 

0668 } 

0669 }; 

0670 // 快速访问 

0671 jRaiser.parseTpl = jRaiser.util.parseTpl; 

0672 jRaiser.each = jRaiser.util.each; 

0673 var readyList = [],  // DOM Ready函数队列 

0674 isReadyBound,  // 是否已绑定DOM Ready事件 

0675 onDomReady; 

0676 if (document.addEventListener) { 

0677 onDomReady = function() { 

0678 document.removeEventListener("DOMContentLoaded", onDomReady, false); 

0679 domReadyNow(); 

0680 }; 

0681 } else if (document.attachEvent) { // For IE Only 

0682 onDomReady = function() { 

0683 if ("complete" === document.readyState) { 

0684 document.detachEvent("onreadystatechange", onDomReady); 

0685 domReadyNow(); 

0686 } 

0687 }; 

0688 } 

0689 // DOM Ready检查 For IE 

0690 function doScrollCheck() { 

0691 if (jRaiser.dom.isReady) { return; } 

0692 try { 

0693 document.documentElement.doScroll("left"); 

0694 } catch (e) { 

0695 setTimeout(doScrollCheck, 1); 

0696 return; 

0697 } 

0698 domReadyNow(); 

0699 } 

0700 // DOM已就绪 

0701 function domReadyNow() { 

0702 if (!jRaiser.dom.isReady) { 

0703 if (!document.body) { return setTimeout(domReadyNow, 13); } 

0704 jRaiser.dom.isReady = true; 

0705 if (readyList) { 

0706 var i = -1, len = readyList.length; 

0707 while (++i < len) { 

0708 readyList[i].call(document, jRaiser); 

0709 } 

0710 readyList = null; 

0711 } 

0712 } 

0713 } 

0714 // 绑定DOMReady事件 

0715 function bindReady() { 

0716 if (isReadyBound) { return; } 

0717 if ("complete" === document.readyState) { return domReadyNow(); } 

0718 if (document.addEventListener) { 

0719 document.addEventListener("DOMContentLoaded", domReadyNow, false); 

0720 window.addEventListener("load", domReadyNow, false); 

0721 } else if (document.attachEvent) { 

0722 document.attachEvent("onreadystatechange", domReadyNow); 

0723 window.attachEvent("onload", domReadyNow); 

0724 var isTopLevel; 

0725 try { 

0726 isTopLevel = window.frameElement == null; 

0727 } catch(e) {} 

0728 document.documentElement.doScroll && isTopLevel && doScrollCheck(); 

0729 } 

0730 isReadyBound = true; 

0731 } 

0732 /// DOM操作 

0733 jRaiser.dom = { 

0734 /// 把节点放到数组容器中 

0735 /// @param {HTMLElement,HTMLCollection,Array} 节点或节点集合 

0736 /// @return {Array} 节点数组 

0737 wrapByArray : function(nodes) { 

0738 if (nodes) { 

0739 if (nodes.nodeType !== undefined || nodes.setInterval) { 

0740 return [nodes]; 

0741 } else if (nodes.length) { 

0742 return jRaiser.util.toArray(nodes); 

0743 } 

0744 } 

0745 return []; 

0746 }, 

0747 /// 对节点执行指定操作 

0748 /// @param {HTMLElement,Array,HTMLCollection} 节点 

0749 /// @param {Function} 回调函数 

0750 /// @param {Array} 额外的参数 

0751 /// @return {HTMLElement,Array,HTMLCollection} 指定节点 

0752 eachNode : function(nodes, callback, args) { 

0753 jRaiser.each(jRaiser.dom.wrapByArray(nodes), callback, args); 

0754 return nodes; 

0755 }, 

0756 /// 在DOM就绪时执行指定函数 

0757 /// @param {Function} 指定函数 

0758 /// @param {Object} 当前对象 

0759 ready : function(fn) { 

0760 // 绑定事件 

0761 bindReady(); 

0762 if (jRaiser.dom.isReady) { 

0763 fn.call(document, jRaiser); 

0764 } else { 

0765 readyList.push(fn); 

0766 } 

0767 return this; 

0768 } 

0769 }; 

0770 // 快速访问 

0771 jRaiser.ready = jRaiser.dom.ready; 

0772 // 对CSS样式字符串进行解释的正则表达式 

0773 var CSSSPACE = /\s*([:;])\s*/g, 

0774 STYLENAME = /[^:;]+?(?=:)/g, 

0775 STYLESPLITER = /[^:;]+/g, 

0776 CLASSSPLITER = /[^\s]+/g, 

0777 FIXCSSNAME = /-([a-z])/gi, 

0778 FLOATNAME = testElem.style.styleFloat !== undefined ? "styleFloat" : "cssFloat", 

0779 ISFLOAT = /^float$/i; 

0780 // 添加样式类 

0781 function addClasses(classes, len, str) { 

0782 if (this.className) { 

0783 var className = " " + this.className + " ", i = -1; 

0784 while (++i < len) { 

0785 -1 === className.indexOf(" " + classes[i] + " ") && (className += (classes[i] + " ")); 

0786 } 

0787 this.className = className.trim(); 

0788 } else { 

0789 this.className = str; 

0790 } 

0791 } 

0792 // 添加样式 

0793 function addStyles(styles, len, str) { 

0794 if (!this.style.cssText && str) { 

0795 this.style.cssText = str; 

0796 } else { 

0797 var i = 0; 

0798 while (i < len) { 

0799 this.style[styles[i++]] = styles[i++].replace(/^NULL$/i, ""); 

0800 } 

0801 } 

0802 } 

0803 // 删除样式类 

0804 function removeClasses(classes, len, str) { 

0805 switch (this.className) { 

0806 case str: 

0807 this.className = ""; 

0808 break; 

0809 case "": 

0810 return; 

0811 break; 

0812 default: 

0813 var className = " " + this.className + " ", i = -1; 

0814 while (++i < len) { 

0815 className = className.replace(" " + classes[i] + " ", " "); 

0816 } 

0817 this.className = className.trim(); 

0818 break; 

0819 } 

0820 } 

0821 // 删除样式 

0822 function removeStyles(styles, len) { 

0823 for (var i = 0; i < len; i++) { 

0824 this.style[styles[i]] !== undefined && (this.style[styles[i]] = ""); 

0825 } 

0826 } 

0827 /// 样式控制 

0828 jRaiser.style = { 

0829 /// 把样式名转换成样式属性名 

0830 /// @param {String} 样式名 

0831 /// @return {String} 样式属性名 

0832 fixStyleName : function(name) { 

0833 return ISFLOAT.test(name) ? FLOATNAME : name.replace(FIXCSSNAME, function($0, $1) { 

0834 return $1.toUpperCase(); // 转换为js标准的样式名 

0835 }); 

0836 }, 

0837 /// 检查指定元素是否包含某些样式类 

0838 /// @param {HTMLElement,HTMLCollection,Array} 指定元素 

0839 /// @param {String} 样式类名 

0840 /// @return {Boolean} 元素是否包含某个样式类 

0841 hasClass : function(elems, className) { 

0842 elems = jRaiser.dom.wrapByArray(elems); 

0843 var i = elems.length; 

0844 if (i > 0) { 

0845 className = " " + className + " "; 

0846 while (--i >= 0) { 

0847 if ((" " + elems[i].className + " ").indexOf(className) >= 0) { 

0848 return true; 

0849 } 

0850 } 

0851 } 

0852 return false; 

0853 }, 

0854 // 识别CSS样式 

0855 // @param {String,Object} 样式 

0856 // @return {Array} 标记了样式类型的样式流 

0857 parse : function(css) { 

0858 var result; 

0859 if ("string" === typeof css) { 

0860 var hasSemi = css.indexOf(";") >= 0, hasColon = css.indexOf(":") >= 0; 

0861 if (hasSemi || hasColon) { 

0862 result = css.trim() 

0863 .replace(CSSSPACE, "$1") 

0864 .replace(hasColon ? STYLENAME : STYLESPLITER, jRaiser.style.fixStyleName) 

0865 .match(STYLESPLITER); 

0866 if (hasColon && result.length % 2 !== 0) { 

0867 throw "invalid inline style"; 

0868 } 

0869 result.type = "style"; 

0870 } else { 

0871 result = css.match(CLASSSPLITER) || []; 

0872 result.type = "class"; 

0873 } 

0874 } else { 

0875 result = []; 

0876 for (var name in css) { 

0877 result.push(jRaiser.style.fixStyleName(name), css[name]); 

0878 } 

0879 result.type = "style"; 

0880 } 

0881 return result; 

0882 }, 

0883 /// 为指定HTML元素添加样式 

0884 /// @param {HTMLElement,Array,HTMLCollection} 指定元素 

0885 /// @param {String,Object} 样式 

0886 /// @return {HTMLElement,Array,HTMLCollection} 指定元素 

0887 addCss : function(elems, css) { 

0888 var stream = jRaiser.style.parse(css); 

0889 return jRaiser.dom.eachNode( 

0890 elems, "class" === stream.type ? addClasses : addStyles, 

0891 [stream, stream.length, "string" === typeof css ? css : undefined] 

0892 ); 

0893 }, 

0894 /// 为指定HTML元素移除样式 

0895 /// @param {HTMLElement,Array,HTMLCollection} 指定元素 

0896 /// @param {String,Object} 样式 

0897 /// @return {HTMLElement,Array,HTMLCollection} 指定元素 

0898 removeCss : function(elems, css) { 

0899 var stream = jRaiser.style.parse(css); 

0900 return jRaiser.dom.eachNode( 

0901 elems, "class" === stream.type ? removeClasses : removeStyles, 

0902 [stream, stream.length, css] 

0903 ); 

0904 }, 

0905 /// 获取指定元素的当前样式 

0906 /// @param {HTMLElement,Array,HTMLCollection} 指定元素 

0907 /// @param {String} 样式名 

0908 /// @param {Object} 元素所在的页面的window对象,默认为当前window对象 

0909 /// @return {String} 样式值 

0910 getCurrentStyle : function(nodes, styleName, w) { 

0911 if (!nodes) { return undefined; } 

0912 !nodes.nodeType && (nodes = nodes[0]); 

0913 return (nodes.currentStyle || (w || window).getComputedStyle(nodes, null)) 

0914 [jRaiser.style.fixStyleName(styleName)]; 

0915 } 

0916 }; 

0917 // 添加事件 

0918 function newEvent(eventName, handler, data) { 

0919 var t = this; 

0920 handler = jRaiser.event.delegate(t, eventName, handler, data); 

0921 if (t.attachEvent) { 

0922 t.attachEvent("on" + eventName, handler); 

0923 } else if (t.addEventListener) { 

0924 t.addEventListener(eventName, handler, false); 

0925 } 

0926 } 

0927 // 移除事件 

0928 function disposeEvent(eventName, handler) { 

0929 var t = this; 

0930 handler = jRaiser.event.getDelegate(t, eventName, handler); 

0931 if (t.detachEvent) { 

0932 t.detachEvent("on" + eventName, handler); 

0933 } else if (t.removeEventListener) { 

0934 t.removeEventListener(eventName, handler, false); 

0935 } 

0936 } 

0937 var EVENTSPLITER = /\s*,\s*/, // 事件名分隔符 

0938 eventId = 0; // 事件编号基值 

0939 /// 事件处理 

0940 jRaiser.event = { 

0941 /// 事件Id属性名 

0942 idName : globalName + "EventId", 

0943 /// 事件容器名 

0944 eventsWrapper : globalName + "Events", 

0945 /// 为指定HTML元素添加事件委托函数 

0946 /// @param {HTMLElement,Array,HTMLCollection} 指定元素 

0947 /// @param {String} 事件名,多个事件名用逗号隔开 

0948 /// @param {Function} 事件委托函数 

0949 /// @param {Object} 额外传入的数据 

0950 /// @return {HTMLElement,Array,HTMLCollection} 指定元素 

0951 addEvent : function(elems, eventNames, handler, data) { 

0952 eventNames = eventNames.split(EVENTSPLITER); 

0953 var i = eventNames.length; 

0954 while (--i >= 0) { 

0955 jRaiser.dom.eachNode(elems, newEvent, [eventNames[i], handler, data]); 

0956 } 

0957 return elems; 

0958 }, 

0959 /// 为指定HTML元素移除事件委托函数 

0960 /// @param {HTMLElement,Array,HTMLCollection} 指定元素 

0961 /// @param {String} 事件名,多个事件名用逗号隔开 

0962 /// @param {Function} 事件处理函数 

0963 /// @return {HTMLElement,Array,HTMLCollection} 指定元素 

0964 removeEvent : function(elems, eventNames, handler) { 

0965 eventNames = eventNames.split(EVENTSPLITER); 

0966 var i = eventNames.length; 

0967 while (--i >= 0) { 

0968 jRaiser.dom.eachNode(elems, disposeEvent, [eventNames[i], handler]); 

0969 } 

0970 return elems; 

0971 }, 

0972 /// 生成事件代理 

0973 /// @param {HTMLElement} 元素 

0974 /// @param {String} 事件名 

0975 /// @param {Function} 事件处理函数 

0976 /// @param {Object} 额外传入的数据 

0977 /// @return {Function} 事件代理 

0978 delegate : function(elem, eventName, handler, data) { 

0979 var t = jRaiser.event, events = elem[t.eventsWrapper] = elem[t.eventsWrapper] || {},  // 取得事件Hash表引用 

0980 id = handler[t.idName] = handler[t.idName] || ++eventId;  // 获取不重复的事件编号 

0981 // 生成特定事件Hash表 

0982 events[eventName] = events[eventName] || {}; 

0983 var trueHandler = events[eventName][id]; 

0984 if (!trueHandler) { 

0985 trueHandler = function(e) { 

0986 e = t.fix(e); 

0987 var temp = handler.call(elem, e, data || {}); 

0988 false === temp && e.preventDefault(); 

0989 return temp; 

0990 }; 

0991 events[eventName][id] = trueHandler; 

0992 } 

0993 return trueHandler; 

0994 }, 

0995 /// 获取事件代理 

0996 /// @param {HTMLElement} 元素 

0997 /// @param {String} 事件名 

0998 /// @param {Function} 事件处理函数 

0999 /// @return {Function} 事件代理 

1000 getDelegate : function(elem, eventName, handler) { 

1001 var t = jRaiser.event; 

1002 try { 

1003 return elem[t.eventsWrapper][eventName][handler[t.idName]]; 

1004 } catch (e) { 

1005 } 

1006 return handler; 

1007 }, 

1008 /// 修复不同浏览器的事件兼容性 

1009 /// @param {Event} 事件对象 

1010 /// @return {Event} 修复后的事件对象 

1011 fix : function(e) { 

1012 if (!e.target) { 

1013 e.target = e.srcElement || document; 

1014 } 

1015 if (3 == e.target.nodeType) { 

1016 e.target = e.target.parentNode; 

1017 } 

1018 e.timestamp = e.timeStamp || Date.now(); 

1019 e.preventDefault = e.preventDefault || function() { 

1020 e.returnValue = false; 

1021 }; 

1022 if (undefined === e.pageX && undefined !== e.clientX) { 

1023 var doc = document.documentElement, body = document.body; 

1024 e.pageX = e.clientX + (doc.scrollLeft || body.scrollLeft || 0) - (doc.clientLeft || 0); 

1025 e.pageY = e.clientY + (doc.scrollTop || body.scrollTop || 0) - (doc.clientTop || 0); 

1026 } 

1027 if (!e.which) { 

1028 e.which = e.charCode || e.keyCode; 

1029 } 

1030 // 鼠标单击:1 == 左键; 2 == 中键; 3 == 右键 

1031 if (!e.which && e.button) { 

1032 e.which = (e.button & 1 ? 1 : (e.button & 2 ? 3 : (e.button & 4 ? 2 : 0))); 

1033 } 

1034 return e; 

1035 } 

1036 }; 

1037 // 获取客户端信息 

1038 var userAgent = window.navigator.userAgent.toLowerCase(); 

1039 /// 浏览器检测对象 

1040 jRaiser.browser = { 

1041 /// {String} 浏览器版本 

1042 version : (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [0,'0'])[1], 

1043 /// {Boolean} 是否Safari浏览器 

1044 safari : /webkit/.test(userAgent), 

1045 /// {Boolean} 是否Opera浏览器 

1046 opera : /opera/.test(userAgent), 

1047 /// {Boolean} 是否IE浏览器 

1048 msie : /msie/.test(userAgent) && !/opera/.test(userAgent), 

1049 /// {Boolean} 是否Mozilla浏览器 

1050 mozilla : /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent) 

1051 }; 

1052 /// Ajax操作 

1053 jRaiser.ajax = { 

1054 /// 创建XmlHttpRequest对象 

1055 /// @return {XMLHttpRequest} XmlHttpRequest对象 

1056 createXhr : function() { 

1057 var xhr; 

1058 try { 

1059 xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); 

1060 } catch (e) { } 

1061 if (!xhr) { 

1062 throw "failed to create XMLHttpRequest object"; 

1063 } 

1064 return xhr; 

1065 }, 

1066 /// 发送Ajax请求 

1067 /// @param {String} 请求地址 

1068 /// @param {String} 发送方式,"GET"或"POST",默认为GET 

1069 /// @param {Object} 发送的数据 

1070 /// @param {Object} 其他可选参数 

1071 /// @param {XMLHttpRequest} 用于发送请求的XmlHttpRequest对象,如不指定则自动创建 

1072 /// @return {XMLHttpRequest} XmlHttpRequest对象 

1073 send : function(url, method, data, options, xhr) { 

1074 // 创建XMLHttpRequest对象 

1075 xhr = xhr || jRaiser.ajax.createXhr(); 

1076 var hasCompleted; 

1077 // 修正参数 

1078 "string" === typeof method && (method = method.toUpperCase()); 

1079 method = method !== "GET" && method !== "POST" ? "GET" : method;  // 默认为GET 

1080 options = options || {}; 

1081 options.async = "boolean" === typeof options.async ? options.async : true; 

1082 // 连接参数键值对 

1083 var postData; 

1084 if (data) { 

1085 postData = []; 

1086 for (var d in data) { 

1087 data[d] != null && postData.push(d + "=" + encodeURIComponent(data[d])); 

1088 } 

1089 postData = postData.join("&").replace(/%20/g, "+"); 

1090 if ("GET" === method) { 

1091 url += ("?" + postData); 

1092 postData = undefined; 

1093 } 

1094 } 

1095 // 超时处理(异步处理时才有效) 

1096 options.async && !isNaN(options.timeout) && options.timeout > 0 && setTimeout(function() { 

1097 if (!hasCompleted) { 

1098 xhr.abort(); 

1099 options.onTimeout && options.onTimeout(xhr); 

1100 } 

1101 }, options.timeout); 

1102 // 设定状态变换时的事件 

1103 xhr.onreadystatechange = function() { 

1104 if (4 == xhr.readyState) { 

1105 hasCompleted = true; 

1106 var eventName = 200 == xhr.status ? "onSuccess" : "onError"; 

1107 options[eventName] && options[eventName](xhr); 

1108 } 

1109 }; 

1110 // 打开连接并发送数据 

1111 xhr.open(method, url, options.async, options.username, options.password); 

1112 var contentType = []; 

1113 "POST" === method && contentType.push("application/x-www-form-urlencoded"); 

1114 // 设置header 

1115 if (options.headers) { 

1116 for (var h in options.headers) { 

1117 if ("content-type" === h.toLowerCase()) { 

1118 contentType.push(options.headers[h]); 

1119 } else { 

1120 xhr.setRequestHeader(h, options.headers[h]); 

1121 } 

1122 } 

1123 } 

1124 contentType.length && 

1125 xhr.setRequestHeader("Content-Type", contentType.join(";").replace(/;+/g, ";").replace(/;$/, "")); 

1126 xhr.send(postData); 

1127 return xhr; 

1128 }, 

1129 /// 动态加载外部Javascript文件 

1130 /// @param {String} 文件地址 

1131 /// @param {Function} 加载完成后执行的回调函数 

1132 /// @param {String} 编码 

1133 /// @param {Object} 文档对象,默认为当前文档 

1134 importJs : function(url, onComplete, charset, doc) { 

1135 doc = doc || document; 

1136 var script = doc.createElement("script"); 

1137 script.language = "javascript"; script.type = "text/javascript"; 

1138 if (charset) { 

1139 script.charset = charset; 

1140 } 

1141 // 读取完后的操作 

1142 script.onload = script.onreadystatechange = function() { 

1143 if (!script.readyState || "loaded" == script.readyState || "complete" == script.readyState) { 

1144 onComplete && onComplete(); 

1145 script.onload = script.onreadystatechange = null; 

1146 script.parentNode.removeChild(script); 

1147 } 

1148 }; 

1149 script.src = url; 

1150 doc.getElementsByTagName("head")[0].appendChild(script); 

1151 } 

1152 }; 

1153 // Cookie过期时间格式 

1154 var EXPIRESWITHUNIT = /[smhdMy]$/, 

1155 TIMEUNITS = { 

1156 s : 1, 

1157 m : 60, 

1158 h : 60 * 60, 

1159 d : 24 * 60 * 60, 

1160 M : 30 * 24 * 60 * 60, 

1161 y : 365 * 24 * 60 * 60 

1162 }; 

1163 /// Cookie操作 

1164 jRaiser.cookie = { 

1165 /// 编码函数 

1166 encoder : window.encodeURIComponent, 

1167 /// 解码函数 

1168 decoder : window.decodeURIComponent, 

1169 /// 获取Cookie值 

1170 /// @param {String} Cookie名 

1171 /// @return {String} Cookie值 

1172 get : function(name) { 

1173 var t = jRaiser.cookie; 

1174 name = t.encoder(name) + "="; 

1175 var cookie = document.cookie, beginPos = cookie.indexOf(name), endPos; 

1176 if (-1 === beginPos) { 

1177 return undefined; 

1178 } 

1179 beginPos += name.length; endPos = cookie.indexOf(";", beginPos); 

1180 if (endPos === -1) { 

1181 endPos = cookie.length; 

1182 } 

1183 return t.decoder(cookie.substring(beginPos, endPos)); 

1184 }, 

1185 /// 写入Cookie值 

1186 /// @param {String} Cookie名 

1187 /// @param {Mixed} Cookie值 

1188 /// @param {Number,Date,String} 过期时间 

1189 /// @param {String} 域,默认为当前页 

1190 /// @param {String} 路径,默认为当前路径 

1191 /// @param {Boolean} 是否仅把Cookie发送给受保护的服务器连接(https),默认为否 

1192 set : function(name, value, expires, domain, path, secure) { 

1193 var t = jRaiser.cookie, cookieStr = [t.encoder(name) + "=" + t.encoder(value)]; 

1194 if (expires) { 

1195 var date, unit; 

1196 if ("[object Date]" === toString.call(expires)) { 

1197 date = expires; 

1198 } else { 

1199 if ("string" === typeof expires && EXPIRESWITHUNIT.test(expires)) { 

1200 expires = expires.substring(0, expires.length - 1); 

1201 unit = RegExp.lastMatch; 

1202 } 

1203 if (!isNaN(expires)) { 

1204 date = new Date(); 

1205 date.setTime(date.getTime() + expires * TIMEUNITS[unit || "m"] * 1000); 

1206 } 

1207 } 

1208 date && cookieStr.push("expires=" + date.toUTCString()); 

1209 } 

1210 path && cookieStr.push("path=" + path); 

1211 domain && cookieStr.push("domain=" + domain); 

1212 secure && cookieStr.push("secure"); 

1213 document.cookie = cookieStr.join(";"); 

1214 }, 

1215 /// 删除Cookie 

1216 /// @param {String} Cookie名 

1217 /// @param {String} 域 

1218 /// @param {String} 路径 

1219 del : function(name, domain, path) { 

1220 document.cookie = jRaiser.cookie.encoder(name) + "=" + (path ? ";path=" + path : "") + (domain ? ";domain=" + domain : "") + ";expires=Thu, 01-Jan-1970 00:00:01 GMT"; 

1221 } 

1222 }; 

1223 var whiteSpaces = /^\s+|\s+$/g; 

1224 /// 去掉当前字符串两端的某段字符串 

1225 /// @param {String} 要去掉的字符串,默认为空白 

1226 /// @return {String} 修整后的字符串 

1227 !String.prototype.trim && (String.prototype.trim = function() { return this.replace(whiteSpaces, ""); }); 

1228 /// 从左边开始截取一定长度的子字符串 

1229 /// @param {Number} 长度 

1230 /// @return {String} 子字符串 

1231 String.prototype.left = function(n) { return this.substr(0, n); }; 

1232 /// 从右边开始截取一定长度的子字符串 

1233 /// @param {Number} 长度 

1234 /// @return {String} 子字符串 

1235 String.prototype.right = function(n) { return this.slice(-n); }; 

1236 /// 格式化字符串 

1237 /// @param {String} 要格式化的字符串 

1238 /// @param {String} 参数 

1239 /// @return {String} 格式化后的字符串 

1240 String.format = function(str) { 

1241 var args = arguments, re = new RegExp("%([1-" + args.length + "])", "g"); 

1242 return String(str).replace(re, function($0, $1) { 

1243 return args[$1]; 

1244 }); 

1245 }; 

1246 /// 为函数绑定this和参数 

1247 /// @param {Mixed} 需绑定为this的对象 

1248 /// @param {Mixed} 参数 

1249 /// @return {Function} 绑定this和参数的函数 

1250 Function.prototype.bind = function() { 

1251 if (!arguments.length) { return this; } 

1252 var method = this, args = slice.call(arguments), object = args.shift(); 

1253 return function() { 

1254 return method.apply(object, args.concat(slice.call(arguments))); 

1255 }; 

1256 }; 

1257 /// 在当前数组中检索指定元素 

1258 /// @param {Mixed} 指定元素 

1259 /// @param {Number} 开始搜索的位置,默认为0 

1260 /// @return {Number} 指定元素在数组中第一个匹配项的索引;如果该元素不存在于数组中,返回-1 

1261 !Array.prototype.indexOf && (Array.prototype.indexOf = function(elt, from) { 

1262 var len = this.length, from = Number(from) || 0; 

1263 from = from < 0 ? Math.ceil(from) : Math.floor(from); 

1264 from < 0 && (from += len); 

1265 for (; from < len; from++) { 

1266 if (this[from] === elt)  { return from; } 

1267 } 

1268 return -1; 

1269 }); 

1270 /// 删除当前数组指定位置的元素 

1271 /// @param {Number} 指定位置 

1272 /// @return {Array} 当前数组 

1273 Array.prototype.remove = function(n) { 

1274 n >= 0 && this.splice(n, 1); 

1275 return this; 

1276 }; 

1277 // 把数字转换成两位数的字符串 

1278 function toTwoDigit(num) { return num < 10 ? "0" + num : num; } 

1279 // 临时记录正在转换的日期 

1280 var tempYear, tempMonth, tempDate, tempHour, tempMinute, tempSecond; 

1281 // 格式替换函数 

1282 function getDatePart(part) { 

1283 switch (part) { 

1284 case "yyyy": return tempYear; 

1285 case "yy": return tempYear.toString().slice(-2); 

1286 case "MM": return toTwoDigit(tempMonth); 

1287 case "M": return tempMonth; 

1288 case "dd": return toTwoDigit(tempDate); 

1289 case "d": return tempDate; 

1290 case "HH": return toTwoDigit(tempHour); 

1291 case "H": return tempHour; 

1292 case "hh": return toTwoDigit(tempHour > 12 ? tempHour - 12 : tempHour); 

1293 case "h": return tempHour > 12 ? tempHour - 12 : tempHour; 

1294 case "mm": return toTwoDigit(tempMinute); 

1295 case "m": return tempMinute; 

1296 case "ss": return toTwoDigit(tempSecond); 

1297 case "s": return tempSecond; 

1298 default: return part; 

1299 } 

1300 } 

1301 /// 返回当前日期的毫秒表示 

1302 /// @param {Number} 当前日期的毫秒表示 

1303 Date.now = Date.now || function() { return +new Date; } 

1304 /// 返回指定格式的日期字符串 

1305 /// @param {String} 格式 

1306 /// @return {String} 指定格式的日期字符串 

1307 Date.prototype.format = function(formation) { 

1308 tempYear = this.getFullYear(); 

1309 tempMonth = this.getMonth() + 1; 

1310 tempDate = this.getDate(); 

1311 tempHour = this.getHours(); 

1312 tempMinute = this.getMinutes(); 

1313 tempSecond = this.getSeconds(); 

1314 return formation.replace(/y+|m+|d+|h+|s+|H+|M+/g, getDatePart); 

1315 }; 

1316 // 回收资源 

1317 testElem = null; 

1318 })(window);
Filed under: JavaScript 源码分析 JavaScript框架 发表评论 js框架中类继承的比较
首先我们来看下jQuery之父john resig的实现方法:

jq之父写的类继承方式的特点是:

有私有变量
可以写在一个构造函数中
可以多级继承,可以有多个父类(需要某种特定格式)
继承基于prototype,且不会执行父类的构造函数
保持了父类的函数链,可以在子类中用this._super简单调用
instanceof 对子类、父类都生效
这是目前为止我看到的最好的方法。除了定义了一个全局变量Class外

view sourceprint?
01 // Inspired by base2 and Prototype 

02 (function(){ 

03 var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; 

04 // The base Class implementation (does nothing) 

05 this.Class = function(){}; 

06 // Create a new Class that inherits from this class 

07 Class.extend = function(prop) { 

08 var _super = this.prototype; 

09 // Instantiate a base class (but only create the instance, 

10 // don't run the init constructor) 

11 initializing = true; 

12 var prototype = new this(); 

13 initializing = false; 

14 // Copy the properties over onto the new prototype 

15 for (var name in prop) { 

16 // Check if we're overwriting an existing function 

17 prototype[name] = typeof prop[name] == "function" && 

18 typeof _super[name] == "function" && fnTest.test(prop[name]) ? 

19 (function(name, fn){ 

20 return function() { 

21 var tmp = this._super; 

22 // Add a new ._super() method that is the same method 

23 // but on the super-class 

24 this._super = _super[name]; 

25 // The method only need to be bound temporarily, so we 

26 // remove it when we're done executing 

27 var ret = fn.apply(this, arguments); 

28 this._super = tmp; 

29 return ret; 

30 }; 

31 })(name, prop[name]) : 

32 prop[name]; 

33 } 

34 // The dummy class constructor 

35 function Class() { 

36 // All construction is actually done in the init method 

37 if ( !initializing && this.init ) 

38 this.init.apply(this, arguments); 

39 } 

40 // Populate our constructed prototype object 

41 Class.prototype = prototype; 

42 // Enforce the constructor to be what we expect 

43 Class.constructor = Class; 

44 // And make this class extendable 

45 Class.extend = arguments.callee; 

46 return Class; 

47 }; 

48 })();
Filed under: JavaScript jQuery ExtJS JavaScript框架 YUI 发表评论 magento中的getBaseUrl函数
在magento中如果要获取js,media,skin目录,我们可以使用magento的

view sourceprint?
1 Mage::getBaseUrl()
这个函数..假设我们的网站根目录是:http://192.168.1.10/magento/

如果我要获取js目录

view sourceprint?
1 <?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_JS);//http://192.168.1.10/magento/js/ ?>
Filed under: Magento 发表评论 jQuery的unbind()函数详解
jQuery的绑定事件非常方便,有bind、unbind、live、one,还有它帮你把一些常用的事件给单独了出来,比如控件的onclick事件,我们绑定onclick事件的时候只需要

view sourceprint?
1 $("#testButton").click(function() { 

2 alert("I'm Test Button");
分享到:
评论

相关推荐

    理解Javascript的最好文章

    这篇文章"悟透JavaScript"很可能深入解析了JS的核心概念、语法特性和应用技巧,旨在帮助读者全面理解这门语言。 在JavaScript中,有几个关键的知识点是不容忽视的: 1. **基础语法**:包括变量(var, let, const)...

    【推荐】Web开发人员必备: JavaScript 精品文章50篇

    JavaScript作为Web开发必备的脚本语言,对于开发人员来说,它非常容易上手,并被数百万计的网页用来改进设计、验证表单、创建Cookies;但开发过程中经常会遇到一些莫名其妙的问题,使开发人员很头疼。本电子书汇集了...

    JavaScript_Demo,文章《JavaScript笔记》配套代码

    这篇文章《JavaScript笔记》的配套代码提供了丰富的实例,旨在帮助读者深入理解和掌握JavaScript的基本概念、语法以及应用技巧。 首先,我们来看看“JS笔记”部分。在学习JavaScript时,理解变量的声明、数据类型...

    JavaScript生成文章目录导航

    生成JavaScript文章目录导航主要涉及以下几个关键知识点: 1. **HTML结构**:首先,HTML文档中需要有合适的标题元素(`&lt;h1&gt;`到`&lt;h6&gt;`),这些元素将被JavaScript解析并用于构建目录。例如,一级标题使用`&lt;h1&gt;`,二...

    常用JS大全,Javascript技术文章

    JavaScript,简称JS,是一种广泛应用于Web开发的轻量级脚本语言,由 Netscape 的 Brendan Eich 在1995年发明。它被设计用来增强网页的交互性,使用户能够与网页进行动态交流,而无需刷新页面。随着前端开发的发展,...

    JavaScript语言教程&案例&相关项目资源

    随后,文章推荐了一系列优质的JavaScript教程资源,从基础知识到高级特性,从入门教程到专业书籍,应有尽有。这些教程不仅详细讲解了JavaScript的语法和核心概念,还提供了丰富的示例代码和实践项目,帮助你逐步掌握...

    关于JavaScript的好书推荐

    **《关于JavaScript的好书推荐》** 这篇文章向读者介绍了几本非常适合初学者入门的JavaScript书籍。首先提到的一本书,作者并未给出具体名称,但通过描述可以推测是一本非常适合初学者用来建立对JavaScript的兴趣并...

    javascript:文章滚动

    文章带滚动效果,可以控制速度,鼠标触发机制等功能

    2024高频前端面试题 JavaScript

    文章旨在帮助面试者更好地准备JavaScript相关的面试,提高对JavaScript的理解和应用能力。 【适用人群】 这篇文章主要面向准备JavaScript相关面试的面试者,特别是那些对JavaScript有深入理解并希望提高面试表现的...

    基于JavaScript语言的VS Code相关资源和技术文章汇总设计源码

    本项目为VS Code相关资源与技术文章的汇总设计源码,汇集了42个文件,其中包括30个PNG图片、4个Markdown文档、2个JSON文件、2个YAML文件、1个LICENSE文件、1个GIF动画、1个Sketch文件以及1个JavaScript文件。...

    JavaScript经典效果集锦

    根据给定的信息,“JavaScript经典效果集锦”这篇文章主要介绍了多种使用JavaScript实现的网页特效与功能。下面将对文章中提及的一些经典效果进行详细介绍。 ### 1. 实现小技巧 文章开头提到了几个简单的...

    基于PHP和Javascript的WordPress文章图片本地化插件设计源码

    本项目是基于PHP和Javascript开发的WordPress文章图片本地化插件,包含29个文件,其中包括16个PHP源代码文件、7个JavaScript脚本文件、1个LICENSE文件、1个Markdown文档文件、1个CSS样式表文件、1个SCSS样式表文件、...

    Javascript语言参考大全

    本篇文章将深入探讨JavaScript语言的核心概念、语法以及JScript教程,同时还会提及fileSystemObject对象的相关知识。 首先,JavaScript语法是理解编程的基础。它采用C语言风格,包含变量声明、数据类型(如字符串、...

    javascript连接Oracle实例

    在文章中,我们可以看到作者使用JavaScript语言编写了一个连接Oracle实例的示例代码。这个示例代码使用了ADODB.Connection对象来连接Oracle实例,并执行了一条SELECT语句来查询数据库中的数据。 标签解释 ...

    jQuery文章底部弹出相关文章列表插件

    **jQuery文章底部弹出相关文章列表插件** 在网页设计中,提高用户浏览体验和页面交互性是非常重要的。本文将详细介绍一款基于jQuery和jQuery UI构建的文章底部弹出相关文章列表插件,它能够智能地在用户滚动到文章...

    JavaScript_阅读mediumcom和基于媒体的文章使用谷歌网页缓存.zip

    2. 保存离线阅读:使用浏览器的存储API(如localStorage或IndexedDB),JavaScript可以将文章内容保存在本地,方便用户在无网络连接时阅读。 3. 自定义样式:JavaScript可以改变文章的样式,如字体、背景色等,满足...

    jQuery和css3侧边栏滑动显示相关文章插件

    在网页设计中,提供相关的文章推荐可以增强用户体验,帮助用户发现更多感兴趣的内容。这款jQuery和CSS3结合的侧边栏滑动显示相关文章插件就是为此目的而设计的。它通过动态效果将文章的相关内容以侧边栏的形式展示,...

    javascript经典特效---多篇文章的处理.rar

    本压缩包"javascript经典特效---多篇文章的处理.rar"显然聚焦于如何利用JavaScript技术来处理和展示多篇文章,可能包括文章的加载、排序、搜索、分页等功能。 在JavaScript中,处理多篇文章的数据结构通常会选择...

    JavaScript实战.pdf

    - **定义与功能**:弹出式帮助是一种在用户需要时显示相关信息的功能,常用于提供额外的帮助或解释。 - **技术实现**: - 使用HTML的`&lt;div&gt;`元素结合CSS定位属性实现布局。 - JavaScript控制弹出窗口的显示与隐藏...

Global site tag (gtag.js) - Google Analytics