Fork me on GitHub

预加载+懒加载-demo展示

预加载&&懒加载-demo展示

一 预加载

html

<!DOCTYPE html>
<html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>预加载</title>
    <style type="text/css">
        #box{
            width: 800px;
            }

    </style>
    </head>
    <body>
    <div id="box"></div>
</body>

步骤:

// 步骤:1 存一组图片到数组中

// 2 因为需要先将图片一张张加载,所以需要利用for循环。

// 3 图片加载前,需要先新建一个图片对象,和图片路径

// 4 每次新建一张图片对象,获取一个图片路径,进行加载(在此,利用index++实现每次加载下一张)

// 5 加载后,将图片存到一盒新的空数组中。

// 6 将数组添加到HTML文档的元素中

js:

//图片
var imgarr=["http://d.hiphotos.baidu.com/image/h%3D200/    sign=2a5a59df74094b36c4921ced93cd7c00/18d8bc3eb13533fa997c342eaad3fd1f40345be3.jpg","http://g.hiphotos.baidu.com/image/pic/item/5882b2b7d0a20cf4c7e9bd9973094b36acaf997f.jpg","http://e.hiphotos.baidu.com/image/h%3D200/sign=c6fd3ae21d178a82d13c78a0c602737f/4e4a20a4462309f7d4896d3c710e0cf3d7cad63e.jpg","http://g.hiphotos.baidu.com/image/pic/item/0eb30f2442a7d9338e2370bcaf4bd11372f00171.jpg","http://f.hiphotos.baidu.com/image/pic/item/f11f3a292df5e0fe8429ca47596034a85edf7246.jpg","http://g.hiphotos.baidu.com/image/pic/item/08f790529822720e62e61b4e7ecb0a46f21fab5e.jpg","http://g.hiphotos.baidu.com/zhidao/pic/item/267f9e2f07082838e161fffabd99a9014d08f1f4.jpg"];



var index=0;
var arr=[];
for (var i = 0; i < imgarr.length; i++) {
var newobj=new Image();
newobj.src=imgarr[i];
newobj.onload=function(){
index++;
arr.push(this); // this指代的是事件的主体,也就是newobj, 而事件的主体我们一般可以用this来指代
// 当index++ 大于我们的imgarr.length时候,也就是加载完成的时候,加载条应该显示100%;
if (index>=imgarr.length) {
box.innerHTML=Math.ceil(index/imgarr.length*100)+"%";
loadingover(); }  }  }

function loadingover(){
    box.innerHTML="";

    for (var i = 0; i < arr.length; i++){
    box.appendChild(arr[i]);   }  }

二 懒加载

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>延时加载</title>
    <style type="text/css">
    #div1{border:1px red solid;
               width: 80%;
               position: absolute;
               top: 500px;
               }
    #div2{border:1px red solid;
    width: 80%;
    position: absolute;
    top: 2000px;
    }
    #div3{
    border:1px red solid;
    width: 80%;
    position: absolute;
    top: 3000px;
    }
    img{
    /*img需要给定宽*/
    width: 600px;    
    height: 400px;
    }
    </style>
    </head>
    <body>
    <div class="big" id="div1"><img c="../img/18.jpg"></div>
    <div class="big" id="div2"><img c="../img/19.jpg"></div>
    <div class="big" id="div3"><img c="../img/20.jpg"></div>
</body>
</html>

js

var img=document.getElementsByTagName('img');

// 图片在定位时,要找到元素最外层定位的父元素,并获取这两个元素之间的高度,一个网页会有很多个延时加载的元素,所以,可以用函数传参来封装函数。
function offset(element){
var t=element.offsetTop;
// 因为不知道子元素外有多少父级,利用while循环来获取子元素到最外层元素间的高度
 while(element){
 t+=element.offsetTop;
 element=element.offsetParent; //让参数element一级一级往上,直到element没有定位的父级为止,此时,while里的element条    件为假,循环停止,得到最后的t值
 }
 return {top:t} // 返回t值 这里的top 是一个对象,我们可以随便定义对象名
 }
// 寻找执行条件 并执行要达到的效果
window.onscroll=function(){
var scrolltop=document.body.scrollTop||document.documentElement.scrollTop;
var ch=document.documentElement.clientHeight;
// 循环每一张图片
for (var i = 0; i < img.length; i++) {
//通过传参获取img的offsetHeight
var oh=offset(img[i]).top;
// if 判断条件 来判断图片在什么时候加载
if (oh<scrolltop+ch-200) {
img[i].src=img[i].getAttribute("c");
}
}
}
</script>

三分钟学会css3中的flexbox布局

三分钟学会css3中的flexbox布局

这篇文章里我们将学习CSS里flexbox布局的几个最重要的概念,通过学习flexbox布局,你会发现以往遇到的所有的关于布局的问题,现在都可以轻松解决了。
我们将只关注几个核心概念,等这些核心知识掌握之后,你可以再慢慢的学习那些不重要的相关知识。

  1. 容器和容器里的元素
    flexbox布局的两个最重要的概念是容器(蓝色)和容器里的子元素(红色)。在本文的例子中,容器和它的子元素都是div。
    横向布局
    为了实现flex布局,我们需要在容器的CSS里添加如下代码:

    .container {
        display: flex;
    }
    

对于容器里面的子元素,我们什么都不需要做。它们会自动的按横坐标一字排开。
纵向布局
在上面的演示中,缺省排列是沿着横坐标方向的,还有一个方向是纵坐标,这个坐标轴的概念在理解flex布局中非常重要。
当我们在容器的CSS里添加 flex-direction: column.后,子元素的排列方向就会发生变化。

.container {
display: flex;
flex-direction: column;
}

