标签:组件 递归 嵌套 阶段 handler 原理 水平 toc 无损压缩
参考资料:MDN: html global attribute或者W3C HTML global-attributes
web语义化是指通过HTML标记表示页面包含的信息,包含了HTML标签的语义化和css命名的语义化。
HTML标签的语义化是指:通过使用包含语义的标签(如h1-h6)恰当地表示文档结构
css命名的语义化是指:为html标签添加有意义的class,id补充未表达的语义,如Microformat通过添加符合规则的class描述信息
为什么需要语义化:
rfc2616中进行了定义:
一个请求报文例子如下:
1 GET /Protocols/rfc2616/rfc2616-sec5.html HTTP/1.1 2 Host: www.w3.org 3 Connection: keep-alive 4 Cache-Control: max-age=0 5 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 6 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36 7 Referer: https://www.google.com.hk/ 8 Accept-Encoding: gzip,deflate,sdch 9 Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 10 Cookie: authorstyle=yes 11 If-None-Match: "2cc8-3e3073913b100" 12 If-Modified-Since: Wed, 01 Sep 2004 13:24:52 GMT 13 14 name=qiu&age=25
rfc2616中进行了定义:
响应报文例子如下:
1 HTTP/1.1 200 OK 2 Date: Tue, 08 Jul 2014 05:28:43 GMT 3 Server: Apache/2 4 Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT 5 ETag: "40d7-3e3073913b100" 6 Accept-Ranges: bytes 7 Content-Length: 16599 8 Cache-Control: max-age=21600 9 Expires: Tue, 08 Jul 2014 11:28:43 GMT 10 P3P: policyref="http://www.w3.org/2001/05/P3P/p3p.xml" 11 Content-Type: text/html; charset=iso-8859-1 12 {"name": "qiu", "age": 25}
雅虎Best Practices for Speeding Up Your Web Site:
渐进增强是指在web设计时强调可访问性、语义化HTML标签、外部样式表和脚本。保证所有人都能访问页面的基本内容和功能同时为高级浏览器和高带宽用户提供更好的用户体验。核心原则如下:
参考RFC 2616
概念:将多个小图片拼接到一个图片中。通过background-position和元素尺寸调节需要显示的背景图案。
优点:
缺点:
联系:它们都能让元素不可见
区别:
原理:利用不同浏览器对CSS的支持和解析结果不一样编写针对特定浏览器样式。常见的hack有1)属性hack。2)选择器hack。3)IE条件注释
1 <!--[if IE 6]> 2 Special instructions for IE 6 here 3 <![endif]-->
1 /***** Selector Hacks ******/ 2 3 /* IE6 and below */ 4 * html #uno { color: red } 5 6 /* IE7 */ 7 *:first-child+html #dos { color: red } 8 9 /* IE7, FF, Saf, Opera */ 10 html>body #tres { color: red } 11 12 /* IE8, FF, Saf, Opera (Everything but IE 6,7) */ 13 html>/**/body #cuatro { color: red } 14 15 /* Opera 9.27 and below, safari 2 */ 16 html:first-child #cinco { color: red } 17 18 /* Safari 2-3 */ 19 html[xmlns*=""] body:last-child #seis { color: red } 20 21 /* safari 3+, chrome 1+, opera9+, ff 3.5+ */ 22 body:nth-of-type(1) #siete { color: red } 23 24 /* safari 3+, chrome 1+, opera9+, ff 3.5+ */ 25 body:first-of-type #ocho { color: red } 26 27 /* saf3+, chrome1+ */ 28 @media screen and (-webkit-min-device-pixel-ratio:0) { 29 #diez { color: red } 30 } 31 32 /* iPhone / mobile webkit */ 33 @media screen and (max-device-width: 480px) { 34 #veintiseis { color: red } 35 } 36 37 /* Safari 2 - 3.1 */ 38 html[xmlns*=""]:root #trece { color: red } 39 40 /* Safari 2 - 3.1, Opera 9.25 */ 41 *|html[xmlns*=""] #catorce { color: red } 42 43 /* Everything but IE6-8 */ 44 :root *> #quince { color: red } 45 46 /* IE7 */ 47 *+html #dieciocho { color: red } 48 49 /* Firefox only. 1+ */ 50 #veinticuatro, x:-moz-any-link { color: red } 51 52 /* Firefox 3.0+ */ 53 #veinticinco, x:-moz-any-link, x:default { color: red } 54
1 /* IE6 */ 2 #once { _color: blue } 3 4 /* IE6, IE7 */ 5 #doce { *color: blue; /* or #color: blue */ } 6 7 /* Everything but IE6 */ 8 #diecisiete { color/**/: blue } 9 10 /* IE6, IE7, IE8 */ 11 #diecinueve { color: blue\9; } 12 13 /* IE7, IE8 */ 14 #veinte { color/*\**/: blue\9; } 15 16 /* IE6, IE7 -- acts as an !important */ 17 #veintesiete { color: blue !ie; } /* string after ! can be anything */
block元素特点:
inline元素特点
参考资料: 选择正确的图片格式
GIF:
JPEG:
PNG:
1 .target { 2 min-height: 100px; 3 height: auto !important; 4 height: 100px; // IE6下内容高度超过会自动扩展高度 5 }
1 <style type="text/css"> 2 .outer { 3 width: 215px; 4 height: 100px; 5 border: 1px solid red; 6 overflow: auto; 7 position: relative; /* 修复bug */ 8 } 9 .inner { 10 width: 100px; 11 height: 200px; 12 background-color: purple; 13 position: relative; 14 } 15 </style> 16 17 <div class="outer"> 18 <div class="inner"></div> 19 </div>
1 <style type="text/css"> 2 .p:hover, 3 .hover { 4 background: purple; 5 } 6 </style> 7 <p class="p" id="target">aaaa bbbbb<span>DDDDDDDDDDDd</span> aaaa lkjlkjdf j</p> 8 <script type="text/javascript"> 9 function addClass(elem, cls) { 10 if(elem.className) { 11 elem.className += ‘ ‘ + cls; 12 } else { 13 elem.className = cls; 14 } 15 } 16 17 function removeClass(elem, cls) { 18 var className = ‘ ‘ + elem.className + ‘ ‘; 19 var reg = new RegExp(‘ +‘ + cls + ‘ +‘, ‘g‘); 20 elem.className = className.replace(reg, ‘ ‘).replace(/^ +| +$/, ‘‘); 21 } 22 var target = document.getElementById(‘target‘); 23 if(target.attachEvent) { 24 target.attachEvent(‘onmouseenter‘, function() { 25 addClass(target, ‘hover‘); 26 }); 27 target.attachEvent(‘onmouseleave‘, function() { 28 removeClass(target, ‘hover‘); 29 }) 30 } 31 </script>
1 .opacity { 2 opacity: 0.4 3 filter: alpha(opacity=60); /* for IE5-7 */ 4 -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; /* for IE 8*/ 5 }
display: inline-block;
*display: inline;
*zoom: 1;
1 /** 2 * 在标准浏览器下使用 3 * 1 content内容为空格用于修复opera下文档中出现 4 * contenteditable属性时在清理浮动元素上下的空白 5 * 2 使用display使用table而不是block:可以防止容器和 6 * 子元素top-margin折叠,这样能使清理效果与BFC,IE6/7 7 * zoom: 1;一致 8 **/ 9 10 .clearfix:before, 11 .clearfix:after { 12 content: " "; /* 1 */ 13 display: table; /* 2 */ 14 } 15 16 .clearfix:after { 17 clear: both; 18 } 19 20 /** 21 * IE 6/7下使用 22 * 通过触发hasLayout实现包含浮动 23 **/ 24 .clearfix { 25 *zoom: 1; 26 }
Flash Of Unstyled Content:用户定义样式表加载之前浏览器使用默认样式显示文档,用户样式加载渲染之后再从新显示文档,造成页面闪烁。解决方法:把样式表放到文档的head
创建规则:
作用:
结起来:绝对定位、浮动、根元素都需要调整display
毗邻的两个或多个margin会合并成一个margin,叫做外边距折叠。规则如下:
z轴上的默认层叠顺序如下(从下到上):
如何创建stacking context:
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 text-align: center; /* 3 */ 11 } 12 .content { 13 width: 500px; /* 1 */ 14 text-align: left; /* 3 */ 15 margin: 0 auto; /* 2 */ 16 17 background: purple; 18 } 19 </style>
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 } 11 .content { 12 width: 500px; /* 1 */ 13 float: left; 14 15 position: relative; /* 2 */ 16 left: 50%; /* 3 */ 17 margin-left: -250px; /* 4 */ 18 19 background-color: purple; 20 } 21 </style>
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 position: relative; 11 } 12 .content { 13 width: 800px; 14 15 position: absolute; 16 left: 50%; 17 margin-left: -400px; 18 19 background-color: purple; 20 } 21 </style>
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 position: relative; 11 } 12 .content { 13 width: 800px; 14 15 position: absolute; 16 margin: 0 auto; 17 left: 0; 18 right: 0; 19 20 background-color: purple; 21 } 22 </style>
参考资料:6 Methods For Vertical Centering With CSS。 盘点8种CSS实现垂直居中
1 <p class="text">center text</p> 2 3 <style> 4 .text { 5 line-height: 200px; 6 } 7 </style>
Measuring Element Dimension and Location with CSSOM in Windows Internet Explorer 9
例子:鼠标从div#target元素移出时进行处理,判断逻辑如下:
1 <div id="target"><span>test</span></div> 2 3 <script type="text/javascript"> 4 var target = document.getElementById(‘target‘); 5 if (target.addEventListener) { 6 target.addEventListener(‘mouseout‘, mouseoutHandler, false); 7 } else if (target.attachEvent) { 8 target.attachEvent(‘onmouseout‘, mouseoutHandler); 9 } 10 11 function mouseoutHandler(e) { 12 e = e || window.event; 13 var target = e.target || e.srcElement; 14 15 // 判断移出鼠标的元素是否为目标元素 16 if (target.id !== ‘target‘) { 17 return; 18 } 19 20 // 判断鼠标是移出元素还是移到子元素 21 var relatedTarget = event.relatedTarget || e.toElement; 22 while (relatedTarget !== target 23 && relatedTarget.nodeName.toUpperCase() !== ‘BODY‘) { 24 relatedTarget = relatedTarget.parentNode; 25 } 26 27 // 如果相等,说明鼠标在元素内部移动 28 if (relatedTarget === target) { 29 return; 30 } 31 32 // 执行需要操作 33 //alert(‘鼠标移出‘); 34 35 } 36 </script>
同源:两个文档同源需满足
跨域通信:js进行DOM操作、通信时如果目标与当前窗口不满足同源条件,浏览器为了安全会阻止跨域操作。跨域通信通常有以下方法
六种基本数据类型
一种引用类型
闭包是在某个作用域内定义的函数,它可以访问这个作用域内的所有变量。闭包作用域链通常包括三个部分:
闭包常见用途:
重要参考资料:MDN:Functions_and_function_scope
HTML5新增应用程序缓存,允许web应用将应用程序自身保存到用户浏览器中,用户离线状态也能访问。
CACHE MANIFEST
CACHE:
myapp.html
myapp.css
myapp.js
FALLBACK:
videos/ offline_help.html
NETWORK:
cgi/
1 localStorage.setItem(‘x‘, 1); // storge x->1 2 localStorage.getItem(‘x); // return value of x 3 4 // 枚举所有存储的键值对 5 for (var i = 0, len = localStorage.length; i < len; ++i ) { 6 var name = localStorage.key(i); 7 var value = localStorage.getItem(name); 8 } 9 10 localStorage.removeItem(‘x‘); // remove x 11 localStorage.clear(); // remove all data
1 document.cookie = ‘name=qiu; max-age=9999; path=/; domain=domain; secure‘; 2 3 document.cookie = ‘name=aaa; path=/; domain=domain; secure‘; 4 // 要改变cookie的值,需要使用相同的名字、路径和域,新的值 5 // 来设置cookie,同样的方法可以用来改变有效期 6 7 // 设置max-age为0可以删除指定cookie 8 9 //读取cookie,访问document.cookie返回键值对组成的字符串, 10 //不同键值对之间用‘; ‘分隔。通过解析获得需要的值
cookieUtil.js:自己写的cookie操作工具
1. 如果对象有valueOf()方法并且返回元素值,javascript将返回值转换为数字作为结果 2. 否则,如果对象有toString()并且返回原始值,javascript将返回结果转换为数字作为结果 3. 否则,throws a TypeError
所有比较运算符都支持任意类型,但是比较只支持数字和字符串,所以需要执行必要的转换然后进行比较,转换规则如下:
1. 如果操作数是对象,转换为原始值:如果valueOf方法返回原始值,则使用这个值,否则使用toString方法的结果,如果转换失败则报错
2. 经过必要的对象到原始值的转换后,如果两个操作数都是字符串,按照字母顺序进行比较(他们的16位unicode值的大小)
3. 否则,如果有一个操作数不是字符串,将两个操作数转换为数字进行比较
1 /** 2 * 跨浏览器事件处理工具。只支持冒泡。不支持捕获 3 * @author (qiu_deqing@126.com) 4 */ 5 6 var EventUtil = { 7 getEvent: function (event) { 8 return event || window.event; 9 }, 10 getTarget: function (event) { 11 return event.target || event.srcElement; 12 }, 13 // 返回注册成功的监听器,IE中需要使用返回值来移除监听器 14 on: function (elem, type, handler) { 15 if (elem.addEventListener) { 16 elem.addEventListener(type, handler, false); 17 return handler; 18 } else if (elem.attachEvent) { 19 var wrapper = function () { 20 var event = window.event; 21 event.target = event.srcElement; 22 handler.call(elem, event); 23 }; 24 elem.attachEvent(‘on‘ + type, wrapper); 25 return wrapper; 26 } 27 }, 28 off: function (elem, type, handler) { 29 if (elem.removeEventListener) { 30 elem.removeEventListener(type, handler, false); 31 } else if (elem.detachEvent) { 32 elem.detachEvent(‘on‘ + type, handler); 33 } 34 }, 35 preventDefault: function (event) { 36 if (event.preventDefault) { 37 event.preventDefault(); 38 } else if (‘returnValue‘ in event) { 39 event.returnValue = false; 40 } 41 }, 42 stopPropagation: function (event) { 43 if (event.stopPropagation) { 44 event.stopPropagation(); 45 } else if (‘cancelBubble‘ in event) { 46 event.cancelBubble = true; 47 } 48 }, 49 /** 50 * keypress事件跨浏览器获取输入字符 51 * 某些浏览器在一些特殊键上也触发keypress,此时返回null 52 **/ 53 getChar: function (event) { 54 if (event.which == null) { 55 return String.fromCharCode(event.keyCode); // IE 56 } 57 else if (event.which != 0 && event.charCode != 0) { 58 return String.fromCharCode(event.which); // the rest 59 } 60 else { 61 return null; // special key 62 } 63 } 64 };
1 function Shape() {} 2 3 function Rect() {} 4 5 // 方法1 6 Rect.prototype = new Shape(); 7 8 // 方法2 9 Rect.prototype = Shape.prototype; 10 11 // 方法3 12 Rect.prototype = Object.create(Shape.prototype); 13 14 Rect.prototype.area = function () { 15 // do something 16 };
方法1:
方法2:
方法3:
改进:
1 function Rect() { 2 Shape.call(this); 3 }
1 function create(obj) { 2 if (Object.create) { 3 return Object.create(obj); 4 } 5 6 function f() {}; 7 f.prototype = obj; 8 return new f(); 9 }
1 <style> 2 #target { 3 width: 200px; 4 height: 300px; 5 margin: 40px; 6 background-color: tomato; 7 } 8 </style> 9 10 <div id="target"></div> 11 12 <script> 13 function addMask(elem, opacity) { 14 opacity = opacity || 0.2; 15 16 var rect = elem.getBoundingClientRect(); 17 var style = getComputedStyle(elem, null); 18 19 var mask = document.createElement(‘div‘); 20 mask.style.position = ‘absolute‘; 21 var marginLeft = parseFloat(style.marginLeft); 22 mask.style.left = (elem.offsetLeft - marginLeft) + ‘px‘; 23 var marginTop = parseFloat(style.marginTop); 24 mask.style.top = (elem.offsetTop - marginTop) + ‘px‘; 25 mask.style.zIndex = 9999; 26 mask.style.opacity = ‘‘ + opacity; 27 mask.style.backgroundColor = ‘#000‘; 28 29 mask.style.width = (parseFloat(style.marginLeft) + 30 parseFloat(style.marginRight) + rect.width) + ‘px‘; 31 mask.style.height = (parseFloat(style.marginTop) + 32 parseFloat(style.marginBottom) + rect.height) + ‘px‘; 33 34 elem.parentNode.appendChild(mask); 35 } 36 37 var target = document.getElementById(‘target‘); 38 addMask(target); 39 40 target.addEventListener(‘click‘, function () { 41 console.log(‘click‘); 42 }, false); 43 </script>
1 var days = [‘日‘,‘一‘,‘二‘,‘三‘,‘四‘,‘五‘,‘六‘]; 2 var date = new Date(); 3 4 console.log(‘今天是星期‘ + days[date.getDay()]);
1 for (var i = 0; i < 5; ++i) { 2 setTimeout(function () { 3 console.log(i + ‘ ‘); 4 }, 100); 5 }
不能输出正确结果,因为循环中setTimeout接受的参数函数通过闭包访问变量i。javascript运行环境为单线程,setTimeout注册的函数需要等待线程空闲才能执行,此时for循环已经结束,i值为5.五个定时输出都是5
修改方法:将setTimeout放在函数立即调用表达式中,将i值作为参数传递给包裹函数,创建新闭包
1 for (var i = 0; i < 5; ++i) { 2 (function (i) { 3 setTimeout(function () { 4 console.log(i + ‘ ‘); 5 }, 100); 6 }(i)); 7 }
1 function Page() {} 2 3 Page.prototype = { 4 constructor: Page, 5 6 postA: function (a) { 7 console.log(‘a:‘ + a); 8 }, 9 postB: function (b) { 10 console.log(‘b:‘ + b); 11 }, 12 postC: function (c) { 13 console.log(‘c:‘ + c); 14 }, 15 check: function () { 16 return Math.random() > 0.5; 17 } 18 } 19 20 function checkfy(obj) { 21 for (var key in obj) { 22 if (key.indexOf(‘post‘) === 0 && typeof obj[key] === ‘function‘) { 23 (function (key) { 24 var fn = obj[key]; 25 obj[key] = function () { 26 if (obj.check()) { 27 fn.apply(obj, arguments); 28 } 29 }; 30 }(key)); 31 } 32 } 33 } // end checkfy() 34 35 checkfy(Page.prototype); 36 37 var obj = new Page(); 38 39 obj.postA(‘checkfy‘); 40 obj.postB(‘checkfy‘); 41 obj.postC(‘checkfy‘); 42
1 function deepClone(obj) { 2 var _toString = Object.prototype.toString; 3 4 // null, undefined, non-object, function 5 if (!obj || typeof obj !== ‘object‘) { 6 return obj; 7 } 8 9 // DOM Node 10 if (obj.nodeType && ‘cloneNode‘ in obj) { 11 return obj.cloneNode(true); 12 } 13 14 // Date 15 if (_toString.call(obj) === ‘[object Date]‘) { 16 return new Date(obj.getTime()); 17 } 18 19 // RegExp 20 if (_toString.call(obj) === ‘[object RegExp]‘) { 21 var flags = []; 22 if (obj.global) { flags.push(‘g‘); } 23 if (obj.multiline) { flags.push(‘m‘); } 24 if (obj.ignoreCase) { flags.push(‘i‘); } 25 26 return new RegExp(obj.source, flags.join(‘‘)); 27 } 28 29 var result = Array.isArray(obj) ? [] : 30 obj.constructor ? new obj.constructor() : {}; 31 32 for (var key in obj ) { 33 result[key] = deepClone(obj[key]); 34 } 35 36 return result; 37 } 38 39 function A() { 40 this.a = a; 41 } 42 43 var a = { 44 name: ‘qiu‘, 45 birth: new Date(), 46 pattern: /qiu/gim, 47 container: document.body, 48 hobbys: [‘book‘, new Date(), /aaa/gim, 111] 49 }; 50 51 var c = new A(); 52 var b = deepClone(c); 53 console.log(c.a === b.a); 54 console.log(c, b);
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>TEst</title> 6 </head> 7 <body> 8 9 <div> 10 <input type="button" id ="button1" value="1" /> 11 <input type="button" id ="button2" value="2" /> 12 </div> 13 14 <script type="text/javascript"> 15 var btn1 = document.getElementById(‘button1‘); 16 var btn2 = document.getElementById(‘button2‘); 17 18 addListener(btn1, ‘click‘, function (event) { 19 btn1.parentNode.insertBefore(btn2, btn1); 20 }); 21 22 function addListener(elem, type, handler) { 23 if (elem.addEventListener) { 24 elem.addEventListener(type, handler, false); 25 return handler; 26 } else if (elem.attachEvent) { 27 function wrapper() { 28 var event = window.event; 29 event.target = event.srcElement; 30 handler.call(elem, event); 31 } 32 elem.attachEvent(‘on‘ + type, wrapper); 33 return wrapper; 34 } 35 } 36 37 </script> 38 </body> 39 </html> 40
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>TEst</title> 6 </head> 7 <body> 8 9 <span id="target"></span> 10 11 12 <script type="text/javascript"> 13 // 为了简化。每月默认30天 14 function getTimeString() { 15 var start = new Date(); 16 var end = new Date(start.getFullYear() + 1, 0, 1); 17 var elapse = Math.floor((end - start) / 1000); 18 19 var seconds = elapse % 60 ; 20 var minutes = Math.floor(elapse / 60) % 60; 21 var hours = Math.floor(elapse / (60 * 60)) % 24; 22 var days = Math.floor(elapse / (60 * 60 * 24)) % 30; 23 var months = Math.floor(elapse / (60 * 60 * 24 * 30)) % 12; 24 var years = Math.floor(elapse / (60 * 60 * 24 * 30 * 12)); 25 26 return start.getFullYear() + ‘年还剩‘ + years + ‘年‘ + months + ‘月‘ + days + ‘日‘ 27 + hours + ‘小时‘ + minutes + ‘分‘ + seconds + ‘秒‘; 28 } 29 30 function domText(elem, text) { 31 if (text == undefined) { 32 33 if (elem.textContent) { 34 return elem.textContent; 35 } else if (elem.innerText) { 36 return elem.innerText; 37 } 38 } else { 39 if (elem.textContent) { 40 elem.textContent = text; 41 } else if (elem.innerText) { 42 elem.innerText = text; 43 } else { 44 elem.innerHTML = text; 45 } 46 } 47 } 48 49 var target = document.getElementById(‘target‘); 50 51 setInterval(function () { 52 domText(target, getTimeString()); 53 }, 1000) 54 </script> 55 56 </body> 57 </html>
如:[1, [2, [ [3, 4], 5], 6]] => [1, 2, 3, 4, 5, 6]
1 var data = [1, [2, [ [3, 4], 5], 6]]; 2 3 function flat(data, result) { 4 var i, d, len; 5 for (i = 0, len = data.length; i < len; ++i) { 6 d = data[i]; 7 if (typeof d === ‘number‘) { 8 result.push(d); 9 } else { 10 flat(d, result); 11 } 12 } 13 } 14 15 var result = []; 16 flat(data, result); 17 18 console.log(result);
如果浏览器支持Array.isArray()可以直接判断否则需进行必要判断
1 /** 2 * 判断一个对象是否是数组,参数不是对象或者不是数组,返回false 3 * 4 * @param {Object} arg 需要测试是否为数组的对象 5 * @return {Boolean} 传入参数是数组返回true,否则返回false 6 */ 7 function isArray(arg) { 8 if (typeof arg === ‘object‘) { 9 return Object.prototype.toString.call(arg) === ‘[object Array]‘; 10 } 11 return false; 12 }
1 if (window.addEventListener) { 2 var addListener = function (el, type, listener, useCapture) { 3 el.addEventListener(type, listener, useCapture); 4 }; 5 } 6 else if (document.all) { 7 addListener = function (el, type, listener) { 8 el.attachEvent(‘on‘ + type, function () { 9 listener.apply(el); 10 }); 11 }; 12 } 13
作用:浏览器功能检测实现跨浏览器DOM事件绑定
优点:
缺点:
改进:
1 var addListener; 2 3 if (window.addEventListener) { 4 addListener = function (el, type, listener, useCapture) { 5 el.addEventListener(type, listener, useCapture); 6 return listener; 7 }; 8 } 9 else if (window.attachEvent) { 10 addListener = function (el, type, listener) { 11 // 标准化this,event,target 12 var wrapper = function () { 13 var event = window.event; 14 event.target = event.srcElement; 15 listener.call(el, event); 16 }; 17 18 el.attachEvent(‘on‘ + type, wrapper); 19 return wrapper; 20 // 返回wrapper。调用者可以保存,以后remove 21 }; 22 }
1 /** 2 * 判断对象是否为函数,如果当前运行环境对可调用对象(如正则表达式) 3 * 的typeof返回‘function‘,采用通用方法,否则采用优化方法 4 * 5 * @param {Any} arg 需要检测是否为函数的对象 6 * @return {boolean} 如果参数是函数,返回true,否则false 7 */ 8 function isFunction(arg) { 9 if (arg) { 10 if (typeof (/./) !== ‘function‘) { 11 return typeof arg === ‘function‘; 12 } else { 13 return Object.prototype.toString.call(arg) === ‘[object Function]‘; 14 } 15 } // end if 16 return false; 17 }
1 /** 2 * 解析query string转换为对象,一个key有多个值时生成数组 3 * 4 * @param {String} query 需要解析的query字符串,开头可以是?, 5 * 按照application/x-www-form-urlencoded编码 6 * @return {Object} 参数解析后的对象 7 */ 8 function parseQuery(query) { 9 var result = {}; 10 11 // 如果不是字符串返回空对象 12 if (typeof query !== ‘string‘) { 13 return result; 14 } 15 16 // 去掉字符串开头可能带的? 17 if (query.charAt(0) === ‘?‘) { 18 query = query.substring(1); 19 } 20 21 var pairs = query.split(‘&‘); 22 var pair; 23 var key, value; 24 var i, len; 25 26 for (i = 0, len = pairs.length; i < len; ++i) { 27 pair = pairs[i].split(‘=‘); 28 // application/x-www-form-urlencoded编码会将‘ ‘转换为+ 29 key = decodeURIComponent(pair[0]).replace(/\+/g, ‘ ‘); 30 value = decodeURIComponent(pair[1]).replace(/\+/g, ‘ ‘); 31 32 // 如果是新key,直接添加 33 if (!(key in result)) { 34 result[key] = value; 35 } 36 // 如果key已经出现一次以上,直接向数组添加value 37 else if (isArray(result[key])) { 38 result[key].push(value); 39 } 40 // key第二次出现,将结果改为数组 41 else { 42 var arr = [result[key]]; 43 arr.push(value); 44 result[key] = arr; 45 } // end if-else 46 } // end for 47 48 return result; 49 } 50 51 function isArray(arg) { 52 if (arg && typeof arg === ‘object‘) { 53 return Object.prototype.toString.call(arg) === ‘[object Array]‘; 54 } 55 return false; 56 } 57 /** 58 console.log(parseQuery(‘sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8‘)); 59 */
1 /** 2 * 解析一个url并生成window.location对象中包含的域 3 * location: 4 * { 5 * href: ‘包含完整的url‘, 6 * origin: ‘包含协议到pathname之前的内容‘, 7 * protocol: ‘url使用的协议,包含末尾的:‘, 8 * username: ‘用户名‘, // 暂时不支持 9 * password: ‘密码‘, // 暂时不支持 10 * host: ‘完整主机名,包含:和端口‘, 11 * hostname: ‘主机名,不包含端口‘ 12 * port: ‘端口号‘, 13 * pathname: ‘服务器上访问资源的路径/开头‘, 14 * search: ‘query string,?开头‘, 15 * hash: ‘#开头的fragment identifier‘ 16 * } 17 * 18 * @param {string} url 需要解析的url 19 * @return {Object} 包含url信息的对象 20 */ 21 function parseUrl(url) { 22 var result = {}; 23 var keys = [‘href‘, ‘origin‘, ‘protocol‘, ‘host‘, 24 ‘hostname‘, ‘port‘, ‘pathname‘, ‘search‘, ‘hash‘]; 25 var i, len; 26 var regexp = /(([^:]+:)\/\/(([^:\/\?#]+)(:\d+)?))(\/[^?#]*)?(\?[^#]*)?(#.*)?/; 27 28 var match = regexp.exec(url); 29 30 if (match) { 31 for (i = keys.length - 1; i >= 0; --i) { 32 result[keys[i]] = match[i] ? match[i] : ‘‘; 33 } 34 } 35 36 return result; 37 } 38
1 /** 2 * 查询指定窗口的视口尺寸,如果不指定窗口,查询当前窗口尺寸 3 **/ 4 function getViewportSize(w) { 5 w = w || window; 6 7 // IE9及标准浏览器中可使用此标准方法 8 if (‘innerHeight‘ in w) { 9 return { 10 width: w.innerWidth, 11 height: w.innerHeight 12 }; 13 } 14 15 var d = w.document; 16 // IE 8及以下浏览器在标准模式下 17 if (document.compatMode === ‘CSS1Compat‘) { 18 return { 19 width: d.documentElement.clientWidth, 20 height: d.documentElement.clientHeight 21 }; 22 } 23 24 // IE8及以下浏览器在怪癖模式下 25 return { 26 width: d.body.clientWidth, 27 height: d.body.clientHeight 28 }; 29 }
1 /** 2 * 获取指定window中滚动条的偏移量,如未指定则获取当前window 3 * 滚动条偏移量 4 * 5 * @param {window} w 需要获取滚动条偏移量的窗口 6 * @return {Object} obj.x为水平滚动条偏移量,obj.y为竖直滚动条偏移量 7 */ 8 function getScrollOffset(w) { 9 w = w || window; 10 // 如果是标准浏览器 11 if (w.pageXOffset != null) { 12 return { 13 x: w.pageXOffset, 14 y: w.pageYOffset 15 }; 16 } 17 18 // 老版本IE,根据兼容性不同访问不同元素 19 var d = w.document; 20 if (d.compatMode === ‘CSS1Compat‘) { 21 return { 22 x: d.documentElement.scrollLeft, 23 y: d.documentElement.scrollTop 24 } 25 } 26 27 return { 28 x: d.body.scrollLeft, 29 y: d.body.scrollTop 30 }; 31 } 32
1 function richText(text) { 2 var div = document.createElement(‘div‘); 3 div.innerHTML = text; 4 var p = div.getElementsByTagName(‘p‘); 5 var i, len; 6 7 for (i = 0, len = p.length; i < len; ++i) { 8 if (p[i].getElementsByTagName(‘img‘).length === 1) { 9 p[i].classList.add(‘pic‘); 10 } 11 } 12 13 return div.innerHTML; 14 } 15
1 function Event() { 2 if (!(this instanceof Event)) { 3 return new Event(); 4 } 5 this._callbacks = {}; 6 } 7 Event.prototype.on = function (type, handler) { 8 this_callbacks = this._callbacks || {}; 9 this._callbacks[type] = this.callbacks[type] || []; 10 this._callbacks[type].push(handler); 11 12 return this; 13 }; 14 15 Event.prototype.off = function (type, handler) { 16 var list = this._callbacks[type]; 17 18 if (list) { 19 for (var i = list.length; i >= 0; --i) { 20 if (list[i] === handler) { 21 list.splice(i, 1); 22 } 23 } 24 } 25 26 return this; 27 }; 28 29 Event.prototype.trigger = function (type, data) { 30 var list = this._callbacks[type]; 31 32 if (list) { 33 for (var i = 0, len = list.length; i < len; ++i) { 34 list[i].call(this, data); 35 } 36 } 37 }; 38 39 Event.prototype.once = function (type, handler) { 40 var self = this; 41 42 function wrapper() { 43 handler.apply(self, arguments); 44 self.off(type, wrapper); 45 } 46 this.on(type, wrapper); 47 return this; 48 }; 49
1 <ul id="target"> 2 <li>1</li> 3 <li>2</li> 4 <li>3</li> 5 <li>4</li> 6 </ul> 7 8 <script> 9 var target = document.getElementById(‘target‘); 10 var i; 11 var frag = document.createDocumentFragment(); 12 13 for (i = target.children.length - 1; i >= 0; --i) { 14 frag.appendChild(target.children[i]); 15 } 16 target.appendChild(frag); 17 </script>
1 // define 2 (function (window) { 3 function fn(str) { 4 this.str = str; 5 } 6 7 fn.prototype.format = function () { 8 var arg = __1__; 9 return this.str.replace(__2__, function (a, b) { 10 return arg[b] || ‘‘; 11 }); 12 }; 13 14 window.fn = fn; 15 })(window); 16 17 // use 18 (function () { 19 var t = new fn(‘<p><a href="{0}">{1}</a><span>{2}</span></p>‘); 20 console.log(t.format(‘http://www.alibaba.com‘, ‘Alibaba‘, ‘Welcome‘)); 21 })(); 22
define部分定义一个简单的模板类,使用{}作为转义标记,中间的数字表示替换目标,format实参用来替换模板内标记
横线处填:
1 <form id="target"> 2 <select name="age"> 3 <option value="aaa">aaa</option> 4 <option value="bbb" selected>bbb</option> 5 </select> 6 <select name="friends" multiple> 7 <option value="qiu" selected>qiu</option> 8 <option value="de">de</option> 9 <option value="qing" selected>qing</option> 10 </select> 11 <input name="name" value="qiudeqing"> 12 <input type="password" name="password" value="11111"> 13 <input type="hidden" name="salery" value="3333"> 14 <textarea name="description">description</textarea> 15 <input type="checkbox" name="hobby" checked value="football">Football 16 <input type="checkbox" name="hobby" value="basketball">Basketball 17 <input type="radio" name="sex" checked value="Female">Female 18 <input type="radio" name="sex" value="Male">Male 19 </form> 20 21 22 <script> 23 24 /** 25 * 将一个表单元素序列化为可提交的字符串 26 * 27 * @param {FormElement} form 需要序列化的表单元素 28 * @return {string} 表单序列化后的字符串 29 */ 30 function serializeForm(form) { 31 if (!form || form.nodeName.toUpperCase() !== ‘FORM‘) { 32 return; 33 } 34 35 var result = []; 36 37 var i, len; 38 var field, fieldName, fieldType; 39 40 for (i = 0, len = form.length; i < len; ++i) { 41 field = form.elements[i]; 42 fieldName = field.name; 43 fieldType = field.type; 44 45 if (field.disabled || !fieldName) { 46 continue; 47 } // enf if 48 49 switch (fieldType) { 50 case ‘text‘: 51 case ‘password‘: 52 case ‘hidden‘: 53 case ‘textarea‘: 54 result.push(encodeURIComponent(fieldName) + ‘=‘ + 55 encodeURIComponent(field.value)); 56 break; 57 58 &nbnbsp;case ‘radio‘: 59 case ‘checkbox‘: 60 if (field.checked) { 61 result.push(encodeURIComponent(fieldName) + ‘=‘ + 62 encodeURIComponent(field.value)); 63 } 64 break; 65 66 case ‘select-one‘: 67 case ‘select-multiple‘: 68 for (var j = 0, jLen = field.options.length; j < jLen; ++j) { 69 if (field.options[j].selected) { 70 result.push(encodeURIComponent(fieldName) + ‘=‘ + 71 encodeURIComponent(field.options[j].value || field.options[j].text)); 72 } 73 } // end for 74 break; 75 76 case ‘file‘: 77 case ‘submit‘: 78 break; // 是否处理? 79 80 default: 81 break; 82 } // end switch 83 } // end for 84 85 return result.join(‘&‘); 86 } 87 88 var form = document.getElementById(‘target‘); 89 console.log(serializeForm(form)); 90 </script>
1 <ul id="nav"> 2 <li><a href="http://11111">111</a></li> 3 <li><a href="http://2222">222</a></li> 4 <li><a href="http://333">333</a></li> 5 <li><a href="http://444">444</a></li> 6 </ul> 7 8 Object: 9 { 10 "index": 1, 11 "name": "111", 12 "link": "http://1111" 13 }
script:
1 var EventUtil = { 2 getEvent: function (event) { 3 return event || window.event; 4 }, 5 getTarget: function (event) { 6 return event.target || event.srcElement; 7 }, 8 // 返回注册成功的监听器,IE中需要使用返回值来移除监听器 9 on: function (elem, type, handler) { 10 if (elem.addEventListener) { 11 elem.addEventListener(type, handler, false); 12 return handler; 13 } else if (elem.attachEvent) { 14 function wrapper(event) { 15 return handler.call(elem, event); 16 }; 17 elem.attachEvent(‘on‘ + type, wrapper); 18 return wrapper; 19 } 20 }, 21 off: function (elem, type, handler) { 22 if (elem.removeEventListener) { 23 elem.removeEventListener(type, handler, false); 24 } else if (elem.detachEvent) { 25 elem.detachEvent(‘on‘ + type, handler); 26 } 27 }, 28 preventDefault: function (event) { 29 if (event.preventDefault) { 30 event.preventDefault(); 31 } else if (‘returnValue‘ in event) { 32 event.returnValue = false; 33 } 34 }, 35 stopPropagation: function (event) { 36 if (event.stopPropagation) { 37 event.stopPropagation(); 38 } else if (‘cancelBubble‘ in event) { 39 event.cancelBubble = true; 40 } 41 } 42 }; 43 var DOMUtil = { 44 text: function (elem) { 45 if (‘textContent‘ in elem) { 46 return elem.textContent; 47 } else if (‘innerText‘ in elem) { 48 return elem.innerText; 49 } 50 }, 51 prop: function (elem, propName) { 52 return elem.getAttribute(propName); 53 } 54 }; 55 56 var nav = document.getElementById(‘nav‘); 57 58 EventUtil.on(nav, ‘click‘, function (event) { 59 var event = EventUtil.getEvent(event); 60 var target = EventUtil.getTarget(event); 61 62 var children = this.children; 63 var i, len; 64 var anchor; 65 var obj = {}; 66 67 for (i = 0, len = children.length; i < len; ++i) { 68 if (children[i] === target) { 69 obj.index = i + 1; 70 anchor = target.getElementsByTagName(‘a‘)[0]; 71 obj.name = DOMUtil.text(anchor); 72 obj.link = DOMUtil.prop(anchor, ‘href‘); 73 } 74 } 75 76 alert(‘index: ‘ + obj.index + ‘ name: ‘ + obj.name + 77 ‘ link: ‘ + obj.link); 78 });
1 /** 2 * 数组去重 3 **/ 4 function normalize(arr) { 5 if (arr && Array.isArray(arr)) { 6 var i, len, map = {}; 7 for (i = arr.length; i >= 0; --i) { 8 if (arr[i] in map) { 9 arr.splice(i, 1); 10 } else { 11 map[arr[i]] = true; 12 } 13 } 14 } 15 return arr; 16 } 17 18 /** 19 * 用100个随机整数对应的字符串填充数组。 20 **/ 21 function fillArray(arr, start, end) { 22 start = start == undefined ? 1 : start; 23 end = end == undefined ? 100 : end; 24 25 if (end <= start) { 26 end = start + 100; 27 } 28 29 var width = end - start; 30 var i; 31 for (i = 100; i >= 1; --i) { 32 arr.push(‘‘ + (Math.floor(Math.random() * width) + start)); 33 } 34 return arr; 35 } 36 37 var input = []; 38 fillArray(input, 1, 100); 39 input.sort(function (a, b) { 40 return a - b; 41 }); 42 console.log(input); 43 44 normalize(input); 45 console.log(input);
前端面试题集锦及答案解析--HTML、 HTTP、web综合问题
标签:组件 递归 嵌套 阶段 handler 原理 水平 toc 无损压缩
原文地址:http://www.cnblogs.com/joyco773/p/6489733.html