html 5 meta tag

meta的作用

meta是用来在HTML文档中模拟HTTP协议的响应头报文。meta 标签位于网页的<head>。。。</head>中,meta 标签的用处很多。meta 的属性有两种:name和http-equiv。name属性主要用于描述网页,对应于content(网页内容),以便于搜索引擎机器人查找、分类,搜索引擎都使用网上机器人自动查找meta值来给网页分类)。这其中最重要的是description(站点摘要)和keywords(分类关键词),所以应该给每页加一个meta值,w3c如是说

  • 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。
  • 标签位于文档的头部,不包含任何内容。 标签的属性定义了与文档相关联的名称/值对。

每个meta标签必须具有content属性,定义与 http-equiv 或 name 属性相关的元信息。

可选属性

http-equiv 属性

http-equiv 属性为名称/值对提供了名称。并指示服务器在发送实际的文档之前先在要传送给浏览器的 MIME 文档头部包含名称/值对。
当服务器向浏览器发送文档时,会先发送许多名称/值对。虽然有些服务器会发送许多这种名称/值对,但是所有服务器都至少要发送一个:content-type:text/html。这将告诉浏览器准备接受一个 HTML 文档。
使用带有 http-equiv 属性的 标签时,服务器将把名称/值对添加到发送给浏览器的内容头部。包括content-type ,expires,refresh ,set-cookie例如,添加:

<meta http-equiv="charset" content="iso-8859-1">
<meta http-equiv="expires" content="31 Dec 2008">

这样发送到浏览器的头部就应该包含:

content-type: text/html
charset:iso-8859-1
expires:31 Dec 2008

5秒刷新一次页面

<meta http-equiv="refresh" content="5" />

content 属性

  • content 属性提供了名称/值对中的值。该值可以是任何有效的字符串。
  • content 属性始终要和 name 属性或 http-equiv 属性一起使用。

name 属性

name 属性提供了名称/值对中的名称。HTML 和 XHTML 标签都没有指定任何预先定义的 名称。通常情况下,您可以自由使用对自己和源文档的读者来说富有意义的名称。
“keywords” 是一个经常被用到的名称。它为文档定义了一组关键字。某些搜索引擎在遇到这些关键字时,会用这些关键字对文档进行分类。
类似这样的 meta 标签可能对于进入搜索引擎的索引有帮助:

<meta name="keywords" content="HTML,ASP,PHP,SQL">
<meta name="KEYWords" contect="">向搜索引擎说明你的网页的关键词; 
<meta name="DEscription" contect="">告诉搜索引擎你的站点的主要内容; 
<meta name="Author" contect="你的姓名">告诉搜索引擎你的站点的制作的作者; 
<meta name="Robots" contect= "all|none|index|noindex|follow|nofollow"> 

其中的属性说明如下:

  • 设定为all:文件将被检索,且页面上的链接可以被查询;
  • 设定为none:文件将不被检索,且页面上的链接不可以被查询;
  • 设定为index:文件将被检索;
  • 设定为follow:页面上的链接可以被查询;
  • 设定为noindex:文件将不被检索,但页面上的链接可以被查询;
  • 设定为nofollow:文件将不被检索,页面上的链接可以被查询。

另外一点需要注意的是在HTML4中定义页面的字符集需要,放在content-type对应的content里面

<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

HTML5中新增了 charset属性 ,使用更简单

<meta charset="utf-8">

html5 canvas 2d绘图API 学习总结

基本知识

canvas本身提供的属性和方法很少 属性有hegight,width(这个属性与通过CSS设置的是不同的),绘图功能主要是存在通过canvas.getContext()返回的上下文中.有个一个toDataUrl()方法, 可以将canvas的转为一定格式的图片。下面主要介绍,context2d里面的方法。之前学过C语言绘图,貌似方法很类似

获取绘图上下文

var context =canvas.getContext("2d");

canvas元素绘制图像的时候有两种方法,分别是

  • context.fill()//填充
  • context.stroke()//绘制边框

style:在进行图形绘制前,要设置好绘图的样式

  • context.fillStyle//填充的样式
  • context.strokeStyle//边框样式
  • context.lineWidth//图形边框宽度

颜色的表示方式:

  • 直接用颜色名称:”red” “green” “blue”
  • 十六进制颜色值: “#EEEEFF”
  • rgb(1-255,1-255,1-255)
  • rgba(1-255,1-255,1-255,透明度)
    默认情况下坐标原点为canvas的左上角,水平向右为X
绘制矩形 context.fillRect(x,y,width,height) strokeRect(x,y,width,height)
  • x:矩形起点横坐标
  • y:矩形起点纵坐标
  • width:矩形长度
  • height:矩形高度

查看Demo

清除矩形区域 context.clearRect(x,y,width,height)
  • x:清除矩形起点横坐标
  • y:清除矩形起点纵坐标
  • width:清除矩形长度
  • height:清除矩形高度

查看Demo

圆弧context.arc(x, y, radius, starAngle,endAngle, anticlockwise)
  • x:圆心的x坐标
  • y:圆心的y坐标
  • straAngle:开始角度
  • endAngle:结束角度
  • anticlockwise:是否逆时针(true)为逆时针,(false)为顺时针

    查看demo

路径 context.beginPath() context.closePath()
  • 系统默认在绘制第一个路径的开始点为beginPath
  • 如果画完前面的路径没有重新指定beginPath,那么画第其他路径的时候会将前面最近指定的beginPath后的全部路径重新绘制
  • 每次调用context.fill()的时候会自动把当次绘制的路径的开始点和结束点相连,接着填充封闭的部分

    查看demo

    绘制线段 context.moveTo(x,y) context.lineTo(x,y)

  • x:x坐标

  • y:y坐标

每次画线都从moveTo的点到lineTo的点,
如果没有moveTo那么第一次lineTo的效果和moveTo一样,
每次lineTo后如果没有moveTo,那么下次lineTo的开始点为前一次lineTo的结束点

查看demo

绘制贝塞尔曲线(贝济埃、bezier) context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)
  • cp1x:第一个控制点x坐标
  • cp1y:第一个控制点y坐标
  • cp2y:第二个控制点y坐标
  • x:终点x坐标
  • y:终点y坐标
绘制二次样条曲线 context.quadraticCurveTo(qcpx,qcpy,qx,qy)
  • qcpx:二次样条曲线控制点x坐标
  • qcpy:二次样条曲线控制点y坐标
  • qx:二次样条曲线终点x坐标
  • qy:二次样条曲线终点y坐标

查看demo

线性渐变 var lg= context.createLinearGradient(xStart,yStart,xEnd,yEnd);线性渐变颜色lg.addColorStop(offset,color)
  • xstart:渐变开始点x坐标
  • ystart:渐变开始点y坐标
  • xEnd:渐变结束点x坐标
  • yEnd:渐变结束点y坐标
  • offset:设定的颜色离渐变结束点的偏移量(0~1)
  • color:绘制时要使用的颜色
径向渐变(发散)var rg=context.createRadialGradient(xStart,yStart,radiusStart,xEnd,yEnd,radiusEnd)
径向渐变(发散)颜色rg.addColorStop(offset,color)
  • xStart:发散开始圆心x坐标
  • yStart:发散开始圆心y坐标
  • radiusStart:发散开始圆的半径
  • xEnd:发散结束圆心的x坐标
  • yEnd:发散结束圆心的y坐标
  • radiusEnd:发散结束圆的半径
  • offset:设定的颜色离渐变结束点的偏移量(0~1)
  • color:绘制时要使用的颜色

渐变Demo

图形变换(坐标系变换)

1、平移context.translate(x,y)

  • x:坐标原点向x轴方向平移x
  • y:坐标原点向y轴方向平移y

2、缩放context.scale(x,y)

  • x:x坐标轴按x比例缩放
  • y:y坐标轴按y比例缩放

3、旋转context.rotate(angle)

  • angle:坐标轴旋转x角度(角度变化模型和画圆的模型一样)
矩阵变换 context.transform(m11,m12,m21,m22,dx,dy)

所谓的矩阵变换其实是context内实现平移,缩放,旋转的一种机制,他的主要原理就是矩阵相乘
参见demo

图形组合 context.globalCompositeOperation=type

图形组合就是两个图形相互叠加了图形的表现形式,是后画的覆盖掉先画的呢,还是相互重叠的部分不显示等等,至于怎么显示就取决于type的值了
type:

source-over(默认值):在原有图形上绘制新图形

destination-over:在原有图形下绘制新图形