现在,子元素的排列方向是沿着纵坐标的方向了。

  1. 调整子元素的对齐方式
    现在我们让子元素重新横向布局,这需要将flex-direction属性的值从 column改成 row, 子元素就会重新回到横向布局。
    调整子元素的对齐方式,我需要使用justify-content 和 align-items 这两个属性,它们控制着子元素的在横向和纵向两方面的定位和对齐方式。
    下面我们将要使用justify-content属性让所有子元素都居中对齐:

    .container {
    display: flex;
    flex-direction: row;
    justify-content: center;
    }
    

    使用 align-items 属性来控制子元素的竖向对齐方式:

    .container {
        display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    }
    

下面的列表中显示了justify-content 和 align-items属性可以使用的属性值:

justify-content:
* flex-start (default)
* flex-end
* center
* space-between
* space-around

align-items:
* flex-start (default)
 * flex-end
* center
* baseline
* stretch

建议大家将justify-content 、align-items和flex-direction几个属性混合使用,相互配合,看看都会达到什么样的布局效果。这样你才能正确的理解flexbox布局的布局方式。

  1. 子元素
    最后,我们将学习针对子元素的一些应对flexbox布局的CSS属性。
    比如我们想调整第一个子元素的位置,我们可以给他添加CSS属性 align-self,这个属性的属性值是和align-items是一样的用法:
.item1 {
  align-self: flex-end;
}

关于flexbox布局的知识远比本文介绍的这些要丰富,这总重要的几个知识点就是这些,掌握了它们,再学些其他的用法就容易多了。

本文转自 http://mp.weixin.qq.com/s?__biz=MjM5MDA2MTI1MA==&mid=2649084363&idx=1&sn=bf9c5f2440caad7a8b5746894d16f3be&chksm=be5bf666892c7f709a6effe503bceaf82e1fae250f9a34d1ce168c48674f539fbdd077aa2d4d&mpshare=1&scene=23&srcid=1120l3DfEjLOj10JXjmtwnkf#rd

帧动画

深入理解CSS3 Animation 帧动画

我们知道CSS3的Animation有八个属性

animation-name

animation-duration

animation-delay

animation-iteration-count

animation-direction

animation-play-state

animation-fill-mode

animation-timing-function

其中1-7大多都有介绍,但是animation-timing-function是控制时间的属性

在取值中除了常用到的 三次贝塞尔曲线 以外,还有个让人比较困惑的 steps() 函数

animation默认以ease方式过渡,它会在每个关键帧之间插入补间动画,所以动画效果是连贯性的

除了ease,linear、cubic-bezier之类的过渡函数都会为其插入补间。但有些效果不需要补间,只需要关键帧之间的跳跃,这时应该使用steps过渡方式

animation-timing-function 规定动画的速度曲线

http://images0.cnblogs.com/blog/329084/201507/110906325499781.png

以上w3school网站上给的使用方法,但是漏掉一个很重要的 steps

简单的来说,我们一直使用animation基本都是实现线性渐变的动画

位置在固定的时间从起点到终点

尺寸在固定的时间线性变化

颜色的线性改变等等

看效果 线性动画

截取CSS如下

.test1 {
width: 90px;
height: 60px;
-webkit-animation-name: skyset;
-webkit-animation-duration: 2000ms;
-webkit-animation-iteration-count: infinite; /*无限循环*/
-webkit-animation-timing-function: linear;}@-webkit-keyframes skyset {
0% { background: red;}
50%{ background: blue}
100% {background: yellow;}}

timing-function:linear 定义的是一个匀速变化的动画,就是在2秒内,从红色过度到蓝色到黄色,是一个很线性的颜色变化

如果要实现帧动画效果而不是线性的变化就需要引入step这个值了,换句话就是没有过渡的效果,而是一帧帧的变化

同样可以看测试 帧动画

理解steps

steps 函数指定了一个阶跃函数

第一个参数指定了时间函数中的间隔数量(必须是正整数)

第二个参数可选,接受 start 和 end 两个值,指定在每个间隔的起点或是终点发生阶跃变化,默认为 end。

step-start等同于steps(1,start),动画分成1步,动画执行时为开始左侧端点的部分为开始;

step-end等同于steps(1,end):动画分成一步,动画执行时以结尾端点为开始,默认值为end。

看看W3C的规范 transition-timing-function

steps第一个参数的错误的理解:

steps(5,start)

steps() 第一个参数 number 为指定的间隔数,即把动画分为 n 步阶段性展示,估计大多数人理解就是keyframes写的变化次数

例如:

@-webkit-keyframes circle {
    0% {}
    25%{}
    50%{}
    75%{}
    100%{}
 }

我之前也一直认为steps(5,start)中的5 就是指的keyframes中的0% 25% 50% 75% 100% 分成5个间隔等分

为什么会出现这种理解错误,我们看一个例子

keyframes的关键帧是只有2个规则的时候,假如我们有一张400px长度的雪碧图

@-webkit-keyframes circle {
    0% {background-position-x: 0;}
    100%{background-position-x: -400px;}
 }

此刻设置steps(5,start)那么会发现5张图会出现帧动画的效果,因为steps中的5把 0% – 100%的规则,内部

分成5个等分

实际内部会执行这样一个关键帧效果

@-webkit-keyframes circle {
    0% {background-position-x: 0;}
    25% {background-position-x: -100px;}
    50% {background-position-x:-200px;}
    75%{background-position-x: -300px;}
    100%{background-position-x: -400px;}
 }

将这个规则稍微修改下,加入一个50%的状态

@-webkit-keyframes circle {
   0% {background-position-x: 0;}
   50% {background-position-x: -200px;}
   100%{background-position-x: -400px;}
}

那么同样用steps(5,start)效果就会乱套

此刻你会很迷惑,所以关键要理解第一个参数的针对点,首先引入一个核心点:

timing-function 作用于每两个关键帧之间,而不是整个动画

那么第一个参数很好理解了,steps的设置都是针对两个关键帧之间的,而非是整个keyframes,所以第一个参数对 - 次数对应了每次steps的变化

换句话说也是 0-25 之间变化5次, 25-50之间 变化5次 ,50-75 之间变化5次,以此类推

