前端开发知识点以及相关面试题(二)

事件

事件绑定

普通的事件绑定如下

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)
})

使用事件代理的优点:

  1. 代码简洁不少;
  2. 减少浏览器的内存占用。

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的缺点有三:

  1. 存储量小,最大只有4KB;
  2. 所有的http请求都会带着它,因此影响获取资源的效率;
  3. 使用太过简单,需要封装才能使用

基于上面cookie的不足,后来就有了sessionStorage和localStorage,先说说localStorage的优点有三:

  1. 存储量最大可达5MB;
  2. 不会带到http请求中;
  3. API适合数据存储 localStorage.setItem(key, value)和localStorage.getItem(key)

sessionStorage和localStorage的区别就是它根据过期时间而失效,而localStorage永久有效;sessionStorage适合存放一些重要但是需要及时失效的信息,而localStorage适合存放一些重要但是不需要经常设置的信息

小技巧:使用localStorage.setItem()的时候记得放到try-catch中,因为某些浏览器是禁用这个API的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值