source-in:显示原有图形和新图形的交集,新图形在上,所以颜色为新图形的颜色

destination-in:显示原有图形和新图形的交集,原有图形在上,所以颜色为原有图形的颜色

source-out:只显示新图形非交集部分

destination-out:只显示原有图形非交集部分

source-atop:显示原有图形和交集部分,新图形在上,所以交集部分的颜色为新图形的颜色

destination-atop:显示新图形和交集部分,新图形在下,所以交集部分的颜色为原有图形的颜色

lighter:原有图形和新图形都显示,交集部分做颜色叠加

xor:重叠飞部分不现实

copy:只显示新图形
给图形绘制阴影
  • context.shadowOffsetX :阴影的横向位移量(默认值为0)
  • context.shadowOffsetY :阴影的纵向位移量(默认值为0)
  • context.shadowColor :阴影的颜色
  • context.shadowBlur :阴影的模糊范围(值越大越模糊)
绘制图像
  • 绘图:context.drawImage

  • 图像平铺:context.createPattern(image,type)

  • 图像裁剪:context.clip()

  • 像素处理:var imagedata=context.getImageData(sx,sy,sw,sh)

  • 设置像素颜色:context.putImageData(imagedata,dx,dy,dirtyX,dirtyY,dirtyWidth,dirtyHeight)

绘制文字
  • 填充文字:context.fillText(text,x,y)
  • 绘制文字轮廓 context.strokeText(text,x,y)

  • text:要绘制的文字

  • x:文字起点的x坐标轴
  • y:文字起点的y坐标轴
  • context.font:设置字体样式
  • context.textAlign:水平对齐方式
    start、end、right、center
    
  • context.textBaseline:垂直对齐方式:top、hanging、middle、alphabetic、ideographic、bottom
保存和恢复上下文状态,主要包括坐标系,裁剪区域等
  • 保存:context.save()
  • 恢复:context.restore()
保存文件 canvas.toDataURL(MIME)

在canvas中绘出的图片只是canvas标签而已,并非是真正的图片,是不能右键,另存为的,我们可以利用canvas.toDataURL()这个方法把canvas绘制的图形生成一幅图片,生成图片后,就能对图片进行相应的操作了。

HTML5 语义化标签

在HTML 5出来之前,我们用div来表示页面章节,但是这些div都没有实际意义。(即使我们用css样式的id和class形容这块内容的意义)。这些标签只是我们提供给浏览器的指令,只是定义一个网页的某些部分。但现在,那些之前没“意义”的标签因为因为html5的出现消失了,这就是我们平时说的“语义”。
节点元素标签因使用的地方不同,我将他们分为:节元素标签、文本元素标签、分组元素标签分开来讲解HTML5中新增加的语义化标签和使用总结。

header元素

header 元素代表“网页”或“section”的页眉。
通常包含h1-h6元素或hgroup,作为整个页面或者一个内容块的标题。也可以包裹一节的目录部分,一个搜索框,一个nav,或者任何相关logo。
整个页面没有限制header元素的个数,可以拥有多个,可以为每个内容块增加一个header元素

<header>
    <hgroup>
        <h1>网站标题</h1>
        <h1>网站副标题</h1>
    </hgroup>
</header>
  • header使用注意:
  • 可以是“网页”或任意“section”的头部部分;
  • 没有个数限制。
  • 如果hgroup或h1-h6自己就能工作的很好,那就不要用header。

footer元素代表“网页”或“section”的页脚,通常含有该节的一些基本信息,譬如:作者,相关文档链接,版权资料。如果footer元素包含了整个节,那么它们就代表附录,索引,提拔,许可协议,标签,类别等一些其他类似信息。

<footer>
    COPYRIGHT@小北
</footer>

footer使用注意:

  • 可以是“网页”或任意“section”的底部部分;
  • 没有个数限制,除了包裹的内容不一样,其他跟header类似。

hgroup元素

hgroup元素代表“网页”或“section”的标题,当元素有多个层级时,该元素可以将h1到h6元素放在其内,譬如文章的主标题和副标题的组合

<hgroup>
    <h1>这是一篇介绍HTML 5语义化标签和更简洁的结构</h1>
    <h2>HTML 5</h2>
</hgroup>

hgroup使用注意:

  • 如果只需要一个h1-h6标签就不用hgroup
  • 如果有连续多个h1-h6标签就用hgroup
  • 如果有连续多个标题和其他文章数据,h1-h6标签就用hgroup包住,和其他文章元数据一起放入header标签

nav元素代表页面的导航链接区域。用于定义页面的主要导航部分。

<nav>
    <ul>
        <li>HTML 5</li>
        <li>CSS3</li>
        <li>JavaScript</li>
    </ul>
</nav>

但是我在有些时候却情不自禁的想用它,譬如:侧边栏上目录,面包屑导航,搜索样式,或者下一篇上一篇文章,但是事实上规范上说nav只能用在页面主要导航部分上。页脚区域中的链接列表,虽然指向不同网站的不同区域,譬如服务条款,版权页等,这些footer元素就能够用了。

nav使用注意:

  • 用在整个页面主要导航部分上,不合适就不要用nav元素

aside元素

aside元素被包含在article元素中作为主要内容的附属信息部分,其中的内容可以是与当前文章有关的相关资料、标签、名次解释等。(特殊的section)
在article元素之外使用作为页面或站点全局的附属信息部分。最典型的是侧边栏,其中的内容可以是日志串连,其他组的导航,甚至广告,这些内容相关的页面。

<article>
    <p>内容</p>
    <aside>
        <h1>作者简介</h1>
        <p>小北,前端一枚</p>
    </aside>
</article>

aside使用总结:

  • aside在article内表示主要内容的附属信息,
  • 在article之外则可做侧边栏,没有article与之对应,最好不用。
  • 如果是广告,其他日志链接或者其他分类导航也可以用

section元素

section元素代表文档中的“节”或“段”,“段”可以是指一篇文章里按照主题的分段;“节”可以是指一个页面里的分组。
section通常还带标题,虽然html5中section会自动给标题h1-h6降级,但是最好手动给他们降级。如下:

<section>
    <h1>section是啥?</h1>
    <article>
        <h2>关于section</h1>
        <p>section的介绍</p>
        <section>
            <h3>关于其他</h3>
            <p>关于其他section的介绍</p>
        </section>
    </article>
</section>

section使用注意:

  • 一张页面可以用section划分为简介、文章条目和联系信息。不过在文章内页,最好用article。section不是一般意义上的容器元素,如果想作为样式展示和脚本的便利,可以用div。
  • 表示文档中的节或者段;
  • article、nav、aside可以理解为特殊的section,所以如果可以用article、nav、aside就不要用section,没实际意义的就用div

article元素

article元素最容易跟section和div容易混淆,其实article代表一个在文档,页面或者网站中自成一体的内容,其目的是为了让开发者独立开发或重用。譬如论坛的帖子,博客上的文章,一篇用户的评论,一个互动的widget小工具。(特殊的section)
除了它的内容,article会有一个标题(通常会在header里),会有一个footer页脚。我们举几个例子介绍一下article,好更好区分article、section、div

<article>
    <h1>一篇文章</h1>
    <p>文章内容..</p>
    <footer>
        <p><small>版权:html5jscss网所属,作者:小北</small></p>
    </footer>
</article>

上例是最好简单的article标签使用情况,如果在article内部再嵌套article,那就代表内嵌的article是与它外部的内容有关联的,如博客文章下面的评论,如下:

<article>
    <header>
        <h1>一篇文章</h1>
        <p><time pubdate datetime="2012-10-03">2012/10/03</time></p>
    </header>
    <p>文章内容..</p>
    <article>
        <h2>评论</h2>
        <article>
            <header>
                <h3>评论者: XXX</h3>
                <p><time pubdate datetime="2012-10-03T19:10-08:00">~1 hour ago</time></p>
            </header>
            <p>哈哈哈</p>
        </article>
        <article>
            <header>
                <h3>评论者: XXX</h3>
                <p><time pubdate datetime="2012-10-03T19:10-08:00">~1 hour ago</time></p>
            </header>
            <p>哈?哈?哈?</p>
        </article>
    </article>
</article>

文章里的评论,一个article嵌套article来表示的实例
article内部嵌套article,有可能是评论或其他跟文章有关联的内容。那article内部嵌套section一般是什么情况呢。如下:

<article>
    <h1>前端技术</h1>
    <p>前端技术有那些</p>
    <section>
        <h2>CSS</h2>
        <p>样式..</p>
    </section>
    <section>
        <h2>JS</h2>
        <p>脚本</p>
    </section>
</article>

文章里的章节,一个article里的section实例
因为文章内section部分虽然也是独立的部分,但是它门只能算是组成整体的一部分,从属关系,article是大主体,section是构成这个大主体的一部分。本网站的全部文章都是article嵌套一个个section章节,这样能让浏览器更容易区分各个章节所包括的内容。
那section内部嵌套article又有哪些情况呢,如下

<section>
    <h1>介绍: 网站制作成员配备</h1>
    <article>
        <h2>设计师</h2>
        <p>设计网页的...</p>
    </article>
    <article>
        <h2>程序员</h2>
        <p>后台写程序的..</p>
    </article>
    <article>
        <h2>前端工程师</h2>
        <p>给楼上两位打杂的..</p>
    </article>
</section>

设计师、程序员、前端工程师都是一个独立的整体,他们组成了网站制作基本配备,当然还有其他成员~~。设计师、程序员、前端工程师就像article,是一个个独立的整体,而section将这些自成一体的article包裹,就组成了一个团体。
article和section和例子就例举这么多了,具体情况具体分析,不易深究。漏了div,其实div就是只是想用来把元素组合或者给它们加样式时使用。

article使用注意:

自身独立的情况下:用article
是相关内容:用section
没有语义的:用div

HTML5其他结构元素标签

HTML5节元素标签包括body article nav aside section header footer hgroup ,还有h1-h6 address

  • address代表区块容器,必须是作为联系信息出现,邮编地址、邮件地址等等,一般出现在footer。
  • h1-h6因为hgroup,section和article的出现,h1-h6定义也发生了变化,允许一张页面出现多个h1。

文本字体元素

文字对SEO影响很大,而HTML5对一些文本字体元素的语义又重新定义了一遍,也增加了一些新的。那我们就来重新认识他们。

  • a(anchor 的缩写): 用于定义超链接
  • em(emphasis 的缩写):em 是句意强调,加与不加会引起语义变化,也可以理解为局部强调,用在语句某个单词上来改变句子的侧重。
  • strong:strong表示重要,strong 的强调则是一种随意无顺序的,看见某文时,立刻就凸显出来的关键词句。
  • p:p元素
  • b(bold 的缩写):b 元素原本就是加粗,现在表示“文体突出”文字,通俗将是用来在文本中高亮显示某个或者几个字符,旨在引起用户的特别注意,无强调作用。譬如文档概要中的关键字,评论中的产品名,以及分类名。
  • i(italic 的缩写):i 元素原本只是倾斜,现在描述为在普通文章中突出不同意见或语气或其他的一段文本,就像剧本里的话外音(外语、译音),或也可以用做排版的斜体文字。
  • code:定义计算机代码文本。
  • q(quote 的缩写):用于定义一段引用的内容(短内容)
    -cite :用于定义引用内容出自书籍或杂志等的标题,不允许其他信息,如作者,日期等。
  • u (underline 的缩写):定义下划线文本
    -abbr (abbreviation 的缩写):定义一个缩写文本,建议在 abbr 的 title 属性中描述缩写的全称
  • dfn (defining instance 的缩写):用于定义一个术语
  • var :定义计算机代码中的变量
  • samp (sample 的缩写):由程序输出的示例文本
  • kbd (keyboard 的缩写):定义由键盘输入的文本
  • wbr (word break)的缩写:定义换行的时机
  • span :没有任何语义
  • br :定义一个换行符

文本字体元素标签使用注意:

  • 在下面这些元素都不适合的时候:表重要的 strong ,表强调的 em ,表标题的 h1–h6,表高亮或标记文本的 p 等,就用 b 来表示。
  • em 的强调是用在语句某个单词上来改变句子的侧重,可以说是局部的,而strong 和局部还是全局无关,局部强调用strong也可以,strong强调的是重要性,不会改变句意。

###分组元素标签
我们熟悉的div、 p 、dl 、dt、dd、ol、ul、li、hr都是分组元素标签,我们接下来看一些不常用的和新加的分组元素标签

  • blockquote:标记一段长引文。标记短引文(行内引文),应采用 q 元素!
  • pre:pre 元素可定义预格式化的文本。被包围在 pre 元素中的文本通常会保留空格和换行符。而文本也会呈现为等宽字体。pre 标签的一个常见应用就是用来表示源代码。他跟code的关系好比blockquote和q的关系。
  • ol元素
    ol元素在HTML5有改良,增加了两个属性:

    • start:start属性用来定义列表编号的起始位置,
    • reversed:reversed属性表示将列表进行反转,但是目前还没有任何一款浏览器对其提供支持,在这里就不细说了。
  • figure元素与figcaption元素
    figure元素用来包含一块独立内容,该内容如果被移除掉不会对周围的内容有影响。具体来说它可以用来表示图片,统计图,图表,音频,视频,代码片段等。如果需要你也可以给该内容添加一个标题,这个标题使用figcaption来表示。figcaption只能作为figure元素的子元素,可以放在figure元素内的任何位置。形如:

    <figure>
        <img src="" alt="" />
        <figcaption>html5jscss前端网是刚建立的小站</figcaption>
    </figure>
    

不是所有图片都用figure来包裹,img 标签也有语义的。如果纯粹只是为了呈现的图,也不在文档其他地方引用,那就绝对不要用figure。如果和上下文有关,也可以把它移动到附录,那就别用figure,aside可能适合。
figure元素和aside元素看起来表达的内容差不多,但是aside所能包含的内容比figure要广。当你不知道如何选择的时候可以这样来做:这段内容对周围的内容来说是一个要点,或者很重要,不可少,那么可以使用figure,否则使用aside。
注意:

  • 一个figure元素内最多只允许放置一个figcaption元素,也可以不放,但是其他元素可无限放置。注意不是所有图片都得用figure元素。

嵌入元素标签

在页面中除了显示文档活字符外,还需要放入一些其他元素,就是我们所说的嵌入元素。
嵌入元素包括img(图片),页面(iframe),多媒体对象将不再全部绑定在 object 或 embed 标签 中,而是由有 video(视频)audio(音频),用于绘画的 canvas 元素
这里我们不详细介绍它们的属性了.
HTML5中增加了一些表单元素和一些交互元素等新的标签,但是着重点不同,所以我们放在另一片文章来继续了解。HTML5语义标签到此结束。

原文链接

文档元素的几何形状以及位置判定

元素的位置是以像素来度量的,向右代表X坐标增加,向下代表Y坐标增加,但是有两个不同的点作为坐标系的原点,元素的X和Y坐标可以相对于文档的左上角,或者相对于其中文档视口的左上角.

“视口”是我们人眼看到的页面,只是实际显示文档内容的一部分:他不包括浏览器的外壳,(如菜单,工具条,标签页等),另一个是文档坐标,他的原点是页面的左上角,不随着页面的滚动发生变化,而视口坐标系的原点位置相对浏览器窗体是不发生变化的,当页面中没有滚动条时候,视口坐标系原点与文档坐标系原点重合的。然后如果存在滚动条的话。向下滚动页面,则某一元素的文档坐标是不发生变化的,视口的Y坐标变小。同理向右滚动的话,元素相对时候X坐标变小。

文档坐标比视口坐标更加基础,并且不随着用户滚动页面而发生变化,当使用CSS指定元素位置是使用了文档坐标吗,但是客户端编程中视口坐标是非常常见的,简单的查询元素在显示页面中位置方法是返回视口坐标系的位置。

为了再坐标系之前进行互相转换,我们需要判定浏览器窗口滚动条的位置,windows对象的pageXOffset和pageYOffset,属性在所有浏览器中提供了这些值除了IE8 以及更低版本的浏览器,不过可以使用scrollleft和scrollTop属性来获取滚动条的位置,正常情况下使用document.documentElemt来获得,在怪异模式下使用document.body对象来获得。下面封装了一个获取浏览器中滚动条位置的方法,并且兼容所有的浏览器

获得浏览中滚动条的位置

function getScrollOffset(w){
            w=w||window;
            if(w.pageXOffset)return {
                x:w.pageXOffset,
                y:w.pageYOffset
            }
        var d=w.document;
        if(document.compatMode=='CSS1Compact'){
            return {x:d.document.scrollLeft,y:d.document.scrollTop}
        }

        return {
            x:d.body.scrollLeft,
            y:d.body.scrollTop
        }
};

