文章目录
一、同源策略和跨域请求
1.同源
- 同源:说的是两个url之间的对比。
如果两个url以下三个方面都相同,则这两个url同源,否则非同源。 - 协议(http、https、file、…)
- 主机地址(www.itcbc.com)
- 端口号(:3000)
http协议默认的端口是 80; https协议默认的端口是 443
2.同源策略
同源策略(同源政策)是浏览器的一种保护机制。
如果发送了一个请求,服务器返回结果后,浏览器会判断(检查)
打开页面的url
和 **请求的接口地址
**是否同源。
- 如果同源则接收响应结果
- 如果不同源,则拒绝接收结果(请求失败)
二、跨域
凡是违反了同源策略的请求,都是跨域请求。
1.突破跨域的限制
突破跨域的限制,可以使用JSONP方案 或CORS方案。
2.CORS方案
- 是标准的解决跨域的方案
- 兼容性不好(IE10+)
- 支持所有的请求方式
- 用起来特别方便
2.1使用CORS方案解决跨域
后端在做出响应的时候,加一个响应头(Access-Control-Allow-Origin: *
)即可。
前端不需要做任何处理,正常发送Ajax请求即可。
3.JSONP方案
- 不是标准的解决跨域的方案
- 是一个古老的方案
- JSONP请求和AJAX无关,只支持GET请求
3.1实现原理:
- 准备好一个函数,名字随意,用于接收响应结果
- 使用script标签的src属性请求接口地址,并通过callback把函数名传给服务器即可
<script>
// 提前准备好 abc 函数
function abcd(res) {
console.log(res)
}
// abcd({ "id": 100, "name": "hahaha", "age": 20 });
// 你的函数名是abcd,参数是响应给你的数据
</script>
<script src="http://www.xxx/jsonp?callback=abcd"></script>
4.封装一个发送JSONP请求的函数
function jsonp({ url, params, success }) {
// 处理params
let arr = []
for (let key in params) {
arr.push(`${key}=${params[key]}`)
}
// console.log(success)
// 准备好的函数是 success
// 服务器返回 success(.....) ,调用的是全局中的 success
// 所以需要把我们的success升级为全局函数
window.success = success
let s = document.createElement('script')
s.src = url + '?callback=success&' + arr.join('&')
document.body.appendChild(s)
// script标签什么时候加载完毕。当服务器返回结果后,表示script标签加载的内容加载完毕了
// 加载完服务器返回的结果,就会触发 load 事件
s.addEventListener('load', function () {
document.body.removeChild(s)
})
}
// 点击按钮,调用函数,进行测试
document.querySelector('button').addEventListener('click', function () {
jsonp({
url: 'http://xxx/jsonp',
params: {
id: 1,
appkey: 'huanghun'
},
success: function (res) {
console.log(res)
}
})
})
三、淘宝搜索建议案例
let timer = null
// 1. 找到输入框,注册input事件(当我们在输入框输入内容的时候就会触发事件)
document.querySelector('.ipt').addEventListener('input', function () {
// 马上清除定时器
clearTimeout(timer)
// 获取搜索关键字
let keyword = this.value
if (keyword === '') return // 关键字为空,不发送请求
timer = setTimeout(() => {
// 2. 事件触发后,发送JSONP请求,获取搜索建议
jsonp({
url: 'https://suggest.taobao.com/sug',
params: {
q: keyword,
code: 'utf-8'
},
success: (res) => {
// 3. 得到搜索建议之后,把数据渲染到 div#suggest-list 中
// console.log(res)
let arr = res.result.map(item => `<div class="suggest-item">${item[0]}</div>`)
// console.log(arr.join(''))
document.querySelector('#suggest-list').innerHTML = arr.join('')
}
})
}, 1000)
})
四、节流案例
let box = document.querySelector('.box')
let btn = document.querySelector('.btn-fire')
btn.addEventListener('click', function () {
console.log(1)
// 判断 box 盒子里面有几个图片
if (box.children.length === 2) return
// 创建一个热狗
let newBall = document.createElement('img')
newBall.src = './img/bullet.png'
newBall.classList.add('ball')
// 将热狗加入到盒子中
box.appendChild(newBall)
// 给热狗加一个动画
for (let i = 1; i <= 95; i++) {
setTimeout(() => {
newBall.style.left = i + '%'
if (i === 95) {
// 当热狗跑到头,移除它
box.removeChild(newBall)
}
}, i * 10)
}
})
五、图片跟随鼠标移动案例
1.通过定时器实现节流
<body>
<img src="./images/tianshi.gif" alt="" style="position: absolute;">
<script>
let img = document.querySelector('img')
let timer = null
// 给 document 注册 mousemove 事件,当鼠标移动的时候触发
document.addEventListener('mousemove', function (e) {
console.log(123)
if (timer) { // timer是数字,则不要往下进行
return
}
timer = setTimeout(() => { // 将定时器赋值给 timer,timer就是数字
console.log('代码执行了一次')
// 获取鼠标的位置
let x = e.clientX
let y = e.clientY
// console.log(x, y)
// 设置图片的 left 样式和 top 样式
img.style.left = (x - 30) + 'px'
img.style.top = (y - 30) + 'px'
// 当前定时器执行完毕,重置 timer
timer = null
}, 30)
})
</script>
</body>
2.通过时间差实现节流
// 节流:单位时间(30ms)内,事件中的计算,最多执行一次
let img = document.querySelector('img')
let prev = Date.now() // 1000130
// 给 document 注册 mousemove 事件,当鼠标移动的时候触发
document.addEventListener('mousemove', function (e) {
console.log(111)
let curr = Date.now() // 1000130
if (curr - prev >= 30) {
console.log(222)
// 获取鼠标的位置
let x = e.clientX
let y = e.clientY
// console.log(x, y)
// 设置图片的 left 样式和 top 样式
img.style.left = (x - 30) + 'px'
img.style.top = (y - 30) + 'px'
// 重置上一次执行时间
prev = Date.now()
}
})