JS5 - DOM & BOM & Ajax跨域

此处的知识点为常用知识点, 了解更多可以查看这篇优秀的文章 《2021JavaScript知识汇总》 ( 也是我写的 - _ - )



1、DOM

⑴、本质

HTML 是一个有既定标签标准的 XML 格式,标签的名字、层级关系和属性,都被标准化(否则浏览器无法解析)。同样,它也是一棵树。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div>
        <p>this is p</p>
    </div>
</body>
</html>

基于以上需求,浏览器就需要把 html 转变成 DOM,html 是一棵树,DOM 也是一棵树。可以认为 DOM 就是 JS 能识别的 html 结构,一个普通的 JS 对象或者数组

⑵、常用方法

DOM节点操作

  • getElementById() 通过元素ID属性值选取节点, 返回单一对象
  • getElementsByClassName() 通过元素类名属性值选取节点, 返回包含该对象的集合
  • getElementsByName() 通过元素name属性值选取节点, 返回包含该对象的集合
  • getElementsByTagName() 通过标签名选取指定元素节点, 返回包含该对象的集合
  • document.querySelector() 通过选择器得到元素
  • document.querySelectorAll() 通过选择器得到元素数组

DOM结构操作

  • 节点的创建 document.createElement()
  • 节点的获取( 父元素 / 子元素 ) 获取的节点 . parentElement / childNodes
  • 节点的删除 removeChild ( 要删除子节点 )
  • 节点的克隆 cloneNode()

⑶、属性 prototype & Attribute 的区别

property 的获取和修改,是直接改变 JS 对象,而 Attibute 是直接改变 html 的属性。两种有很大的区别


prototype

var pList = document.querySelectorAll('p')
var p = pList[0]
console.log(p.style.width)  // 获取样式
p.style.width = '100px'  // 修改样式
console.log(p.className)  // 获取 class
p.className = 'p1'  // 修改 class

// 获取 nodeName 和 nodeType
console.log(p.nodeName)
console.log(p.nodeType)

Attribute

var pList = document.querySelectorAll('p')
var p = pList[0]
p.getAttribute('data-name')
p.setAttribute('data-name', 'imooc')
p.getAttribute('style')
p.setAttribute('style', 'font-size:30px;')

⑷、实例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>DOM实例</title>

</head>
<body>
  <div id="div1" class="class-div1">
    <p id="p1" data-name="p1-data-name">this is p1</p>
    <p id="p2">this is p2</p>
  </div>
  <div id="div2">
    <p id="p3">this is p3</p>
    <p id="p4">this is p4</p>
  </div>
  <style>
    div{
      margin: 20px;
      padding: 20px;
      background-color: #eee;
    }
  </style>
    <script type="text/javascript">

      // 通过元素`ID`属性值选取节点, 返回单一对象
      var div1 = document.getElementById('div1')
      console.log( div1 )

      // 修改ID - property
      console.log( div1.className )
      div1.className = "class-div2"
      console.log( div1.className )

      // 修改data-name - attribute
      var p1 = document.getElementById('p1')
      console.log( p1.getAttribute( 'data-name' ) )
      p1.setAttribute( 'data-name', 'p2-data-name' )
      console.log( p1.getAttribute( 'data-name' ) )


      // 通过`标签名`选取指定元素节点。返回包含该对象的集合
      var divList = document.getElementsByTagName('div')
      console.log( divList )
      // 对象的个数
      console.log(divList.length)
      // 第 0 个对象
      console.log(divList[0])


      // 通过元素`类名`属性值选取节点, 返回包含该对象的集合
      var containerList = document.getElementsByClassName('.container')
      console.log( containerList )


      // 通过`选择器`得到元素数组
      var pList = document.querySelectorAll('p')
      console.log( pList )





      // !!!DOM结构操作

      // 添加新节点
      var p = document.createElement('p')
      p.innerHTML = 'new p'
      var div1 = document.getElementById('div1')
      div1.appendChild(p)

      // 移动已有节点
      var p4 = document.getElementById('p4')
      var div1 = document.getElementById('div1')
      div1.appendChild(p4)

      // 获取父元素节点
      var p3 = document.getElementById('p3')
      var div1 = document.getElementById('div1')
      var parent = div1.parentElement
      console.log( parent )
      console.log( p3.parentElement )

      // 获取子元素节点
      var div1 = document.getElementById('div1')
      var child = div1.childNodes
      console.log( child )
      console.log( child[0].nodeType )  // text 1
      console.log( child[1].nodeType )  // p 1
      console.log( child[0].nodeName )  // text #text
      console.log( child[1].nodeName )  // p #p

      // 删除节点
      var div1 = document.getElementById('div1')
      var childNodes = div1.childNodes
      // childNodes[0]是一个空text, 删除会报错
      div1.removeChild(childNodes[1])
    </script>