第二个参数可选,接受 start 和 end 两个值,指定在每个间隔的起点或是终点发生阶跃变化,默认为 end

通过案例看下 step-start,step-end 的区别

@-webkit-keyframes circle {
    0% {background: red}
    50%{background: yellow}
    100% {background: blue}
}

step-start : 黄色与蓝色相互切换

step-end : 红色与黄色相互切换

2个参数都会选择性的跳过前后部分,start跳过0%,end跳过100%

step-start在变化过程中,都是以下一帧的显示效果来填充间隔动画,所以0% 到 50% 直接就显示了黄色yellow

step-end与上面相反,都是以上一帧的显示效果来填充间隔动画,所以0% 到 50% 直接就显示了红色red

引用w3c的一张step的工作机制图

http://images.cnitblog.com/i/596159/201406/091121212334792.png

总结:

steps函数,它可以传入两个参数,第一个是一个大于0的整数,他是将间隔动画等分成指定数目的小间隔动画,然后根据第二个参数来决定显示效果。

第二个参数设置后其实和step-start,step-end同义,在分成的小间隔动画中判断显示效果。可以看出:steps(1, start) 等于step-start,steps(1,end)等于step-end

最核心的一点就是:timing-function 作用于每两个关键帧之间,而不是整个动画

三张图搞懂JavaScript的原型对象与原型链

三张图搞懂JavaScript的原型对象与原型链

原文地址:三张图搞懂JavaScript的原型对象与原型链

对于新人来说,JavaScript的原型是一个很让人头疼的事情,一来prototype容易与proto混淆,二来它们之间的各种指向实在有些复杂,其实市面上已经有非常多的文章在尝试说清楚,有一张所谓很经典的图,上面画了各种线条,一会连接这个一会连接那个,说实话我自己看得就非常头晕,更谈不上完全理解了。所以我自己也想尝试一下,看看能不能把原型中的重要知识点拆分出来,用最简单的图表形式说清楚。

我们知道原型是一个对象,其他对象可以通过它实现属性继承。但是尼玛除了prototype,又有一个proto是用来干嘛的?长那么像,让人怎么区分呢?它们都指向谁,那么混乱怎么记啊?原型链又是什么鬼?相信不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,下面用三张简单的图,配合一些示例代码来理解一下。

1、prototype和proto的区别

http://ac-myg6wstv.clouddn.com/2e7817d676e605e54e62.png

var a = {};
console.log(a.prototype); //undefined
console.log(a.__proto__);  //Object {}

var b = function(){}
console.log(b.prototype); //b {}
console.log(b.__proto__);  //function() {}

2、proto属性指向谁

http://ac-myg6wstv.clouddn.com/414693e5821245adeb86.png

/*1、字面量方式*/
var a = {};
console.log(a.constructor); //function Object() { [native code] } (即构造器Object)
console.log(a.__proto__ === a.constructor.prototype); //true

/*2、构造器方式*/
var A = function (){}; var a = new A();
console.log(a.constructor); // function(){}(即构造器function A)
console.log(a.__proto__ === a.constructor.prototype); //true

/*3、Object.create()方式*/
var a1 = {a:1} 
var a2 = Object.create(a1);
console.log(a2.constructor); //function Object() { [native code] } (即构造器Object)
console.log(a2.__proto__ === a1);// true 
console.log(a2.__proto__ === a2.constructor.prototype); //false(此处即为图1中的例外情况)

三、什么是原型链

http://ac-myg6wstv.clouddn.com/e8f4cc45af11650de1f8.png

var A = function(){};
var a = new A();
console.log(a.__proto__); //Object {}(即构造器function A 的原型对象)
console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
console.log(a.__proto__.__proto__.__proto__); //null

使用CSS完成元素居中的七种方法

使用CSS完成元素居中的七种方法

在网页上使 HTML 元素居中看似一件很简单的事情. 至少在某些情况下是这样的,但是复杂的布局往往使一些解决方案不能很好的发挥作用。

在网页布局中元素水平居中比元素垂直居中要简单不少,同时实现水平居中和垂直居中往往是最难的。现在是响应式设计的时代,我们很难确切的知道元素的准确高度和宽度,所以一些方案不大适用。据我所知, 在CSS中至少有六种实现居中的方法。我将使用下面的HTML结构从简单到复杂开始讲解:

<div class="center">
      <img src="jimmy-choo-shoe.jpg" alt></div>

使用text-align水平居中

有时显而易见的方案是最佳的选择:

div.center {
  text-align: center;
  background: hsl(0, 100%, 97%);}div.center img {
  width: 33%; height: auto;}

这种方案没有使图片垂直居中:你需要给

添加 padding 或者给内容添加margin-top 和 margin-bottom使容器与内容之间有一定的距离。

使用 margin: auto 居中

这种方式实现水平居中和上面使用text-align的方法有相同局限性。

div.center {
  background: hsl(60, 100%, 97%);}div.center img {
  display: block;
  width: 33%;
  height: auto;
  margin: 0 auto;}

注意: 必须使用display: block使 margin: 0 auto对img元素生效。

使用table-cell居中

使用 display: table-cell, 而不是使用table标签; 可以实现水平居中和垂直居中,但是这种方法需要添加额外的元素作为外部容器。

<div class="center-aligned">
<div class="center-core">
    <img src="jimmy-choo-shoe.jpg">
</div></div>

CSS:

.center-aligned {
display: table;
background: hsl(120, 100%, 97%);
width: 100%;}.center-core {
display: table-cell;
text-align: center;
vertical-align: middle;}.center-core img {
width: 33%;
height: auto;}

注意:为了使div 不折叠必须加上 width: 100%,外部容器元素也需要加上一定高度使得内容垂直居中。给html和body设置高度后,也可以使元素在body垂直居中。此方法在IE8+浏览器上生效。

使用absolute定位居中

这种 方案 有非常好的跨浏览器支持。有一个缺点就是必须显式声明外部容器元素的height:

.absolute-aligned {
position: relative;
min-height: 500px;
background: hsl(200, 100%, 97%);}.absolute-aligned img {
width: 50%;
min-width: 200px;
height: auto;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0;
bottom: 0; right: 0;}

Stephen在他的 博客 中演示了这种方案的几种变化。

使用translate居中


Chris Coiyer 提出了一个使用 CSS transforms 的新方案。 同样支持水平居中和垂直居中:

.center {
background: hsl(180, 100%, 97%);
position: relative;
min-height: 500px;}.center img {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 30%; height: auto;}

但是有以下几种缺点:

  • CSS transform 在部分就浏览器上需要使用 前缀。
  • 不支持 IE9 以下的浏览器。
  • 外部容器需要设置height (或者用其他方式设置),因为不能获取 绝对定位 的内容的高度。
  • 如果内容包含文字,现在的浏览器合成技术会使文字模糊不清。

使用Flexbox居中


当新旧语法差异和浏览器前缀消失时,这种方法会成为主流的居中方案。

.center { 
background: hsl(240, 100%, 97%);
display: flex;
justify-content: center;
align-items: center;}.center img { 
width: 30%; height: auto;}

在很多方面 flexbox 是一种简单的方案, 但是它有新旧两种语法以及早期版本的IE缺乏支持 (尽管可以使用 display: table-cell作为降级方案)。

现在规范已经最终确定,现代浏览器也大都支持,我写了一篇详细的教程 教程。

使用calc居中

在某些情况下比flexbox更全面:

.center {
background: hsl(300, 100%, 97%);
min-height: 600px;
position: relative;}.center img {
width: 40%;
height: auto;
position: absolute;
top: calc(50% - 20%);
left: calc(50% - 20%);}

很简单,calc 允许你基于当前的页面布局计算尺寸。在上面的简单计算中, 50% 是容器元素的中心点,但是如果只设置50%会使图片的左上角对齐div的中心位置。 我们需要把图片向左和向上各移动图片宽高的一半。计算公式为:

top: calc(50% - (40% / 2));left: calc(50% - (40% / 2));

在现在的浏览其中你会发现,这种方法更适用于当内容的宽高为固定尺寸:

.center img {
width: 500px; height: 500px;
position: absolute;
top: calc(50% - (300px / 2));
left: calc(50% - (300px – 2)); }

这种方案和flex一样有许多相同的缺点: 虽然在现代浏览器中有良好的支持,但是在较早的版本中仍然需要浏览器前缀,并且不支持IE8。

 .center img {
width: 40%; height: auto;
position: absolute;
top: calc(50% - 20%);
left: calc(50% - 20%);}

当然还有 其他更多的方案。理解这六种方案之后,web开发人员在面对元素居中的时候会有更多的选择。

来源http://www.zcfy.cc/article/the-new-code-seven-ways-of-centering-with-css-439.html

高德地图插件使用

高德地图

本文引自高德开放平台

准备页面

在正式开始开发地图应用之前,您需要做如下几步:

1 在高德地图官网注册一个账号

2 申请JSAPI的开发者Key
申请地址:

http://lbs.amap.com/dev/key

引入高德地图JavaScript API入口脚本:

<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=您申请的key值"></script>

创建地图容器

在页面body里你想展示地图的地方创建一个div 容器,并指定id标识:

<div id="container"></div>

指定容器大小

使用CSS为地图容器设置合适的大小,比如:

#container {width:300px; height: 180px; } 

创建地图

做完简单的准备工作之后,就可以开始创建地图了.

按照默认属性创建地图

生成一副简单地图只需要一句代码,将我们刚刚创建的div的id传给Map的构造函数即可,这个时候API将根据用户所在的城市自动进行地图中心点和级别的设定:

var map = new AMap.Map('container');
  • 设定地图的中心点和级别

我们一般需要给地图按需设定中心点和坐标等属性,这里可以通过两种方式,第一种,直接在地图初始化的时候传入相关属性,center属性的值可以使经纬度的二元数组,也可以是AMap.LngLat对象,要求经度值在前,纬度值在后:

var map = new AMap.Map('container',{
zoom: 10,
center: [116.39,39.9]});

也可以在地图初始化过后,任何需要的地方通过方法来改变地图的中心点和级别

 var map = new AMap.Map('container');
map.setZoom(10);
map.setCenter([116.39,39.9]);

添加点标记

创建好地图之后,我们就可以在地图上添加点标记了,用来标注任何用户感兴趣的位置和信息,这里使用到了AMap.Marker这个类。

  • 点标记的创建与添加

    同地图一样,点标记可以在创建的时候设定位置等属性,如果设定了map属性的话,marker点将被立即添加到地图上:

    var marker = new AMap.Marker({
    position: [116.480983, 39.989628],
        map:map
    });    
    

    也可以在创建之后按需更改这些属性:

    var marker = new AMap.Marker();
    marker.setMap(map);
    
  • 点标记的移除

    移除的话,同样使用setMap方法,不传参数或者传入空参数:

    marker.setMap();
    

添加信息窗体

我们也可以用信息窗体InfoWindow类来向用户展示一些更详细的信息,比如点击一个点标记后,通过信息窗体来展示这个点标记在哪里

信息窗体的创建与设定

信息窗体一样可以在创建的时候设定内容、偏移量、大小等属性,offset是信息窗体的锚点以position为基准位置的像素偏移量,content除了使用字符串的形式外也可以直接设定为某个创建好的DOM节点:

var infowindow = new AMap.InfoWindow({
 content: '<h3>高德地图</h3><div>高德是中国领先的数字地图内容、导航    和位置服务解决方案提供商。</div>',
 offset: new AMap.Pixel(0, -30),
 size:new AMap.Size(230,0)
})

也可以在创建之后按需更改这些属性:

infowindow.setSize(new AMap.Size(150,50));
var contentDiv = document.createElement('div');
contentDiv.innerText='我是信息窗体';
infowindow.setContent(contentDiv);
如何打开信息窗体

我们可以在信息窗体创建之后立即调用其open方法将它显示在需要的位置:

infowindow.open(map,new AMap.LngLat(116.480983, 39.989628));

也可以通过事件监听,在需要的时候才将信息窗体显示出来,比如在marker被单击的时候显示

var clickHandle = AMap.event.addListener(marker, 'click',     function() {
    infowindow2.open(map, marker.getPosition())
})

当不再需要点击marker显示信息窗体这个功能的时候,可以通过如下方式移除事件绑定

AMap.event.removeListener(clickHandle);

使用高级信息窗体

除了普通的信息窗体,我们还提供了封装了周边搜索和路线规划功能在内的高级信息窗体,要使用高级信息窗体,首先需要通过plugin方法加载该插件,然后就可以和普通信息窗体一样进行创建和打开了。如果为高级信息窗体制定了panel属性,将在以panel的值为id的div上显示周边搜索或者路线规划的结果,如果需要对高级信息窗体和panel内容的样式进行修改,可以对相应classname的css进行重写:

AMap.plugin('AMap.AdvancedInfoWindow',function(){
  var infowindow = new AMap.AdvancedInfoWindow({
content: '<h3 class="title">高德地图</h3>'+
         '<div class="content">高德是中国领先的数字地图内容、'+
         '导航和位置服务解决方案提供商。</div>',
offset: new AMap.Pixel(0, -30),
asOrigin:false
  });
  infowindow.open(map,new AMap.LngLat(116.480983, 39.989628));
})
添加工具条和比例尺

高德地图JSAPI提供了大量丰富的功能控件和服务插件,下面我们来给上面做好的地图添加两个常用的控件,工具条和比例尺。

添加

添加控件的时候首先需要加载插件,同时需要多个插件的时候第一个参数可以设定为控件名称的数组

AMap.plugin(['AMap.ToolBar','AMap.Scale'],function(){
//TODO  创建控件并添加
})

在回调函数里我们来进行控件的生成和添加:

AMap.plugin(['AMap.ToolBar','AMap.Scale'],function(){
var toolBar = new AMap.ToolBar();
var scale = new AMap.Scale();
map.addControl(toolBar);
map.addControl(scale);
})
移除

要移除控件的时候调用地图的removeControl方法即可

map.removeControl(toolBar);

原生JavaScript事件详解

原生JavaScript事件详解

JQuery这种Write Less Do More的框架,用多了难免会对原生js眼高手低。

小菜其实不想写这篇博客,貌似很初级的样子,但是看到网络上连原生js事件绑定和解除都说不明白,还是决定科普一下了。

首先声明,小菜懂的也不是很多,只是把我的思路和大家分享一下。

DOM0事件模型

事件模型在不断发展,早期的事件模型称为DOM0级别。

DOM0事件模型,所有的浏览器都支持。

直接在dom对象上注册事件名称,就是DOM0写法,比如:

document.getElementById("test").onclick = function(e){};

意思就是注册一个onclick事件。当然,它和这种写法是一个意思:

document.getElementById("test")["onmousemove"] = function(e){};

这没什么,只不过是两种访问js对象属性的方法,[]的形式主要是为了解决属性名不是合法的标识符,比如:object.123肯定报错,但是object[“123”]就避免了这个问题,与此同时,[]的写法,也把js写活了,用字符串表示属性名称,可以在运行时动态绑定事件。

言归正传,事件被触发时,会默认传入一个参数e,表示事件对象,通过e,我们可以获取很多有用的信息,比如点击的坐标、具体触发该事件的dom元素等等。

基于DOM0的事件,对于同一个dom节点而言,只能注册一个,后边注册的同种事件会覆盖之前注册的。例如:

var btn = document.getElementById("test");
btn.onmousemove = function(e){
 alert("ok");
 };

 btn["onmousemove"] = function(e){
  alert("ok1");
 };

结果会输出ok1。

接下来再说说this。事件触发时,this就是指该事件在哪个dom对象上触发。例如:

var btn = document.getElementById("test");

btn.onmousemove = function(e){
  alert(this.id);
  };

结果输出test。因为事件就是在id为test的dom节点上注册的,事件触发时,this当然代表这个dom节点,可以理解为事件是被这个dom节点调用的。

所以,想解除事件就相当简单了,只需要再注册一次事件,把值设成null,例如:

var btn = document.getElementById("test");
btn.onclick = function(e){
 alert("ok");
 };

  btn.onclick = null;

原理就是最后注册的事件要覆盖之前的,最后一次注册事件设置成null,也就解除了事件绑定。

事情还没结束,DOM0事件模型还涉及到直接写在html中的事件。例如:

<div id="test" class="test" onclick="exec();" ></div>

通过这种方式注册的事件,同样遵循覆盖原则,同样只能注册一个,最后一个生效。

区别就是,这样注册的事件,相当于动态调用函数(有点eval的意思),因此不会传入event对象,同时,this指向的是window,不再是触发事件的dom对象。

DOM2事件模型

DOM2事件模型相对于DOM0,小菜仅仅了解如下两点:

· DOM2支持同一dom元素注册多个同种事件。

· DOM2新增了捕获和冒泡的概念。

DOM2事件通过addEventListener和removeEventListener管理,当然,这是标准。

但IE8及其以下版本浏览器,自娱自乐,搞出了对应的attachEvent和detachEvent,由于小菜才疏学浅,本文不做讨论。

addEventListener当然就是注册事件,她有三个参数,分别为:”事件名称”, “事件回调”, “捕获/冒泡”。举个例子:

var btn = document.getElementById("test");
btn.addEventListener("click", function(e){
 alert("ok");
 }, false);

事件名称就不用多说了,相比DOM0,去掉了前边的on而已。

事件回调也很好理解,事件触发了总得通知你吧!回调时和DOM0一样,也会默认传入一个event参数,同时this是指触发该事件的dom节点。