查询窗口视口的尺寸,确定当前文档中哪些部分是可见的。

function getViewportSize(w){
    w=w||window;
    //ie8+
    if(w.innerWidth !=null)return{w:w.innerWidth ,h:w.innerHeight}
     //ie标准模式以及其他浏览器
        var d=w.document;
    if(document.compatMode=='CSS1Compact'){
        return {
            w:d.document.clientWidth,
            h:d.document.clientHeight
        }
    }
    // 怪异模式下的浏览器
    return{
        w:d.body.document.clientWidth,
        h:d.body.document.clientHeight
    }

}

查询元素的尺寸

判定一个元素位置最简单的方法是调用他的getBoundingClientRect()方法,该方法是在IE5中引入的,而现在当前的浏览器中都实现了,返回一个有left、right、top 、bottom 属性的对象。left,top表示左上角的坐标,right、bottom表示右下角的坐标。这个方法返回的是元素在视口坐标中的位置。为了转化为相对文档文档坐标需要加上滚动的偏移量。通过上面的getScrollOffset(w)获取滚动条的位置。

var box=e.getBoundingClientRect();
var offsets=getScrollOffset();
var x=box.left;
var y=box.top;

很多浏览器中还可以获得width和height属性但是IE中未实现。getBoundingClientRect()返回的值包括内边距和边框,但是不包含外边距。
使用elementFromPoint查询视口中指定位置有什么元素。参数为视口坐标系下的x,y坐标

任何HTML元素的只读属性offsetWidth 和offsetHeight以CSS像素返回他的屏幕的尺寸,返回的尺寸包括元素的边框和内边距,不包括外边距。所有的HTML元素用有OffsetLeft和offsetTop属性来返回元素的X和Y坐标,这些值都是文档坐标。对于已经定位的元素的后代和一些其他的元素,这些属性返回是相对于祖先元素而非文档,offsetParent指定这些元素相对的父元素,如果offsetParent为null这些属性都是文档坐标,一般来说用offsetLeft和OffsetTop来计算元素e的位置需要一个循环

function getElmentPosition(e){
    var x=0,y=0;
    while(e){
        x+=e.offsetLeft;
        y+=e.offsetTop;
        e=e.offsetParentl
    }
    return{
        x:x,
        y:y
    }
}

所有HTML元素定义了如下与位置相关的属性。

offsetwidth clientWidth scrollWidth
offsetHeight clientHeight scrollHeight
offsetLeft clientLeft scrollLeft
offsetTop clientTop scrollTop
offsetParent

offsetHeight、offsetwidth包含内边距和边框、clientWidth、clientHeight不包含边框,只包含内容和内边距。scrollWidth、scrollHeight内容+内边距+任何内容溢出的尺寸。其中scrollLeft、scrollTop指定滚动条的位置。当文档中包含滚动条且有内容溢出时上面的getElmentPosition(e) 不在起作用了,因为没有把滚动条考虑进去。offsetLeft offsetTop为文档坐标包含了滚动条的位置 修改版本如下

function getElementPos(elt){
    var x=0,y=0;
    for(var e=elt;e!=null;e=e.offsetParent){
        x+=e.offsetLeft;
        y+e.offsetTop;
    }
    //offsetLeft offsetTop为文档坐标包含了滚动条的位置,再次循环所有的祖先元素,
    //减去滚动条的偏移量,并转换为视口坐标
    for(var e=elt.parentNode;e!=null&&e.nodeType==1;e=e.parentNode){
        x-=e.scrollLeft;
        y-=e.scrollTop;
    }
    return {
            x:x;
            y:y
    }
}
  • 文档的高度 document.body.offsetHeight
  • 视口的高度 window.innerHeight
  • 滚动条滑动的高度 window.scrollY

javascript valueOf方法

如果将对象用于Javascript的关系比较运算符,比如<<=,javascript会首先调用对象的valueOf方法,如果这个方法返回一个原始值,则直接比较原始值。定义一个类Person

function person(age,name){
    this.age=age;
    this.valueOf=function(){
        return this.age;
    }
}

然后新建两个Person的实例。

var person1=new person(12,'张三');
var person2=new person(13,'李四');
console.log(person1<person2) //true
console.log(person1>person2)//false

如果构造函数没有valueOf方法,以上对象无轮如何比较都是输出false
此外在对两个对象求和的话,也会尝试调用valueOf方法

比如
var person1=new person(12,’张三’);
var person2=new person(13,’李四’);
console.log(person1+person2) //25

当然如果构造函数没有valueOf方法,则会对象会先自动调用的toString方法。。默认情况下对象使用的是Object的toString方法的话则输出[object Object];我们也可以重写toString方法。

function person(age,name){
    this.age=age;
    this.name=name;
    this.toString=function(){
        return this.name;
    }
}

var person1=new person(12,'张三');
var person2=new person(13,'李四');
console.log(person1+person2);//张三李四。

如果一个构造函数中同时重写了valueOf和toString的话则只调用valueOf返回的结果参与运算.如下

function person(age,name){
    this.age=age;
    this.valueOf=function(){
        return this.age;
    }
    this.toString=function(){
        return this.name;
    }
}

var person1=new person(12,'张三');
var person2=new person(13,'李四');
console.log(person1+person2);//25

Media Queries

媒体查询在CSS2中就有了,CSS3中得到了进一步增强,简单来说我们可以设置不同类型的媒体条件,并根据对应的条件,给相应符合条件的媒体调用相对应的样式表,说白了就是就是根据设备当前本身的环境(比如屏幕的长宽,设备的种类等)来对元素应用响应的CSS文件,但是所有的CSS 文件总是要下载到本地的。

引入方式

  • link方法引入

    <link rel="stylesheet" type="text/css" href="../css/print.css" media="print" />
    
  • xml方式引入

    <?xml-stylesheet rel="stylesheet" media="screen" href="css/style.css" ?>
    
  • @import方式引入

    @import url("css/reset.css") screen;
    
  • @media引入

    @media screen{
         选择器{
        属性:属性值;
         }
       }
    

如何定义查询条件

媒体类型包括如下几种

  • all 所有设备可用
  • braille 盲文
  • embossed
  • handheld
  • print 打印
  • projection 投影
  • screen 显示器
  • speech
  • tty 电传打字机
  • tv 电视

最大宽度Max Width,max-height,max-width

<link rel="stylesheet" media="screen and (max-width:600px)" href="small.css" type="text/css" />

也可在style 标签或者单独的CSS文件里面:

@media only screen and (max-device-width: 480px) {
        div#wrapper {
            width: 400px;
        }

        div#header {
            background-image: url(media-queries-phone.jpg);
            height: 93px;
            position: relative;
        }

        div#header h1 {
            font-size: 140%;
        }

        #content {
            float: none;
            width: 100%;
        }

        #navigation {
            float:none;
            width: auto;
        }
    }

最小宽度Min Width min-width,min-height

<link rel="stylesheet" media="screen and (min-width:900px)" href="big.css" type="text/css"  />

and not only关键字

多个Media Queries使用查询取交集
<link rel="stylesheet" media="screen and (min-width:600px) and (max-width:900px)" href="style.css" type="text/css" />
not用于排除符合表达式的设备。
<link rel="stylesheet" media="not print and (max-width: 1200px)" href="print.css" type="text/css" />
only用来定某种特定的媒体类型
<link rel="stylesheet" media="only screen and (max-device-width:240px)" href="android240.css" type="text/css" />

Device Width设备屏幕的输出宽度、即是设备的实际分辨率,也就是指可视面积分辨率、可以使用

max-device-width、min-device-width

orientation 横屏或者竖屏

device-pixel-ratio 设备的宽高比min-device-pixel-ratiomax-device-pixel-ratio

resolution 分辨率 min-resolution max-resolution

可以使用设备的宽高比,输出的最大最小宽度来判断设备的类型,甚至是具体的某一款设备。比如如下
使用media query为android手机在不同分辨率提供特定样式,这样就可以解决屏幕分辨率的不同给android手机的页面重构问题。

/*240px的宽度*/
 <link rel="stylesheet" media="only screen and (max-device-width:240px)" href="android240.css" type="text/css" />
 /*360px的宽度*/
 <link rel="stylesheet" media="only screen and (min-device-width:241px) and (max-device-width:360px)" href="android360.css" type="text/css" />
 /*480px的宽度*/
 <link rel="stylesheet" media="only screen and (min-device-width:361px) and (max-device-width:480px)" href="android480.css" type="text/css" />。

