跳到主要内容

new Date 在浏览器中兼容的问题

· 阅读需 3 分钟

在开发时,只在 chrome 下开发,所以,在其他浏览器上的效果并未发现。 结果在 ff 和 IE 下的 new Date(str) 时,出现了 NaN。

比如如下代码:

var timestart = '2010-05-04';
var timeend = '2015-06-23';
var time1 = (timestart+' 00:00:00').toString();
var time2 = (timeend+' 23:59:59').toString();
timestart = new Date(time1);
timeend = new Date(time2);

尝试

  • IE 下的执行情况:

    结果:Invalid Date

  • firefox 下的执行情况:

    结果:Invalid Date

  • chrome 下的执行情况:

    结果:正常

正确的姿势

主要的变化是对默认的日期格式进行了转换, 基于 '/' 格式的日期字符串,才是被各个浏览器所广泛支持的,‘-’连接的日期字符串,则是只在 chrome 下可以正常工作。

var time1 = (timestart+' 00:00:00').toString();
var time2 = (timeend+' 23:59:59').toString();
timestart = new Date(Date.parse(str.replace(/-/g,"/"))).getTime();
timeend = new Date(Date.parse(str.replace(/-/g,"/"))).getTime();

结论

2015-06-23 是无法被各个浏览器中,使用 new Date(str) 来正确生成日期对象的。 正确的用法是 2015/06/23.

Promise/Deffered 模式

· 阅读需 3 分钟

包含两个部分:

  • Promise
  • Deffered

Promise 抽象定义

Promise/A 对单个异步作出了这样的抽象定义:

  • Promise 操作只会处在 3 中状态:未完成完成失败
  • Promise 的状态只会出现从未完成状态转化为完成态或失败态,不能逆反。完成态和失败态不能互相转化。
  • Promise 的状态一旦转化,将不能被更改。

Promise 状态转化示意图

API 定义

一个 Promise 对象只要具备 then 方法即可。 但是 then 方法也有要求:

  • 接受完成态错误态的回调函数。在操作完成或出错时,将会调用对应方法。
  • 可选的支持 progress 事件回调作为第三个方法。
  • then() 方法只接受 function 对象,其余对象将被忽略。(可使用 typeof func === 'function' 来判断)
  • then() 方法继续返回 Promise 对象,以实现链式调用。

代码可参考这里的例子 https://github.com/luoyjx/promise-impl

事件冒泡和事件捕获

· 阅读需 10 分钟

事件——怎样使用事件以及 IE 和 DOM 事件模型之间存在哪些主要差别

冒泡型事件

事件按照从最特定的事件目标到最不特定的事件目标 (document 对象) 的顺序触发。

  • IE 5.5: div -> body -> document
  • IE 6.0: div -> body -> html -> document
  • Mozilla 1.0: div -> body -> html -> document -> window

捕获型事件 (event capturing)