</body>
</html>



2、BOM

⑴、题目

  • 如何检测浏览器的类型
  • 拆解url的各部分

⑵、知识点

BOM(浏览器对象模型)是浏览器本身的一些信息的设置和获取,例如获取浏览器的宽度、高度,设置让浏览器跳转到哪个地址。

  • navigator 浏览器
  • screen 屏幕
  • location 地址
  • history 历史( 前进 后退 )

实例

// navigator
var ua = navigator.userAgent
var isChrome = ua.indexOf('Chrome')
console.log(isChrome)

// screen
console.log(screen.width)
console.log(screen.height)

// location
console.log(location.href)  // 整个url
console.log(location.protocol) // 协议 'http:' 'https:'
console.log(location.host) // 域名
console.log(location.pathname) // 路径 '/learn/199'
console.log(location.search)  // 参数 ?后面的
console.log(location.hash)  // #后面就是哈希

// history
history.forward()  // 前进
history.back()  // 后退



3、事件

⑴、题目

  • 编写一个通用的事件监听函数
  • 描述DOM事件冒泡流程
  • 对于一个无线下拉加载图片的页面,如何给每个图片绑定事件

⑵、知识点

①、事件绑定

var btn = document.getElementById('btn1')
btn.addEventListener('click', function (event) {
    console.log('clicked')
})

②、通用事件绑定函数

// elem 元素、type 类型、fn 函数
function bindEvent(elem, type, fn) {
    elem.addEventListener(type, fn)
}
var a = document.getElementById('link1')
// 对应 a是链接, 'click'是类型, function是函数
bindEvent(a, 'click', function(e) {
    e.preventDefault() // 阻止默认行为
    alert('clicked')
})

③、关于IE低版本的兼容性

IE 低版本是使用attachEvent来绑定事件的


④、事件冒泡

需求:仅绑定两个事件, 点击 激活 ,弹出 激活, 点击 取消, 弹出 取消

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

**实现**
var p1 = document.getElementById('p1')
var body = document.body
bindEvent(p1, 'click', function (e) {
	// 阻止事件冒泡
    e.stopPropatation()
    alert('激活')
})
// 最终事件冒泡, 均会触发给body绑定的事件
bindEvent(body, 'click', function (e) {
    alert('取消')
})

如果在p1 div1 body中都绑定了事件,会根据 DOM 的结构,来冒泡从下到上挨个执行。但是我们使用e.stopPropatation()就可以阻止冒泡

⑤、代理

场景:一个<div>中包含了若干个<a>,而且还能继续增加。怎么给所有的<a>绑定事件

<div id="div1">
    <a href="#">a1</a>
    <a href="#">a2</a>
    <a href="#">a3</a>
    <a href="#">a4</a>
</div>
<button>点击增加一个 a 标签</button>

这里就会用到事件代理,我们要监听<a>的事件,把具体的事件绑定到<div>上,然后看事件的触发点,是不是<a>

var div1 = document.getElementById('div1')
div1.addEventListener('click', function (e) {
    var target = e.target
    if (e.nodeName === 'A') {
        alert(target.innerHTML)
    }
})

⑥、完善通用绑定事件的函数 ( 代理 )

