事件
事件绑定
普通的事件绑定如下
var btn = document.getElementById('btn1');
btn.addEventListener('click', function(event) {
event.preventDefault() // 阻止默认行为
event.stopPropagation() // 阻止事件传播
console.log('clicked')
})
先封装一个绑定事件的函数,现在看起来是有一些简单
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
事件冒泡
<body>
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
</body>
现在我们要想实现点击id为p1的按钮弹出激活,点击其他任何一个p都弹出取消。
var body = docuemnt.body;
var p1 = document.getElementById('p1');
bindEvent(body, 'click', function() {
alert('取消')
});
bindEvent(p1, 'click', function(e) {
e.stopPropagation(); // 阻止向上冒泡
})
因为DOM中body是p的上级节点,绑定在p标签上面的事件会沿着DOM树一层一层向上冒泡,这就是事件冒泡。
事件代理
假设现在有这么一个场景:一个div里有很多个a标签,并且a标签的数量还可以动态的增加,那么我们如何快速的给每一个a都添加点击事件呢?
<div id="div1">
<a href="#">我是按钮1</a>
<a href="#">我是按钮2</a>
<a href="#">我是按钮3</a>
<a href="#">我是按钮4</a>
<a href="#">我是按钮5</a>
</div>
<button>添加一个a</button>
这个时候我们就用到了事件代理,给a标签的父级元素也就是div添加点击事件,借助事件对象来给a标签添加点击事件
var div = document.getElementById('div1');
div.addEventListener('click', function(e) {
var target = e.target;
if (target.nodeName === 'A') {
alert(target.innerHTML)
}
})
来完善一下之前的绑定事件的函数
function bindEvent(elem, type, selector, fn) {
if (fn == null) {
fn = selector
selector = null
}
elem.addEventListener(type, function(e) {
var target
if (selector) {
target = e.target
if (target.matches(selector)) {
fn.call(target, e)
}
} else {
fn(e)
}
})
}
然后按照下面这样使用,代码会简单很多
// 使用代理
var div = document.getElementById('div1');
bindEvent(div, 'click', 'a', function(e) {
console.log(this.innerHTML)
})
//不使用代理
var a = document.getElementById('a1');
bindEvent(div, 'click', function(e) {
console.log(a.innerHTML)
})
使用事件代理的优点:
- 代码简洁不少;
- 减少浏览器的内存占用。
Ajax
手写xhr,不借助任何库。
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
alert(xhr.responseText)
}
}
}
xhr.open('GET', '/api', false)
xhr.send(null)
xhr.readyState的状态码说明:
- 0 代理未被创建,open()方法未被调用;
- 1 open()方法已经被调用;
- 2 send()方法已经被调用,并且头部和状态已经可获得;
- 3 下载中,responseText属性包含部分数据;
- 4 下载完成。
xhr.status的状态码说明:
- 200 正常
- 3xx
- 301 永久重定向。
- 302 临时重定向。
- 304 找到资源,但是不符合条件,不会返回任何主体。
- 404 找不到资源
- 5xx 服务器端出错了
跨域
url哪几个地方不同算跨域?
- 协议
- 域名
- 端口
哪三个标签可以躲过同源策略实现跨域?
- img
- script
- link
解决跨域的两种方式
jsonp
服务端设置 http header
存储
cookie和localStorage有什么不同
cookie本身不是用来做服务器端存储的,它是被设计用来服务器和客户端进行信息传递的,因此每个http请求都会带着它,cookie也具备浏览器端存储的能力,使用起来也非常简单,document.cookie = ...
cookie的缺点有三:
- 存储量小,最大只有4KB;
- 所有的http请求都会带着它,因此影响获取资源的效率;
- 使用太过简单,需要封装才能使用
基于上面cookie的不足,后来就有了sessionStorage和localStorage,先说说localStorage的优点有三:
- 存储量最大可达5MB;
- 不会带到http请求中;
- API适合数据存储 localStorage.setItem(key, value)和localStorage.getItem(key)
sessionStorage和localStorage的区别就是它根据过期时间而失效,而localStorage永久有效;sessionStorage适合存放一些重要但是需要及时失效的信息,而localStorage适合存放一些重要但是不需要经常设置的信息
小技巧:使用localStorage.setItem()的时候记得放到try-catch中,因为某些浏览器是禁用这个API的。