最后一个参数是布尔型,true代表捕获事件,false代表冒泡事件。其实很好理解,先来个示意图:
http://images.cnitblog.com/blog/471788/201412/282221104503701.gif

意思就是说,某个元素触发了某个事件,最先得到通知的是window,然后是document,依次而入,直到真正触发事件的那个元素(目标元素)为止,这个过程就是捕获。接下来,事件会从目标元素开始起泡,再依次而出,直到window对象为止,这个过程就是冒泡。

为什么要这样设计呢?这貌似是由于深厚的历史渊源,小菜也不怎么了解,就不乱说了。

由此可以看出,捕获事件要比冒泡事件先触发.

假设有这样的html结构:

<div id="test" class="test">
    <div id="testInner" class="test-inner"></div>
</div>

然后我们在外层div上注册两个click事件,分别是捕获事件和冒泡事件,代码如下:

var btn = document.getElementById("test");
//捕获事件
btn.addEventListener("click", function(e){
alert("ok1");
}, true);

//冒泡事件
btn.addEventListener("click", function(e){
 alert("ok");
 }, false);

最后,点击内层的div,先弹出ok1,后弹出ok。结合上边的原理图,外层div相当于图中的body,内层div相当于图中最下边的div,证明了捕获事件先执行,然后执行冒泡事件。

为什么要强调点击内层的div呢?因为真正触发事件的dom元素,必须是内层的,外层dom元素才有机会模拟捕获事件和冒泡事件,从原理图上就看出了。

如果在真正触发事件的dom元素上注册捕获事件和冒泡事件呢?

html结构同上,js代码如下:

var btnInner = document.getElementById("testInner");
 3 //冒泡事件
 btnInner.addEventListener("click", function(e){
  alert("ok");
  }, false);
  //捕获事件
  btnInner.addEventListener("click", function(e){
  alert("ok1");
  }, true);

当然还是点击内层div,结果是先弹出ok,再弹出ok1。理论上应该先触发捕获事件,也就是先弹出ok1,但是这里比较特殊,因为我们是在真正触发事件的dom元素上注册的事件,相当于在图中的div上注册,由图可以看出真正触发事件的dom元素,是捕获事件的终点,是冒泡事件的起点,所以这里就不区分事件了,哪个先注册,就先执行哪个。本例中,冒泡事件先注册,所以先执行。

这个道理适用于多个同种事件,比如说一下子注册了3个冒泡事件,那么执行顺序就按照注册的顺序来,先注册先执行。例如:

var btnInner = document.getElementById("testInner");
btnInner.addEventListener("click", function(e){
 alert("ok");
}, false);

 btnInner.addEventListener("click", function(e){
    alert("ok1");
 }, false);

 btnInner.addEventListener("click", function(e){
     alert("ok2");
 }, false);

结果当然是依次弹出ok、ok1、ok2.

为了进一步理解事件模型,还有一种场景,假如说外层div和内层div同时注册了捕获事件,那么点击内层div时,外层div的事件一定是先触发的,代码如下:

var btn = document.getElementById("test");
var btnInner = document.getElementById("testInner");

 btnInner.addEventListener("click", function(e){
   alert("ok");
  }, true);

 btn.addEventListener("click", function(e){
     alert("ok1");
 }, true);

结果是先弹出ok1。

假如外层div和内层div都是注册的冒泡事件,点击内层div时,一定是内层div事件先执行,原理相同。

细心的读者会发现,对于div嵌套的情况,如果点击内层的div,外层的div也会触发事件,这貌似会有问题!

点击的明明是内层div,但是外层div的事件也触发了,这的确是个问题。

其实,事件触发时,会默认传入一个event对象,前边提过了,这个event对象上有一个方法:stopPropagation,通过此方法,可以阻止冒泡,这样外层div就接收不到事件了。代码如下:

var btn = document.getElementById("test");
var btnInner = document.getElementById("testInner");

btn.addEventListener("click", function(e){
  alert("ok1");
  }, false);

 btnInner.addEventListener("click", function(e){
   //阻止冒泡
  e.stopPropagation();
    alert("ok");
  }, false);

终于要说说怎么解除事件了。解除事件语法:btn.removeEventListener(“事件名称”, “事件回调”, “捕获/冒泡”);

这和绑定事件的参数一样,详细说明下:

· 事件名称,就是说解除哪个事件呗。

· 事件回调,是一个函数,这个函数必须和注册事件的函数是同一个。

· 事件类型,布尔值,这个必须和注册事件时的类型一致。

也就是说,名称、回调、类型,三者共同决定解除哪个事件,缺一不可。举个例子:

var btn = document.getElementById("test");
//将回调存储在变量中
var fn = function(e){
 alert("ok");
 };
 //绑定
 btn.addEventListener("click", fn, false);

 //解除
  btn.removeEventListener("click", fn, false);

要想注册过的事件能够被解除,必须将回调函数保存起来,否则无法解除。

至此,原生js事件已经讲的差不多了,小菜仅仅知道这些而已,欢迎读者补充其他知识点。

在实际应用中,真正的行家不会傻傻的真的注册这么多事件,一般情况下,只需在最外层dom元素注册一次事件,然后通过捕获、冒泡机制去找到真正触发事件的dom元素,最后根据触发事件的dom元素提供的信息去调用回调。

也就是说,行家会自己管理事件,而不依赖浏览器去管理,这样即可以提高效率,又保证了兼容性,JQuery不就是这么做的嘛~

好了,教程到此结束,希望对读者有所帮助!

原文链接:http://www.cnblogs.com/iyangyuan/p/4190773.html

javascript中常用事件

一 获取事件对象

document.onmouseover=function(){
console.log("a")}
由于火狐的兼容性问题,所以通过传参来解决兼容性问题
document.onclick=function(a){
var ev=a||window.event;
console.log(ev)
}

二获取鼠标当前位置clientX\clientY