在完善一下之前写过的通用事件绑定函数,加上事件代理

// elem 元素、type 类型、selector 选择器、fn 函数
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
            // 如果 target 满足这个选择器
            if (target.matches(selector)) {
                fn.call(target, e)
            }
        } else {
            fn(e)
        }
    })
}


// 使用


// 使用代理
var div1 = document.getElementById('div1')
bindEvent(div1, 'click', 'a', function (e) {
    console.log(this.innerHTML)
})

// 不适用代理
var a = document.getElementById('a1')
bindEvent(div1, 'click', function (e) {
    console.log(a.innerHTML)
})

4、Ajax 跨域

⑴、题目

  • 手动编写一个 ajax,不依赖第三方库
  • 跨域的几种实现方式

⑵、知识点

①、XMLHttpRequest - Ajax核心API

// 通过 XMLHttpRequest() 声明一个对象
var xhr = new XMLHttpRequest()
// 打开 通过get的方式 请求地址 异步/ false是同步
xhr.open("GET", "/api", true)
//  会监听状态变化, 重新执行函数
xhr.onreadystatechange = function () {
	// 如果 已完成
    if (xhr.readyState == 4) {
    	// 如果 服务端返回的是 200
        if (xhr.status == 200) {
        	// 弹出 服务端返回的内容
            alert(xhr.responseText)
        }
    }
}
// 发送
xhr.send(null)

②、XMLHttpRequest - Ajax核心API

IE 低版本的兼容性问题,它使用var xhr = new ActiveXObject("Microsoft.XMLHTTP")创建


③、状态码说明

Ⅰ、readyState
  • 0 - (未初始化)还没有调用send()方法
  • 1 -(载入)已调用send()方法,正在发送请求
  • 2 -(载入完成)send()方法执行完成,已经接收到全部响应内容
  • 3 -(交互)正在解析响应内容
  • 4 -(完成)响应内容解析完成,可以在客户端调用了

Ⅱ、status
  • 2xx 表示成功处理请求, 如:200
  • 3xx 需要重新定向, 浏览器直接跳转
  • 4xx 客户端请求错误, 如:404
  • 5xx 服务器端错误

④、跨域

Ⅰ、什么是跨域
  • 浏览器有同源策略, 不允许 ajax 访问其他域接口
  • 跨域条件:协议、域名、端口, 有一个不同就算跨域
  • 例:https://www.csdn.net/?spm=1011.2124.3001.4476
  • :80就是端口号, 没写就是通用端口

跨域跨域的三个标签

  • < img src = xxx > // 部分网站会做处理
  • < link href = xxx >
  • < script src = xxx >

  • < img > 用于打点统计, 统计网站可能是其他域
  • < link > < script > 跨域使用CDN, CDN的也是其他域
  • < script > 可以用与 JSONP

跨域注意事项:所有的跨域请求都必须经过信息提供方允许, 如果未经允许即可获得, 那是浏览器同源侧栏出现漏洞


Ⅱ、JSONP

访问http://coding.m.imooc.com/classindex.html的时候,服务器端就不一定有一个classindex.html文件,服务器可以拿到这个请求,然后动态生成一个文件,然后返回。

同理,<script src="http://coding.m.imooc.com/api.js">也不一定加载一个服务器端的静态文件,服务器也可以动态生成文件并返回

实现原理

<script>
window.callback = function (data) {
    // 这是我们跨域得到信息
    console.log(data)
}
</script>

<script src="http://coding.m.imooc.com/api.js"></script>
// 以上将返回 callback({x:100, y:200})
// 这个js加载之后,就会执行内容,我们就得到内容了

Ⅲ、服务端设置 http header

需要在服务器端设置

response.setHeader("Access-Control-Allow-Origin", "http://localhost:8011");  // 第二个参数填写允许跨域的域名称,不建议直接写 "*"
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
response.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");

// 接收跨域的cookie
response.setHeader("Access-Control-Allow-Credentials", "true");



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后海 0_o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值