总结:media query 就是让我们根据屏幕的大小来对HTML元素应用适合当前屏幕的样式,能够在不同尺寸的屏幕,甚至是不同的设备上达到较好的用户体验。

ECMAScript 5 学习总结

话说ES6的草稿都出来了,貌似好多人对ES5 还没有全面的了解,下面将我学习的关于ES5的一些东西总结一下。
ECMAScript 5.1(或者成为ES5 、ECMAScript 5),在2009年发布草稿,2011发布正式版本,最初在2011年发布的Firefox 4上得到支持。但是万恶的IE(6、7、8) 并不支持ES5,因此这也一定程度上阻止了ES5的普及。但是我们可以通过ployfill的形式来让IE8支持ES5的一些功能,比如引入shim;

浏览器对ES5的支持情况。

ES5出现以前,用的最多的是ES3(ES4 流产了). 总体上当今主流的浏览器都已经支持了ES5.比如常见的ie9+,chrome 19+,safari5+,firefox4+,opera 12+,android 3+,Blackberry Browser 7+,IOS safari 5+,opera mobile 12+,ie mobile 10+,例外是IE 9不支持ES 5.1的严格模式,IE10 已经支持。Safari 5.1+在严格模式下不支持0宽字符,比如var $\u200c = 'a' 或者{_\u200d: 'vuur'}.IE8 是ES3的脚本引擎,但是支持ES5的一些特性,比如JSONObject.defineProperty,Object.getOwnPropertyDescriptor,然而 我们最好还是要把IE8 称为ES3的浏览器。当然如果对于不支持ES 5的浏览器可以使用shim 来进行扩展,以提供支持。下面开始描述ES 5的那些东西。

数组或者是对象中的最后元素允许添加逗号。

var myObject = {
    foo:'foo',
    bar:'bar', //no error
};

var myArray = [1,2,3,];

console.log(myArray.length) //logs 3, regardless of trailing comma 

使用\ 分割来实现多行字符串

//no error in ES5 scripting engines
var stringLiteral = "Lorem ipsum dolor sit amet, consectetur \ 
elit, sed do eiusmod tempor incididunt ut labore et dolore \
magna aliqua. Ut enim ad minim veniam, quis nostrud \
exercitation ullamco laboris nisi ut aliquip ex ea";

对象属性的名字允许使用限定字符。

var myObject = {function:'function',new:'new'};

console.log(myObject.function,myObject.new); //logs 'function new'

处理JSON 的方法 JSON.parse JSON.stringify

原生的字符串去空格方法string.trim()

ES 5 提供String.trim()来去除字符串首尾的空格。

'   foo   '.trim(); // 'foo'

需要关注的是,有些浏览器已经提供了 trimRight(),trimLeft(),但是这并不是正式的标准。

通过[i]来访问字符串中的字符。

'ES5'[1]; //  "S"

ES3中 是不允许这种方式来进行访问的

undefined,NaN 以及Infinty是只读的常量。

在ES5 之前的版本中这三个变量是可读写的。于是可能给undefined赋值,这样undefined,就不是真的undefined了。

数组相关

判断数组类型的最佳方法:Array.isArray([])

####Array.prototype 新增的方法。

  • Array.prototype.every()
  • Array.prototype.filter()
  • Array.prototype.forEach()
  • Array.prototype.indexOf()
  • Array.prototype.lastIndexOf()
  • Array.prototype.map()
  • Array.prototype.reduce()
  • Array.prototype.some()

同时也可以在字符串以及类数组中使用这些方法,比如

//在字符串中使用
[].forEach.call('ABC',console.log);

//argument  
var myFunction = function(a,b,c){
    [].forEach.call(arguments,console.log);
};
myFunction(1,2,3);

为数组的 forEach(), every(), some(), filter(), map()中的回调函数指定this(上下文);这几个函数的第三个参数即callback中的this对象,下面代码中我设置了一个 arrayLikeObject 对象,作为forEach Callback的this。

var arrayLikeObject = {0:'f',1:'o',2:'g',length:3};

[].forEach.call(arrayLikeObject,function(item){

    // this = arrayLikeObject
    console.log(item + ' total: ' + this.length);

},arrayLikeObject); //注意第三个参数 传递了也是arrayLikeObject

属性访问器 getter setter

var myObject = {
    //name:'', WOULD CAUSE ERROR
    get name() { //notice use of get to indicate accessor property 
        console.log('read name');
    },
    set name(value) { //notice use of set to indicate accessor property
        console.log('wrote to name the value: ' + value);
    }

};

myObject.name = 'codylindley'; //调用 set 
myObject.name; //调用get

对象属性的配置项

ES5中新的特性让对象的属性具有可只读readable,可只写writable、可配置性configurable,可遍历enumerable,通过Object.getOwnPropertyDescriptor() 可以查看特性的描述信息。

var accessor = {
    get name(){},
    set name(){}
};

var data = {name:'Cody Lindley'};

//logs {get: function, set: function, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(accessor,'name'));

//logs {value: "Cody Lindley", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(data,'name'));

默认情况下Object.defineProperty() Object.defineProperties()writable: true, enumerable: true, configurable: true。如果是通过属性访问器来定义的属性 默认特性为 enumerable: true, configurable:true

####新的 定义/修改对象的语法
通过Object.defineProperty() 以及 Object.defineProperties()两个函数来定义对象的属性以及属性的特性。下面是通过Object.defineProperty()为data对象定义两个属性agename.

var data = {}; //create data object
Object.defineProperty( //在data 对象上定义属性age
    data,
    "age", 
    {
        value: 38,//配置属性的特性 包括value writable enumerable configurable
        writable: true,
        enumerable: true,
        configurable: true
    }
);

var accessor = {}; 
Object.defineProperty( //以get set的形式来定义属性 name
    accessor,
    "name", 
    {
        get: function () {},
        set: function (value){},
        enumerable: true,
        configurable: true
    }
);

//{value: 38, writable: true, enumerable: true, configurable: true} 
console.log(Object.getOwnPropertyDescriptor(data,'age'));

//{get: function, set: function, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(accessor,'name'));

与上不同的是Object.defineProperties() 可以同时定义多组属性

var cody = {}; //
Object.defineProperties( //定义两个属性
    cody, 
    {
        "age": {
            value: 38,
            writable: true,
            enumerable: true,
            configurable: true
        },
        "name": {
            get: function(){},
            set:function(value){},
            enumerable: true,
            configurable: true
        }
    }
);

//{value: 38, writable: true, enumerable: true, configurable: true} 
console.log(Object.getOwnPropertyDescriptor(cody,'age'));

// {get: function, set: function, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(cody,'name'));

注意 通过Object.defineProperty() 以及Object.defineProperties()定义的属性默认配置为writable: false, enumerable: false, configurable: false.定义的访问器属性默认配置enumerable: false, configurable:false

使用Object.keys 以及Object.getOwnPropertyNames()获取对象的属性的name。

Object.keys 以及Object.getOwnPropertyNames()用来获取对象中的属性的name,不包括继承来的属性,两者区别是Object.keys 只能获取可遍历的属性的名字的数组,Object.getOwnPropertyNames()可以获得所有的属性的名字,作为字符串数组返回。

var person = {};
Object.defineProperties(person, 
    {
        "name": {value: 'Cody Lindley',enumerable: true},
        "age": {value: 38,enumerable: false}
    }
);

//只返回可以可遍历的属性 
console.log(Object.keys(person)); //logs ["name"]

//return array of all properties, including ones that are non-enumerable
console.log(Object.getOwnPropertyNames(person)); //returns ["name", "age"]

属性保护 extending、 sealing、freezing。

在ES5中 对象可以被设置为non-extensible, sealed, 以及 frozen。这是三种不同的属性保护级别,可以通过Object.preventExtensions(myObject), Object.seal(myObject), Object.freeze(myObject)来进行设置。

  • Object.preventExtensions() 让对象无法新增属性。
  • Object.seal()包括了Object.preventExtensions()的功能,同时还具有让已经存在的属性不可修改配置也就说不能使用Object.defineProperty以及Object.defineProperties 来修改属性的配置,但是修改属性的值依然是可以修改的。
  • Object.freeze() 包括了Object.preventExtensions(),Object.seal()的功能,同时为对象的所有数据属性将 writable 特性设置为 false。 当 writable 为 false 时,无法更改数据属性值。(如果 属性值是对象的话,还是可以改变的)

    var  p={
                user:"kunkun"
            }
    Object.seal(p);
    p.name='du';
    console.log(p.name);//undefined 并没有增加
    Object.freeze(p);
    p.user='baokun'
    console.log(p.user);// 输出kunkun 还是原来的值发现并没有被修改
    