event.clientX 在可视区中,鼠标点击的x坐标 
event.clientY 在可视区中,鼠标点击的y坐标 

三 鼠标按下(onmousedown)和抬起(onmouseup)事件

demo  :使用鼠标拖拽一个div 

var box=document.getElementById('box');
document.onmousedown=function(e){
// 解决火狐兼容性问题
var evs=e||window.event; 
var divx=evs.clientX-box.offsetLeft;
var divy=evs.clientY-box.offsetTop;     
 document.onmousemove=function(b){
 // var evs=b||window.event; // 解决火狐兼容性问题
 var evb=b||window.event; 
 var divxb=evb.clientX-divx;
 var divyb=evb.clientY-divy; 
 box.style.left=divxb+"px";
 box.style.top=divyb+"px";
 console.log(divxb)
 }

 document.onmouseup=function(a){
 var eva=a||window.event; // 解决火狐兼容性问题
 document.onmousemove="null";
  }
  }

四 鼠标双击事件:ondblclick

五 组织默认事件的2中方法:

1 return false 由于会阻止其他,所以一般放在最后执行

2 preventDefault 对IE6-IE8不兼容

六 键盘事件 keydown keyup

keydown携带的一个参数是:keyCode,这个参数里的是每个按键的编码,我们可以通 过编码来判断用户按的是哪个按键

demo  使用键盘的上下左右键控制div移动 
<script type="text/javascript">
var box=document.getElementById('box');
var l=0;
var t=0;
var s=0;
document.onkeydown=function(a){
var ev=a||window.event;
 if (ev.keyCode==37){
 l-=10;
 box.style.left=l+"px";
 }
 else if(ev.keyCode==39){
 l+=10;
 box.style.left=l+"px";
 }
else if(ev.keyCode==38){
t-=10;
box.style.top=t+"px";
}

else if(ev.keyCode==40){
t+=10;
box.style.top=t+"px";
}

else if(ev.keyCode==13){
s+=10;
box.style.top=s+"px";
box.style.left=s+"px";
}
}

一些特殊的按键

ctrlKey 返回boolean值,按下时为true 

shiftKey 返回boolean值,按下时为true 

altKey 返回boolean值,按下时为true 

按下以上的按键,并不会返回键盘编码,而是布尔值。我们经常在论坛中发帖,可以 按着control+回车键,就能直接发送蚊子了,我们就可以捕捉这两个按键返回的值来做 对应的处理。

window.onload = function () {
var oText1 = document.getElementById('text1');
var oText2 = document.getElementById('text2');
var oBtn = document.getElementById('btn');
// oBtn.onclick = function () { 
// oText1.value += oText2.value + '\n'; // 
oText2.value = ''; 
}; 
// control+enter , 
oText2.onkeydown = function (ev) {
var oEvent = ev || event;
// control 
if (oEvent.keyCode == 13 && oEvent.ctrlKey) { 
// oText1.value += oText2.value + '\n';
// 
oText2.value = '';
}; 
} }  

七 输入框焦点事件:onfocus 焦点聚集 blur 焦点失去

八 事件冒泡

子标签发生事件后,向父级发送该事件,一直追溯到document。如:点击一个嵌套在 body中的button,则该button的onclick事件也会传递给body、document中,触发他们 的onclick里触发的函数。
事件冒泡只发生在相同事件上。可通过cancelBubble=true取消相同事件冒泡

九 事件绑定

1.非IE浏览器

target. addEventListener(type, listener, useCapture)

target: 文档节点、document、window 或 XMLHttpRequest。

type: 字符串,事件名称,不含“on”,比如“click”、“mouseover”、“keydown”等。 

listener :实现了 EventListener 接口或者是 JavaScript 中的函数。 

useCapture :是否使用捕捉,一般用 false 。

2.IE浏览器

target.attachEvent(type,listener)

target :文档节点、document、window 或 XMLHttpRequest。 

type :字符串,事件名称,含“on”,比 如“onclick”、“onmouseover”、“onkeydown”等。

listener :实现了 EventListener 接口或者是 JavaScript 中的函数。 

3 有了绑定事件,自然有移除事件,根据是否是IE浏览器有两种写法:

非IE浏览器 :

target.removeEventListener(type,listener,useCapture);

IE浏览器:

target.detachEvent(type, listener);

4 通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过addEventListener()添加的匿名函数无法移除,如下面的例子所示:

var btn = document.getElementById("myBtn");

btn.addEventListener("click", function () {
alert(this.id);
}, false);
btn.removeEventListener("click", function () { //无效!
alert(this.id);
}, false);

在这个例子中,我使用addEventListener()添加一个事件处理程序。虽然调用removeEventListener(0是看似使用了相同的参数,但实际上,第二个参数与传入addEventListener()中的那一个完全不同的函数。而传入removeEventListener()中的事件处理程序函数必须与传入addEventListener()中的相同,如下面的例子所示:

var btn = document.getElementById("myBtn");
var handler = function () {
alert(this.id);
};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false); //有效!

重写后的这个例子没有问题,是因为在addEventListener()和removeEventListener()中用来相同的函数。

5两者使用的原理:可对执行的优先级不一样,实例讲解如下:

IE:

ele.attachEvent("onclick",method1);

ele.attachEvent("onclick",method2);

ele.attachEvent("onclick",method3);

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

非IE:

ele.addEventListener("click",method1,false);

ele.addEventListener("click",method2,false);

ele.addEventListener("click",method3,false);

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

6 为解决兼容性问题,利用判断

var func = function(){}; 
//例: addEvent(window,"load",func) 
function addEvent(elem, type, fn) {
if (elem.attachEvent) { elem.attachEvent('on' + type, fn); return;
 }
  if (elem.addEventListener) { elem.addEventListener(type, fn, false);
   }
  }
  //例: removeEvent(window,"load",func) 