事件从最不精确的对象 (document 对象) 开始触发,然后到最精确 (也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。

DOM 事件流

同时支持两种事件模型:捕获型事件和冒泡型事件,但是,捕获型事件先发生。两种事件流会触及 DOM 中的所有对象,从 document 对象开始,也在 document 对象结束。

支持 W3C 标准的浏览器在添加事件时用 addEventListener(event,fn,useCapture) 方法,基中第 3 个参数 useCapture 是一个 Boolean 值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容 W3C 的浏览器 (IE) 用 attachEvent() 方法,此方法没有相关设置,不过 IE 的事件模型默认是在事件冒泡时执行的,也就是在 useCapture 等于 false 的时候执行,所以把在处理事件时把 useCapture 设置为 false 是比较安全,也实现兼容浏览器的效果。

事件冒泡

  • 事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标 (target)。
  • 事件冒泡阶段:事件从事件目标 (target) 开始,往上冒泡直到页面的最上一级标签。

举例

假设一个元素 div,它有一个下级元素 p。

<div>
  <p>元素</p>
</div>

这两个元素都绑定了 click 事件,如果用户点击了 p,它在 div 和 p 上都触发了 click 事件,那这两个事件处理程序哪个先执行呢?事件顺序是什么?

两种模型

以前,Netscape 和 Microsoft 是不同的实现方式。

  • Netscape 中,div 先触发,这就叫做事件捕获。
  • Microsoft 中,p 先触发,这就叫做事件冒泡。

两种事件处理顺序刚好相反。IE 只支持事件冒泡,Mozilla, Opera 7 和 Konqueror 两种都支持,旧版本的 Opera's 和 iCab 两种都不支持 。

事件捕获

当你使用事件捕获时,父级元素先触发,子级元素后触发,即 div 先触发,p 后触发。

事件冒泡

当你使用事件冒泡时,子级元素先触发,父级元素后触发,即 p 先触发,div 后触发。

W3C 模型

W3C 模型是将两者进行中和,在 W3C 模型中,任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达了事件源元素。然后,再从事件源往上进行事件冒泡,直到到达 document。

程序员可以自己选择绑定事件时采用事件捕获还是事件冒泡,方法就是绑定事件时通过 addEventListener 函数,它有三个参数,第三个参数若是 true,则表示采用事件捕获,若是 false,则表示采用事件冒泡

ele.addEventListener('click',doSomething2,true)
//true=捕获
//false=冒泡

传统绑定事件方式

在一个支持 W3C DOM 的浏览器中,像这样一般的绑定事件方式,是采用的事件冒泡方式

ele.onclick = doSomething2

IE 浏览器

如上面所说,IE 只支持事件冒泡,不支持事件捕获,它也不支持 addEventListener 函数,不会用第三个参数来表示是冒泡还是捕获,它提供了另一个函数 attachEvent

ele.attachEvent("onclick", doSomething2);

附:事件冒泡(的过程):事件从发生的目标(event.srcElement||event.target)开始,沿着文档逐层向上冒泡,到 document 为止。

事件的传播是可以阻止的

具体可参见另一篇博文《js 中的事件冒泡》

js 中的事件冒泡

· 阅读需 11 分钟

JavaSciprt 事件中有两个很重要的特性:

  • 事件冒泡
  • 目标元素

在一个对象上触发某类事件(比如单击 onclick 事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回 true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即 document 对象(有些浏览器是 window)。

打个比方说:你在地方法院要上诉一件案子,如果地方没有处理此类案件的法院,地方相关部门会帮你继续往上级法院上诉,比如从市级到省级,直至到中央法院,最终使你的案件得以处理。

事件冒泡

事件冒泡允许多个操作被集中处理

事件冒泡允许多个操作被集中处理(把事件处理器添加到一个父级元素上,避免把事件处理器添加到多个子级元素上),它还可以让你在对象层的不同级别捕获事件

<div onclick="eventHandle(event)" id="outSide" >
<div id="inSide" ></div>
</div>
<script type="text/javascript">
//本例子只在外面盒子定义了处理方法,而这个方法一样可以捕获到子元素点击行为并处理它。假设有成千上万子元素要处理,难道我们要为每个元素加“onclick="eventHandle(event)"”?显然没有这种集中处理的方法来的简单,同时它的性能也是更高的。
function eventHandle(e)
{
var e=e||window.event;
var obj=e.target||e.srcElement;
alert(obj.id+' was click')
}
</script>

让不同的对象同时捕获同一事件

让不同的对象同时捕获同一事件 , 并调用自己的专属处理程序做自己的事情,就像老板一下命令,各自员工做自己岗位上的工作去了

<div onclick="outSideWork()" id="outSide" >
<div onclick="inSideWork()" id="inSide" ></div>
</div>
<script type="text/javascript">
function outSideWork()
{
alert('My name is outSide,I was working...');
}

function inSideWork()
{
alert('My name is inSide,I was working...');
}

//因为下面程序自动激活单击事件,有些浏览器不允许,所以请单击灰色盒子,从这里开始下命令,这样因为冒泡的原因,黑色大盒子也会收到单击事件,并调用了自己的处理程序。如果还有更多盒子嵌套,一样道理。

/*
function bossOrder()
{
document.getElmentById('inSide').click();
}
bossOrder();
*/
</script>

冒泡类型

冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标 (document 对象) 的顺序触发。

  • IE 5.5: div -> body -> document
  • IE 6.0: div -> body -> html -> document
  • Mozilla 1.0: div -> body -> html -> document -> window

阻止冒泡

通常情况下我们都是一步到位,明确自己的事件触发源,并不希望浏览器自作聪明、漫无目的地去帮我们找合适的事件处理程序,即我们明确最精准目标,这种情况下我们不需要事件冒泡。另外通过对事件冒泡的理解,我们知道程序将做多较多额外的事情,这必然增大程序开销。还有一个重要的问题是:事件冒泡处理可能会激活我们本来不想激活的事件,导致程序错乱,甚至无从下手调试,这常成为对事件冒泡不熟悉程序员的棘手问题。所以必要时,我们要阻止事件冒泡。

javascript 中兼容 IE 和 ff 的方式

//阻止事件冒泡函数
function stopBubble(e)
{
if (e && e.stopPropagation)
e.stopPropagation()
else
window.event.cancelBubble=true
}

阻止 jQuery 事件冒泡

jQuery 对 DOM 的事件触发具有冒泡特性。有时利用这一特性可以减少重复代码,但有时候我们又不希望事件冒泡。这个时候就要阻止 jQuery.Event 冒泡。

jQuery.Event 提供了一个非常简单的方法来阻止事件冒泡:event.stopPropagation();

$("p").click(function(event){
event.stopPropagation();
// do something
})

重放攻击 (Replay Attacks)

· 阅读需 16 分钟

根据百科的解释:

重放攻击(Replay Attacks)又称重播攻击、回放攻击或新鲜性攻击(Freshness Attacks),是指攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。 它是一种攻击类型,这种攻击会不断恶意或欺诈性地重复一个有效的数据传输,重放攻击可以由发起者,也可以由拦截并重发该数据的敌方进行。攻击者利用网络监听或者其他方式盗取认证凭据,之后再把它重新发给认证服务器。从这个解释上理解,加密可以有效防止会话劫持,但是却防止不了重放攻击。重放攻击任何网络通讯过程中都可能发生。重放攻击是计算机世界黑客常用的攻击方式之一,它的书面定义对不了解密码学的人来说比较抽象。

概念性的几个防御手段

时间戳

“时戳”──代表当前时刻的数 基本思想──A 接收一个消息当且仅当其包含一个对 A 而言足够接近当前时刻的时戳 原理──重放的时戳将相对远离当前时刻 时钟要求──通信各方的计算机时钟保持同步 处理方式──设置大小适当的时间窗(间隔),越大越能包容网络传输延时,越小越能防重放攻击 适用性──用于非连接性的对话(在连接情形下双方时钟若偶然出现不同步,则正确的信息可能会被误判为重放信息而丢弃,而错误的重放信息可能会当作最新信息而接收)

序号

通信双方通过消息中的序列号来判断消息的新鲜性 要求通信双方必须事先协商一个初始序列号,并协商递增方法

提问与应答

“现时”──与当前事件有关的一次性随机数 N(互不重复即可) 基本做法──期望从 B 获得消息的 A 事先发给 B 一个现时 N,并要求 B 应答的消息中包含 N 或 f(N),f 是 A、B 预先约定的简单函数 原理──A 通过 B 回复的 N 或 f(N) 与自己发出是否一致来判定本次消息是不是重放的 时钟要求──无 适用性──用于连接性的对话 重放攻击是对协议的攻击中危害最大、最常见的一种攻击形式。

以登陆为例看具体的例子

常规流程

  1. 前端 web 页面用户输入账号、密码,点击登录。
  2. 请求提交之前,web 端首先通过客户端脚本如 javascript 对密码原文进行 md5 加密。
  3. 提交账号、md5 之后的密码
  4. 请求提交至后端,验证账号与密码是否与数据库中的一致,一致则认为登录成功,反之失败。

有什么问题呢?

上述流程看似安全,认为传输过程中的密码是 md5 之后的,即使被监听截取到,由于 md5 的不可逆性,密码明文也不会泄露。其实不然!监听者无需解密出密码明文即可登录!监听者只需将监听到的 url(如:http://****/login.do?method=login&password=md5 之后的密码 &userid= 登录账号)重放一下,即可冒充你的身份登录系统。

稍微安全点的方式

  1. 进入登陆页面时,生成一个随机码(称之为盐值),在客户端页面和 session 中各保存一份。
  2. 客户端提交登录请求时,将 md5 之后的密码与该随机码拼接后,再次执行 md5,然后提交(提交的密码 =md5(md5(密码明文)+随机码))。
  3. 后端接收到登录请求后,将从数据库中查询出的密码与 session 中的随机码拼接后,md5 运算,然后与前端传递的结果进行比较。

为何要这样?

该登录方式,即使登录请求被监听到,回放登录 URL,由于随机码不匹配(监听者的 session 中的随机码与被监听者的 session 中的随机码相同概率可忽略),无法登录成功。 该登录方式,由于传输的密码是原密码 md5 之后与随机码再次 md5 之后的结果,即使监听者采用暴力破解的方式,也很难解密出密码明文。

更进一步

考虑到密码输入的方便性,好多用户的密码都设置的很短,并且不够复杂,往往是 6 位数字字母组合,这样的密码 md5 之后保存到数据库,一旦数据库数据泄露,简单密码的 md5 结果很容易通过暴力破解的方式给解密出来,何况 md5 出现了这么多年,可能已经有不少字典了!同时为了方便用户登录的方便性,我们的系统一般不可能要求用户设置很长、很复杂的密码!怎么办?加固定盐值

  1. 系统设置一个固定的盐值,该盐值最好足够复杂,如 :1qaz2wsx3edc4rfv!@#$%^&qqtrtRTWDFHAJBFHAGFUAHKJFHAJHFJHAJWRFA
  2. 用户注册、修改密码时,将用户的原始密码与我们的固定盐值拼接,然后做 md5 运算。
  3. 传递至后端,保存进数据库(数据库中保存的密码是用户的原始密码拼接固定盐值后,md5 运算后的结果)。
  4. 登录时,将用户的原始密码与我们的固定盐值进行拼接,然后做 md5 运算,运算后的结果再拼接上我们的随机码,再次 md5 运算,然后提交。
  5. 后端接收到登录请求后,将从数据库中查询出的密码与 session 中的随机码拼接后,md5 运算,然后与前端传递的结果进行比较。

再再进一步

  1. 加登录验证码,可预防人为地暴力登录破解
  2. 账户锁定,如果用户密码输入错误次数达到一定量后(如 6 次),则可以锁定该账号

js 中的 dom 操作回顾

· 阅读需 7 分钟

创建节点

  • document.body 指向的是 body 元素
  • document.documentElement 则指向 html 元素
    //创建节点
var createNode = document.createElement("div");
var createTextNode = document.createTextNode("hello world");
createNode.appendChild(createTextNode);
document.body.appendChild(createNode);
document.documentElement.appendChild(createNode);

插入节点

可以使用

  • appendChild
  • insertBefore insertBefore 接收两个参数,第一个是插入的节点,第二个是参照节点,如 insertBefore(a,b),则 a 会插入在 b 的前面
    //插入节点
var createNode = document.createElement("div");
var createTextNode = document.createTextNode("hello world");
createNode.appendChild(createTextNode);
var div1 = document.getElementById("div1");
document.body.insertBefore(createNode,div1);

替换和删除元素

从 replaceChild 和 removeChild 的字面意思看,就是删除子节点,因此调用者,需要包含子节点 div1,不然调用会报错。返回的节点是替换的或删除的元素,被替换 / 删除的元素仍然存在,但 document 中已经没有他们的位置了。

//替换元素
var replaceChild = document.body.replaceChild(createNode,div1);
//删除元素
var removeChild = document.body.removeChild(div1);

节点的属性

  • firstChild: 第一个子节点
  • lastChild: 最后一个子节点
  • childNodes: 子节点集合,获取其中子节点可以 someNode.childNodes[index] 或者 someNode.childNodes.item(index)
  • nextSibling: 下一个兄弟节点
  • previousSibling:上一个兄弟节点
  • parentNode:父节点

文档片段

好处在于减少 dom 的渲染次数,可以优化性能。

//文本片段
var fragment = document.createDocumentFragment();
var ul = document.getElementById("ul");
var li = null;
for (var i = 4; i >= 0; i--) {
li = document.createElement("li");
li.appendChild(document.createTextNode("item "+i));
fragment.appendChild(li);
}
ul.appendChild(fragment);

克隆元素

  • someNode.cloneNode(true): 深度克隆,会复制节点及整个子节点
  • someNode.cloneNode(false): 浅克隆,会复制节点,但不复制子节点
//克隆
var clone = ul.cloneNode(true);
document.body.appendChild(clone);

注意

childNodes.length 存在跨浏览器的问题

可以看到有关列表的 html 片段没有用

<ul id="ul">
<li>sdsssssss</li>
<li>qqqq</li>
<li>wwww</li>
<li>eeee</li>
</ul>

这种书写格式而是使用没有换行的格式书写,是因为在不同的浏览器中,获取 ul.childNodes.length 的结果有差异: 在 ie 中,ul.childNodes.length 不会计算 li 之间的换行空格,从而得到数值为 4 在 ff、chrome,safari 中,会有包含 li 之间的空白符的 5 个文本节点,因此 ul.childNodes.length 为 9 若要解决跨浏览器问题,可以将 li 之间的换行去掉,改成一行书写格式。

cloneNode 存在跨浏览器的问题

在 IE 中,通过 cloneNode 方法复制的元素,会复制事件处理程序,比如,var b = a.cloneNode(true). 若 a 存在 click,mouseover 等事件监听,则 b 也会拥有这些事件监听。 在 ff,chrome,safari 中,通过 cloneNode 方法复制的元素,只会复制特性,其他一切都不会复制 因此,若要解决跨浏览器问题,在复制前,最好先移除事件处理程序。

Javascript 的 addEventListener() 及 attachEvent() 区别分析

· 阅读需 9 分钟

大家都知道事件的用法就是当某个事件 (状况) 被触发了之后就会去执行某个 Function, 尤其是 Javascript, 在当红 AJAX 的催化下 , 了解 Javascript 的 Event 用法更加重要 , 在这里就大概介绍一下 avascript 的 Event 用法。

Mozilla 中

addEventListener 的使用方式:

target.addEventListener(type, listener, useCapture);

  • target: 文档节点、document、window 或 XMLHttpRequest。
  • type: 字符串,事件名称,不含“on”,比如“click”、“mouseover”、“keydown”等。
  • listener :实现了 EventListener 接口或者是 JavaScript 中的函数。
  • useCapture :是否使用捕捉,一般用 false 。 例如:
document.getElementById("testText").addEventListener("keydown", function (event) { alert(event.keyCode); }, false);

栗子

document.getElementById("testText").addEventListener("keydown", function (event) { alert(event.keyCode); }, false);

IE中

target.attachEvent(type, listener);

  • target: 文档节点、document、window 或 XMLHttpRequest。
  • type: 字符串,事件名称,含“on”,比如“onclick”、“onmouseover”、“onkeydown”等。
  • listener :实现了 EventListener 接口或者是 JavaScript 中的函数。 例如:document.getElementById("txt").attachEvent("onclick",function(event){alert(event.keyCode);});

移除事件

W3C 及 IE 同时支持移除指定的事件 , 用途是移除设定的事件 , 格式分别如下 :

W3C 格式

removeEventListener(event,function,capture/bubble);

Windows IE的格式如下

detachEvent(event,function);

浏览器兼容

适应的浏览器版本不同,同时在使用的过程中要注意

  • attachEvent 方法 按钮 onclick IE 中使用
  • addEventListener 方法 按钮 click fox 中使用

两者使用的原理:可对执行的优先级不一样:

  • attachEvent 方法,为某一事件附加其它的处理事件。(不支持 Mozilla 系列)
  • addEventListener 方法 用于 Mozilla 系列

栗子

document.getElementById("btn").onclick = method1;
document.getElementById("btn").onclick = method2;
document.getElementById("btn").onclick = method3;

**如果这样写 , 那么将会只有 medhot3 被执行 **

写成这样:

var btn1Obj = document.getElementById("btn1"); //object.attachEvent(event,function);
btn1Obj.attachEvent("onclick",method1);
btn1Obj.attachEvent("onclick",method2);
btn1Obj.attachEvent("onclick",method3);

**执行顺序为 method3->method2->method1 **

如果是 Mozilla 系列,并不支持该方法,需要用到 addEventListener

var btn1Obj = document.getElementById("btn1");
//element.addEventListener(type,listener,useCapture);
btn1Obj.addEventListener("click",method1,false);
btn1Obj.addEventListener("click",method2,false);
btn1Obj.addEventListener("click",method3,false);

执行顺序为 method1->method2->method3

兼容 IE 和 firefox 的事件处理

封装

function addListener(element, eventName, handler) {
if (element.addEventListener) {
element.addEventListener(eventName, handler, false);
}
else if (element.attachEvent) {
element.attachEvent('on' + eventName, handler);
}
else {
element['on' + eventName] = handler;
}
}

function removeListener(element, eventName, handler) {
if (element.addEventListener) {
element.removeEventListener(eventName, handler, false);
}
else if (element.detachEvent) {
element.detachEvent('on' + eventName, handler);
}
else {
element['on' + eventName] = null;
}
}

上面函数有两处需要注意一下就是 :

  1. 第一个分支最好先测定 w3c 标准 . 因为 IE 也渐渐向标准靠近 . 第二个分支监测 IE.
  2. 第三个分支是留给既不支持 (add/remove)EventListener 也不支持 (attach/detach)Event 的浏览器 .

优化

对于上面的函数我们是运用 " 运行时 " 监测的 . 也就是每次绑定事件都需要进行分支监测 . 我们可以将其改为 " 运行前 " 就确定兼容函数 . 而不需要每次监测 .

这样我们就需要用一个 DOM 元素提前进行探测 . 这里我们选用了 document.documentElement. 为什么不用 document.body 呢 ? 因为 document.documentElement 在 document 没有 ready 的时候就已经存在. 而 document.body 没 ready 前是不存在的 .

这样函数就优化成

var addListener, removeListener,
/* test element */
docEl = document.documentElement;

// addListener
if (docEl.addEventListener) {
/* if `addEventListener` exists on test element, define function to use `addEventListener` */
addListener = function (element, eventName, handler) {
element.addEventListener(eventName, handler, false);
};
} else if (docEl.attachEvent) {
/* if `attachEvent` exists on test element, define function to use `attachEvent` */
addListener = function (element, eventName, handler) {
element.attachEvent('on' + eventName, handler);
};
} else {
/* if neither methods exists on test element, define function to fallback strategy */
addListener = function (element, eventName, handler) {
element['on' + eventName] = handler;
};
}

// removeListener
if (docEl.removeEventListener) {
removeListener = function (element, eventName, handler) {
element.removeEventListener(eventName, handler, false);
};
} else if (docEl.detachEvent) {
removeListener = function (element, eventName, handler) {
element.detachEvent('on' + eventName, handler);
};
} else {
removeListener = function (element, eventName, handler) {
element['on' + eventName] = null;
};
}

简单说说 web 语义化

· 阅读需 6 分钟

一个小问题

先看一段 HTML 代码

<table>
<tr>
<td colspan="2">Student List</td>
</tr>
<tr>
<td>Name</td>
<td>Age</td>
</tr>
<tr>
<td>Byron</td>
<td>24</td>
</tr>
<tr>
<td>Vincent</td>
<td>25</td>
</tr>
<tr>
<td>Casper</td>
<td>27</td>
</tr>
</table>

就算是没有看到页面效果,相信很多同学看到内容后也能明白这个表格在描述什么,但是计算机(搜索引擎)却不明白,计算机并不知道 Name 或者 Age 代表 title,而下面的是内容。但如果这么写

<table>
<caption>Student List</caption>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Byron</td>
<td>24</td>
</tr>
<tr>
<td>Vincent</td>
<td>25</td>
</tr>
<tr>
<td>Casper</td>
<td>27</td>
</tr>
</tbody>
</table>

这样即使我们不看内容也能了解这大概是什么,计算机也会理解哪些是标题,哪些是 header,哪些是内容。

Web 语义化

这个东西我也是和同学们聊了聊天儿,自己翻了些资料,所以这里仅说一下个人的理解。HTML 的每个标签都有其特定含义(语义),Web 语义化是指使用语义恰当的标签,使页面有良好的结构,页面元素有含义,能够让人和搜索引擎都容易理解

如果可以在合适的位置使用恰当的标签,那么写出来的页面语义明确,结构清晰,搜索引擎也可以认出哪些是页面重要内容,予以较高的权值。h1h6 这几个标签在搜索引擎中权值非常高,用它们作页面标题就是一个简单的 SEO 优化了,知道了这个你还使用 DIV+CSS 来写标题吗?(不是说直接用 h1h6 标签做标题,要这几个标签+CSS)

回到开始时的疑惑,这时候 header、footer、sidebar、article 等标签的出现就不是那么让人困惑了,HTML5 的一大革新就是语义化标签的完善。

语义化网页结构

使用这样结构写出的网页其语义显而易见。在有些面试的时候会问到类似 strong 和 font-weight: bold 有什么区别,这时候就可以从语义化的角度解答了。

一些标签语义

标签 语义

  • h1~h6 标题
  • th table 的 header
  • p 段落
  • ul 无序列表
  • ol 排序列表
  • dl definition list,定义列表
  • dt definition title,定义名称
  • dd definition description 定义描述
  • em emphasized,局部强调 , 段落内强调
  • strong 更强烈的强调,全文强调

js 键盘粘贴上传图片

· 阅读需 2 分钟

segmentfault 上看到的一个问直接在文本框中粘贴就可以上传图片的例子。

/** 粘贴上传图片 **/
document.body.addEventListener('paste', function(e) {
var clipboard = e.clipboardData;
for(var i=0,len=clipboard.items.length; i<len; i++) {
if(clipboard.items[i].kind == 'file' || clipboard.items[i].type.indexOf('image') > -1) {
var imageFile = clipboard.items[i].getAsFile();
var form = new FormData;
form.append('image', imageFile);
$.ajax({
url: channel.server+"/u.php?community="+channel.community,
type: "POST",
data: form,
processData: false,
contentType: false,
beforeSend: function() {
$('#uploadmessage').html('正在上传图片...');
},
error: function() {
$('#uploadmessage').html('上传失败请重新上传!');
setTimeout('$(\'#uploadmessage\').html(\'\')', 1000);
},
success: function(url) {
$('#uploadmessage').html('图片上传成功');
setTimeout('$(\'#uploadmessage\').html(\'\')', 1000);
var textarea = $('.textarea');
textarea.val(textarea.val() + '[![]('+url+')]('+url+')')
}
})
e.preventDefault();
}
}
});

这里是帖子原文

http://segmentfault.com/q/1010000002729267

IE9 以下不支持 JSON.parse 的一些解决方案

· 阅读需 4 分钟

在 IE9 以下是不支持 JSON.parse 方法来解析 JSON 字符串的。

原来,在 IE8 中使用原生 JSON 对象是有条件的。微软在介绍 JSON 对象时也有下面的一段注释:

Starting with JScript. 5.8, by default, the JScript. scripting engine supports the language feature set as it existed in version 5.7. This is to maintain compatibility with the earlier versions of the engine. To use the complete language feature set of version 5.8, the Windows Script. interface host has to invoke IActiveScriptProperty::SetProperty.

Internet Explorer 8 opts into the JScript. 5.8 language features when the document mode for Internet Explorer 8 is "Internet Explorer 8 Standards" mode. For other document modes, Internet Explorer uses the version 5.7 feature set.

JScript. 5.8 includes native JavaScript. Object Notation (JSON) support and the accessor methods for Document Object Model (DOM) prototypes.

由于 JSON 对象是在 JScript. 5.8 及其以后的版本引入的,所以,默认情况下,IE8 使用的是 JScript. 5.7 版本,所以,原生 JSON 对象是无法使用的。

1.eval 方式解析,恐怕这是最早的解析方式了

    function strToJson(str){
var json = eval('(' + str + ')');
return json;
}

但是出于安全性的考虑,建议尽量不要使用 eval,如果从第三方获取数据进行解析,会存在恶意脚本代码的风险。

2.new Function 形式,比较怪异。

    function strToJson(str){
var json = (new Function("return " + str))();
return json;
}