同时也提供三个函数来对这三种保护级别进行判断

  • Object.isExtensible()
  • Object.isSealed()
  • Object.isFrozen()

使用Object.create()显式继承。

在ES3中创建对象的方式主要有以下三种

  • var objectViaObjectLiteral = {};
  • var objectViaObjectConstructor = new Object();
  • var objectViaCustomConstructor = new(function Person(){});

ES5中新增了Object.create函数来让开发者现实地设置对象以及对象继承的原型。第一个参数为对象的原型

var object = Object.create(Object.prototype); //创建对象 与{} 、 new Object()功能相同。

object.create的主要作用继承指定的对象来创建新的对象,如果不传递参数,则默认值为Object.prototype。如果传递null 表示对象将会不继承于任何东西,则创建一个真正的空对象

var person = {alive: true};
var cody = Object.create(person, {
    name: {
        configurable: true,
        enumerable: true,
        writeable: true,
        value: 'cody'
    }
});

console.log(cody.alive); // true

//
console.log(Object.getPrototypeOf(cody).alive); //logs true

上面的例子中,可以看到create也传递了第二个参数来为对象增加属性,第二个参数与Object.defineProperties()结果是一样的。

使用getPrototypeOf() 来获取对象的原型。

ES3中有个非标准的proto 来获取对象的原型金,浏览器支持不兼容,ES5中有了标准化。

Object.getPrototypeOf(new Object('foo')) === String.prototype // true

bind :为函数绑定上下文。

在ES3中通过Apply或者call来实现 比如

Function.prototype.bind = function(obj) { 
   var method = this, 
   temp = function() { 
     return method.apply(obj,arguments); 
   }; 

   return temp; 
} 

ES 5中有了正式的bind

var myObject = {foo:'foo'};
var myFunction = function(){
    console.log(this,arguments[0],arguments[1],arguments[2]);
};
var usingBind = myFunction.bind(myObject,1,2,3); 
usingBind(); // {foo="foo"} 1 2 3

use strict 严格模式

JavaScript代码标志为“严格模式”,则其中运行的所有代码都必然是严格模式下的。
其一:如果在语法检测时发现语法问题,则整个代码块失效,并导致一个语法异常。
其二:如果在运行期出现了违反严格模式的代码,则抛出执行异常。

  • 主要规则
  • 定义变量必须带var 、
  • 不能在JSON定义重复的key、
  • 函数不能有重复的参数、
  • 不能改变arguments的值

underscore学习总结

underscore介绍

underscore是一个很小很强大的函数库,帮助程序猿不用扩展内置的JS对象即可实现一系列常用的功能。对于“如果我面前是一个空白的HTML 页面,我想想立刻开发出网页,我需要做什么”这样的问题,underscore给出了答案。

underscore 提供了80多个 工具函数,来提供了常见的功能。比如map ,select,invoke,以及更专业的助手 函数绑定,javascript模板,深度相等测试。如果当今流行的浏览器中如果已经存内置方法,他会优先调用浏览器原生的方法比如ES5中新增的forEachmapreducefiltereverysome, indexOf 等。

underscore的函数主要包含了Collections,Arrays,Functions,Object,Utility,Chaining 等6块内容。对开发者来说是个很强的轮子。

underscore如何使用

相关文档

帮助文档

带注释的源码

Github;

获取方法:

开发环境版本 未压缩

生产环境版本 经过压缩混淆