function removeEvent(elem, type, fn) {
 if (elem.detachEvent) { elem.detachEvent('on' + type, fn); return;
 }
  if (elem.removeEventListener) { elem.removeEventListener(type, fn, false); }
   } 

Touch事件

js的touch事件,一般用于移动端的触屏滑动,例如:

$(function(){document.addEventListener("touchmove", _touch,     false);}) function _touch(event){alert(1);}

主要认识一下四种事件:

touchstart:当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。

touchend:当手指从屏幕上移开时触发。

touchmove:当手指在屏幕上滑动时连续的触发。在这个事件发生期间,调用

touchcancel:当系统停止跟踪触摸时触发。

preventDefault()可阻止滚动。

以上事件的event对象上面都存在如下属性:

touches:表示当前跟踪的触摸操作的Touch对象的数组。

targetTouches:特定于事件目标的Touch对象的数组。

changeTouches:表示自上次触摸以来发生了什么改变的Touch对象的数组。

每个Touch对象包含下列属性:

clientX:触摸目标在视口中的X坐标。

clientY:触摸目标在视口中的Y坐标。

identifier:表示触摸的唯一ID。

pageX:触摸目标在页面中的x坐标。

pageY:触摸目标在页面中的y坐标。

screenX:触摸目标在屏幕中的x坐标。

screenY:触摸目标在屏幕中的y坐标。

target:触摸的DOM节点坐标

触摸事件

  • touchstart:手指放在一个DOM元素上。
  • touchmove:手指拖曳一个DOM元素。
  • touchend:手指从一个DOM元素上移开。

每个触摸事件都包括了三个触摸列表:

touches:当前位于屏幕上的所有手指的一个列表。

targetTouches:位于当前DOM元素上的手指的一个列表。

changedTouches:涉及当前事件的手指的一个列表

可触控应用

touchstart、touchmove和touchend事件提供了一组足够丰富的功能来支持几乎是任何类型的基于触摸的交互——其中包括常见的多点触摸手势,比如说捏缩放、旋转等待。 下面的这段代码让你使用单指触摸来四处拖曳一个DOM元素:

var obj = document.getElementByIdx_x_x_x_x_x_x('id');
 obj.addEventListener('touchmove', function(event) 
 { // 如果这个元素的位置内只有一个手指的话
if (event.targetTouches.length == 1) 
 {
  var touch = event.targetTouches[0];
   // 把元素放在手指所在的位置
   obj.style.left = touch.pageX + 'px';
 obj.style.top = touch.pageY + 'px';
  }
}, false);

下面是一个示例,该例子显示了屏幕上当前所有的触点,它的作用就是用来感受一下设备的响应性。

canvas.addEventListener('touchmove',   
function(event) {
   for (var i = 0; i < event.touches.length; i++) {
var touch = event.touches;
 ctx.beginPath();
   ctx.arc(touch.pageX, touch.pageY, 20, 0, 2*Math.PI, true);
   ctx.fill();
   ctx.stroke();
  }
 }, false);

阻止滚动

一些移动设备有缺省的touchmove行为,比如说经典的iOS overscroll效果,当滚动超出了内容的界限时就引发视图反弹。这种做法在许多多点触控应用中会带来混乱,但要禁用它很容易。

document.body.addEventListener('touchmove', function(event) {
 event.preventDefault();
}, false); 

如果你正在编写的多点触控应用涉及了复杂的多指手势的话,要小心地考虑如何响应触摸事件,因为一次要处理这么多的事情。考虑一下前面一节中的在屏幕上画出所有触点的例子,你可以在有触摸输入的时候就立刻进行绘制:

canvas.addEventListener('touchmove', function(event) {
 renderTouches(event.touches);
},

不过这一技术并不是要随着屏幕上的手指个数的增多而扩充,替代做法是,可以跟踪所有的手指,然后在一个循环中做渲染,这样可获得更好的性能:

var touches = []
canvas.addEventListener('touchmove', function(event) {
  touches = event.touches;
}, false);
// 设置一个每秒60帧的定时器
timer = setInterval(function() {
 renderTouches(touches);
}, 15);

提示:setInterval不太适合于动画,因为它没有考虑到浏览器自己的渲染循环。现代的桌面浏览器提供了requestAnimationFrame这一函数,基于性能和电池工作时间原因,这是一个更好的选择。一但浏览器提供了对该函数的支持,那将是首选的处理事情的方式。
使用targetTouches和changedTouches
要记住的一点是,event.touches是与屏幕接触的所有手指的一个数组,而不仅是位于目标DOM元素上的那些。你可能会发现使用 event.targetTouches和event.changedTouches来代替event.touches更有用一些。
最后一点,因为你是在为移动设备做开发,因此你应该要留心移动的最佳做法,这些在Eric Bidelman的文章中有论及,以及要了解这一W3C文档。

设备支持

遗憾的是,触摸事件的实现在完备性和质量方面的差别很大。我编写了一个诊断脚本来显示一些关于触摸API实现的基本信息,其中包括哪些事件是支持的,以及 touchmove事件触发的解决方案。我在Nexus One和Nexus S硬件上测试了Android2.3.3,在Xoom上测试了Android 3.0.1,以及在iPad和iPhone上测试了iOS 4.2。

简而言之,所有被测试的浏览器都支持touchstart、touchend和touchmove事件。

规范提供了额外的三个触摸事件,但被测试的浏览器没有支持它们:

1. touchenter:移动的手指进入一个DOM元素。

2. toucheleave:移动手指离开一个DOM元素。

3. touchcancel:触摸被中断(实现规范)。

被测试的浏览器还在每个触摸列表内部都提供了touches、targetTouches和

changedTouches列表。不过,被测试的浏览器没有支持radiusX、radiusY或是
rotationAngle属性,这些属性指明触摸屏幕的手指的形状。在一次touchmove期
间,事件大约一秒钟触发60次,所有的被测试设备都是这样。

转载自:
脚本之家

  • Copyrights © 2015-2021 魏姣
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信