也可以使用工具安装的方式来获取

  • Node.js npm install underscore
  • Require.js require([“underscore”], …
  • Bower bowser install underscore
  • Component component install jashkenas/underscore

使用Demo

之前使用过Jquery的时候我们学会了用$,使用underscore也同样的容易,只需要一个下划线_即可,
比如

_.each([1, 2, 3], alert);
=> alerts each number in turn...
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...

看到函数名字基本上就能猜到功能了,为了方便全面了解功能,这里仅列出函数的名字,仅对不熟悉的做一下解释,个别函数值列出了源码,其实看源码能学到更多。

Collections(数组,对象以及类数组可以调用的方法)

  • each
  • map
  • reduce
  • reduceright
  • find
  • filter
  • every
  • some 以上几个都是ES5 中的东东 就不在介绍了
  • where:选出所有的符合条件的
  • findWhere:只返回第一个符合条件的元素
  • reject 筛选出不符合条件的
  • contains
  • invoke依次传入集合中的方法,来调用一个函数
  • pluck 提取某个字段的集合
  • max 根据集合中的某一属性或者对其操作的结果,提取结果最大的元素。如果第二个参数省略,则根据数组中值得大小进行比较。比如

    var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
    _.max(stooges, function(stooge){ return stooge.age; });
    => {name: 'curly', age: 60};
    
  • min 根据集合中的某一属性或者对其操作的结果,提取结果最小的元素。

  • sortBy
  • groupBy
  • countBy
  • indexBy 给集合添加索引
  • shuffle打乱集合元素的顺序
  • sample从数组中随机子数组
  • toArray。将集合转化为数组

####Array Functions

  • first
  • initial 返回前几个元素比如

    `_.initial([5, 4, 3, 2, 1]); => [5, 4, 3, 2]`
    
  • last

  • rest
  • compact 返回一个数组的拷贝,其中不包括值为false的元素 比如

    _.compact([0, 1, false, 2, '', 3]);
    => [1, 2, 3]
    
  • flatten,把嵌套数组中的元素提取出来做为数组的元素。如果第二个参数为true 仅进行浅提取。比如

    _.flatten([1, [2], [3, [[4]]]]);
    => [1, 2, 3, 4];
    
    _.flatten([1, [2], [3, [[4]]]], true);
    => [1, 2, 3, [[4]]];
    
  • without

  • partition 将一个数组分组,其中的元素第一个满足第二个参数,第二个是不满足的
  • union 求数组的并集
  • intersection 交集
  • difference 差集
  • uniq 去掉数组中重复的元素
  • zip 看Demo

    _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
    => [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
    
  • object 把数组转为对象。

    _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
    => {moe: 30, larry: 40, curly: 50}
    
    _.object([['moe', 30], ['larry', 40], ['curly', 50]]);
    => {moe: 30, larry: 40, curly: 50}
    
  • indexOf

  • `lastIndexOf
  • sortedIndex
  • range 产生一个连续的数组

Functions

  • bind 将函数绑定到具体的对象,并且可以绑定参数

    var func = function(greeting){ return greeting + ': ' + this.name };
    func = _.bind(func, {name: 'moe'}, 'hi');
    func();
    => 'hi: moe'
    
  • bindAll 同时绑定对象的方法,只需要指定相应的方法即可

    var buttonView = {
      label  : 'underscore',
      onClick: function(){ alert('clicked: ' + this.label); },
      onHover: function(){ console.log('hovering: ' + this.label); }
    };
    _.bindAll(buttonView, 'onClick', 'onHover');
    // When the button is clicked, this.label will have the correct value.
    jQuery('#underscore_button').bind('click', buttonView.onClick);
    
  • partial 绑定部分的参数。返回一个函数

    var add = function(a, b) { return a + b; };
    add5 = _.partial(add, 5);
    add5(10);
    => 15
    
  • memioze 缓存计算结果。

  • delay 延迟执行,类似于setTimeOut
  • defer也是延迟执行方法,不同的是他能保证在当前堆栈中的所有的代码跑完之后再执行function。其实就是setTimeout(fn,0);
  • throttle throttle这个单词的意思是使减速,用于控制频繁触发的 function的的频率,比如,拖动页面滚动条时scroll方法会以很高的频率触发,如果在scroll的处理事件中做了很费时的操作,会导致浏览器假死,如果使用了throttle后,function被触发的频率可以降低。

    var throttled = _.throttle(updatePosition, 100);
    $(window).scroll(throttled);
    
  • debounce 对于频繁处理的时间,只在第一次触发(是否触发取决于immdiate 参数),和事件频繁触发最后一次触发(有最多wait的延时)。拿滚动事件为例,滚动事件50ms触发一次,如果设置wait为100ms。则在最后一次触发scroll事件时,也就是停止滚动时,在100ms后触发function。如果immediate参数为true,开始滚动时也会触发function

    var lazyLayout = _.debounce(calculateLayout, 300);
    $(window).resize(lazyLayout);

  • once once能确保func只调用一次,如果用func返回一个什么对象,源码也比较简单,无非就是用一个标志位来标示是否运行过,缓存返回值
  • after 创建一个新的函数,当func反复调用时,count次才调用一次,比如:

    var afterA = _.after(3,a);
    afterA();//调用
    afterA();//不alert
    afterA();//不alert
    afterA();//调用

  • now 返回当前的时间戳 _.now = Date.now || function() { return new Date().getTime(); };

  • wrap
  • compose

####Objects

  • keys 返回 对象的key的数组

    _.keys({one: 1, two: 2, three: 3});
    => [“one”, “two”, “three”]

  • values 返回对象的value数组

    _.values({one: 1, two: 2, three: 3});
    => [1, 2, 3]

  • pairs 转为[key,valu]的集合

    _.values({one: 1, two: 2, three: 3});
    => [1, 2, 3]

  • invert 将 key和value反转

  • functions返回对象中方法的集合
  • extend 扩展对象的属性。

    _.extend({name: ‘moe’}, {age: 50});
    => {name: ‘moe’, age: 50}

  • pick 筛选字段,只选满足传入的key的字段

    _.pick({name: ‘moe’, age: 50, userid: ‘moe1’}, ‘name’, ‘age’);
    => {name: ‘moe’, age: 50}

  • omit 与上面相反

  • defaults
  • clone
  • tap 对象的拦截器,用于在对象方法链中,调试对象
  • has
  • matches
  • property

    var moe = {name: ‘moe’};
    ‘moe’ === _.property(‘name’)(moe);
    => true

  • isEqual 深度比较是否相等

    var moe   = {name: 'moe', luckyNumbers: [13, 27, 34]};
    var clone = {name: 'moe', luckyNumbers: [13, 27, 34]};
    moe == clone;
    => false
    _.isEqual(moe, clone);
    => true
    
  • isEmpty 判断对象是否为{}

    _.isEmpty([1, 2, 3]);
    => false
    _.isEmpty({});
    => true
    
  • isElement 判断是否为dom 元素

    _.isElement = function(obj) {

      return !!(obj && obj.nodeType === 1);
    };
    
  • isArray

  • isObject
  • isArguments
  • isFunction
  • isString
  • isNumber
  • isDate
  • isRegExp
    以上就不解释了,看源码吧

     each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
      _['is' + name] = function(obj) {
        return toString.call(obj) == '[object ' + name + ']';
      };
    });
    
  • isFinite 是否为有限数

    _.isFinite = function(obj) {
      return isFinite(obj) && !isNaN(parseFloat(obj));
    };
    
  • isBoolean 是否为bool值

    _.isBoolean = function(obj) {
      return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
    };
    
  • isNaN 注意typeof(NaA)为number

    _.isNaN = function(obj) {
      return _.isNumber(obj) && obj != +obj;
    };
    
  • isNull

    _.isNull = function(obj) {
        return obj === null;
      };
    
  • isUndefined

    _.isUndefined = function(obj) {
       return obj === void 0;
     };
    

####UTILITY FUNCTIONS

  • noConflict 这个 与jQuery中的类似,将_ 还原为之前代表的意思,以后使用

    var underscore = _.noConflict();

    _.noConflict = function() {
      root._ = previousUnderscore;
      return this;
    };
    
  • identify 返回用作参数的相同值。数学 f(x) = x、这个函数看着没有什么用途,但使用整个Underscore作为默认的迭代器

    _.identity = function(value) {
       return value;
     };
    
  • constant。创建一个返回与传入参数相同值得函数

    _.constant = function(value) {
        return function () {
          return value;
        };
      };
    
  • times 调用给定的迭代函数n次

     _.times = function(n, iterator, context) {
       var accum = Array(Math.max(0, n));
       for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
       return accum;
     };
    _(3).times(function(n){ dosomething });
    
  • radom 返回随机数

    _.random = function(min, max) {
      if (max == null) {
        max = min;
        min = 0;
      }
      return min + Math.floor(Math.random() * (max - min + 1));
    };
    
  • mixin 扩展underscore中的方法

    _.mixin({
      capitalize: function(string) {
        return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
      }
    });
    _("fabio").capitalize();
    => "Fabio"
    
  • uniqueId 为一个对象生成一个唯一的ID 可以自己加前缀

  • escape转义HTML字符串,替换&, <, >, “, ‘, /字符 替换为&, <, >, ", &#x27

    _.escape('Curly, Larry & Moe'); 
    => "Curly, Larry &amp; Moe" 
    
  • unescape 与上相反 替换 &, <, >, ", ' 替换为&, <, >, “, ‘, /

  • result _.result(object, property) 如果第二个参数是函数的话则调用这个函数,并将第一个参数作为函数的上下文,否则返回object[property]
  • template javascript模板编译函数使用<%= … %> 替换变量,<% … %>执行JS代码, <%- … %>让HTML被转义。

####Chaining
可以根据自己的喜好决定是函数式编程还是采用面向对象的方式来使用underscore,比如下的两种方式

_.map([1, 2, 3], function(n){ return n * 2; });
_([1, 2, 3]).map(function(n){ return n * 2; });

value 提取出_(obj)对象的值。比如

_([1, 2, 3]).value();
=> [1, 2, 3]

####OOP
如果_作为函数被调用的话,会返回一个包装的好的对象,这个对象拥有当前版本Underscore的所有方法。同时这个对象还可以通过调用chain实现对一个对象的包裹

链式调用

var lyrics = [
  {line: 1, words: "I'm a lumberjack and I'm okay"},
  {line: 2, words: "I sleep all night and I work all day"},
  {line: 3, words: "He's a lumberjack and he's okay"},
  {line: 4, words: "He sleeps all night and he works all day"}
];

_.chain(lyrics)
  .map(function(line) { return line.words.split(' '); })
  .flatten()
  .reduce(function(counts, word) {
    counts[word] = (counts[word] || 0) + 1;
    return counts;
  }, {})
  .value();
=> {lumberjack: 2, all: 4, night: 2 ... }

chain 的源码

_.chain = function(obj) {
    return _(obj).chain();
  };

同时下面还为_原型增加了方法

_.extend(_.prototype, {
  chain: function() {
    this._chain = true;
    return this;
  },
  value: function() {
    return this._wrapped;
  }
});

上面的例子中开始调用.chain(lyrics),是调用的 .chain(obj)。然后经过_(obj) 返回一个示例。接下来调用的是原型上的方法chain 将 this.chain = true; 然后返回this 这样就可以进行链式调用的,第一次调用的对象的chain,第二次调用的是_函数的原型对象的方法。接下来是一句神奇的代码

_.mixin(_);

然后调用了 mixin为把中的所有方法都赋给了.prototype.于是经过包装的对象都是经过 new (obj)的,具有了_对象的中的方法

mixin的源码 ,将传入对象的方法都添加到.prototype上

_.mixin = function(obj) {
  each(_.functions(obj), function(name) {
    var func = _[name] = obj[name];
    _.prototype[name] = function() {
      var args = [this._wrapped];
      push.apply(args, arguments);
      return result.call(this, func.apply(_, args));
    };
  });
};

看看执行_()发生了什么,回到源码开头

var _ = function(obj) {
   if (obj instanceof _) return obj; //如果传入的对象是 _的实例
   if (!(this instanceof _)) return new _(obj); // 如果不是通过new _()的,则new new _(obj) 一个实例继续调用
   this._wrapped = obj;// 传入其他参数 new 实例的时候传入的参数
 };

这是一个单例模式,通过创建一个underscore对象,如果以包裹的形式来调用的话。会将包裹的对象设置为内部的_wrapped变量。

git账户配置以及多账户配置

在使用git的时候,git与远程服务器是一般通过ssh传输的(也支持ftp,https),我们在管理远程分支之前 需要在本机上创建ssh-key密钥对,并把其中的公钥添加到github中。

单用户情况

如果你就会一直在你的计算计算机使用一个远程的Git服务器,并且账号是一个,比较简单,生成key的时候也没有太大注意的地方,直接运行如下的第一步然后按回车就可以了
1、在 gitbash上运行 ssh-keygen -t rsa -C “Github账户邮箱”
2、接下来会提示输入key的名字 默认名字为id_rsa .默认就行了
3、然后会提示输入口令,这里口令与Github中的密码无关,随便输入可以为空。

  1. 如果在第二步中的没有重新命名的话,则忽略此步骤,ssh agent默认只读取id_rsa,为了让SSH识别新的私钥,需将其添加到SSH agent中
    ssh-add id_rsa
    如果出现Could not open a connection to your authentication agent的错误,就试着先用以下命令:

    ssh-agent bash
    ssh-add id_rsa
    添加完之后 登陆Github 点击 网页右上侧的 Account Setting 按钮 - 选择 ssh-keys 点击Add SSH Key ,在title中输入名字,然后将公约即id_rsa.pub添加到ssh-key处。

在git bash的命令行中输入

ssh -T git@github.com 如果能正常访问即可

$ ssh -T git@github.com
Enter passphrase for key 'C:/Users/kunkun/.ssh/github.rsa':
Hi kunkun01! You've successfully authenticated, but GitHub does not provide shel
l access.

多账户配置

多账户又分为两种情况

  • 针对同一个服务器的同用户(比如 我平时开发开源的小东东,有的是一个账号是公司的账号对外开源项目用的,另外我自己也比较崇尚开源,所以自己也有了Github账号)
  • 针对不同服务器的用户(现在pass平台 部署应用都是通过git来管理的,比如常见的Openshift,Heroku appfog等,在这里我也注册了账号)

    在我们访问git服务器的时候,如果通过ssh的方式话,访问不同的服务器要使用不同的ssh-key。经过在第一步的过程中,在创建ssh-key的默认命名为id_rsa,如果使用不同的账户的,必须得给不同的key设置不同的名字,否则如果继续使用默认名字的话,会把之前的id_rsa覆盖掉。
    具体操作如下 user2是我的另外一个Github账户

    1、新建user2的SSH Key

    #新建SSH key:
    $ cd ~/.ssh # 切换到C:\Users\Administrator.ssh
    ssh-keygen -t rsa -C “mywork@email.com” # 新建工作的SSH key

    设置名称为id_rsa_work

    Enter file in which to save the key (/c/Users/Administrator/.ssh/id_rsa): id_rsa_work
    ####2、新密钥添加到SSH agent中
    因为默认只读取id_rsa,为了让SSH识别新的私钥,需将其添加到SSH agent中:

    ssh-add ~/.ssh/id_rsa_work
    上面提到了,如果出现Could not open a connection to your authentication agent的错误,就试着用以下命令:

    ssh-agent bash
    ssh-add ~/.ssh/id_rsa_work

    3、修改config文件 将账户以及git服务器与对应的密钥关联。在C:\Users\kunkun\.ssh目录下找到config文件,如果没有就创建名字为config的文本文件(无后缀名),然后修改如下: 比如我的config配置如下:

    该文件用于配置私钥对应的服务器

    Default github user(first@mail.com)

    Host github.com
    HostName github.com
    User git
    IdentityFile C:/Users/Administrator/.ssh/id_rsa

    second user(second@mail.com)

    建一个github别名,新建的帐号使用这个别名做克隆和更新

    Host github2
    HostName github.com
    User git
    IdentityFile C:/Users/Administrator/.ssh/id_rsa_work
    其规则就是:从上至下读取config的内容,在每个Host下寻找对应的私钥。这里将GitHub SSH仓库地址中的git@github.com替换成新建的Host别名如:github2,那么原地址是:git@github.com:kunkun/Mywork.git,替换后应该是:github2:kunkun/Mywork.git。

4、用记事本打开新生成的~/.ssh/id_rsa2.pub 和id_rsa_work 复制里面的内容、登陆Github网站,将里面的内容添加到分别加入对应的ssh keys中。

5、测试:

$ ssh -T git@github.com
Hi BeginMan! You've successfully authenticated, but GitHub does not provide shel
l access.

$ ssh -T github2
Hi BeginMan! You've successfully authenticated, but GitHub does not provide shel
l access.

克隆的时候将Github.com替换为对应的别名即可
比如我的第二个账户中的一个仓库地址为git@github.com:kunkun12/PiesLayer.git。但是我以上的配置中使用

git clone git@github2:kunkun12/PiesLayer.git

注意:如果你只是通过这篇文章中所述配置了Host,那么你多个账号下面的提交用户会是一个人,所以需要通过命令git config –global –unset user.email删除用户账户设置,在每一个repo下面使用git config –local user.email ‘你的github邮箱@mail.com’ 命令单独设置用户账户信息

判断浏览器特性

浏览器类型判断

有时候为了判断浏览器对HTML5/CSS3支持情况,我们常常会首先选择判断浏览器类型,浏览器对象中有一个navigator 对象,具有的主要属性如下
appCodeName – 浏览器代码名的字符串表示
appName – 官方浏览器名的字符串表示
appVersion – 浏览器版本信息的字符串表示
cookieEnabled – 如果启用cookie返回true,否则返回false
javaEnabled – 如果启用java返回true,否则返回false
platform – 浏览器所在计算机平台的字符串表示
plugins – 安装在浏览器中的插件数组
taintEnabled – 如果启用了数据污点返回true,否则返回false
userAgent – 用户代理头的字符串表示

我们其中户代理头的字符串userAgent包含了浏览器的信息,包括操作系统以及版本,以及浏览器的内核信息,通过这个属性可以判断出当前页面所处的浏览器环境,帮助针对不同的浏览器实现兼容性。
在Chrome中用户代理头的字符串内容如下
“Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36”
firefox中则为
“Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0”
通过正则表达式来匹配是否满足相对应的浏览器的特性

 var Sys = {}; 
var ua = navigator.userAgent.toLowerCase(); 
var s; 
(s = ua.match(/msie ([/d.]+)/)) ? Sys.ie = s[1] : 
(s = ua.match(/firefox//([/d.]+)/)) ? Sys.firefox = s[1] : 
(s = ua.match(/chrome//([/d.]+)/)) ? Sys.chrome = s[1] : 
(s = ua.match(/opera.([/d.]+)/)) ? Sys.opera = s[1] : 
(s = ua.match(/version//([/d.]+).*safari/)) ? Sys.safari = s[1] : 0;

测试代码

if (Sys.ie) document.write('IE: ' + Sys.ie); 
if (Sys.firefox) document.write('Firefox: ' + Sys.firefox); 
if (Sys.chrome) document.write('Chrome: ' + Sys.chrome); 
if (Sys.opera) document.write('Opera: ' + Sys.opera); 
if (Sys.safari) document.write('Safari: ' + Sys.safari);

在Jquery 1.9版本之前有个可以通过$.browser来判断浏览器的类型,但是之后版本中去掉了这个方法,但是可以通过 jQuery.migrate 插件来完成该功能,同时官网推荐Modernizr实现。

Modernizr是专门用来检测浏览器对HTML5和CSS3特性的JS库。

引入Modernizr库之后,很方便地检测浏览的特性

if (Modernizr.borderradius) {
      //do something
   }

   if (Modernizr.csstransforms) {
      //
   }

在某些不支持新特性的浏览器上,Modernizr不仅仅提供了上述方式告诉你,也提供了load功能允许你加载一些shim/polyfill脚本来达到支持的目的.

可以使用Modernizr的load()函数来动态加载脚本,该函数的test属性是表明要测试是否支持的新特性,如果测试成功支持的话,就加载yep属性设置的脚本,如果不支持就加载nope属性设置的脚本,不管是否支持,both属性里设置的脚本都会加载的。例子代码如下:

Modernizr.load({
    test: Modernizr.canvas,
    yep:  'html5CanvasAvailable.js’,
    nope: 'excanvas.js’, 
    both: 'myCustomScript.js' 
});

在该例子里,Modernizr会判断当前浏览器是否支持canvas特性,如果支持,那就会加载html5CanvasAvailable.js和myCustomScript.js这两个脚本,如果不支持,就会加载excanvas.js(用于IE9之前的版本)脚本文件以让该浏览器支持canvas功能,然后再加载myCustomScript.js脚本。

因为Modernizr可以加载脚本,所以你还可以用于其它的用途,比如,如果你引用的第三方脚本(例如提供CDN服务的Google和Microsoft提供jquery的托管)加载失败的情况下,可以加载备用的文件。下面的代码是Modernizr提供的一个加载jquery的示例:

Modernizr.load([
    {
        load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js',
        complete: function () {
            if (!window.jQuery) {
                Modernizr.load('js/libs/jquery-1.6.4.min.js');
            }
        }
    },
    {
        // This will wait for the fallback to load and
        // execute if it needs to.
        load: 'needs-jQuery.js'
    }
]);

参考资料 Detecting HTML5/CSS3 Features using Modernizr