关于jsonp的关键点:
1.src属性不受同源策略的限制;(是get请求)
2.后端传递到cb里的数据格式一般是json格式,如果是其他数据格式传输的数据是有限的
3.动态创建script是异步加载数据,所以我们无法确定数据什么时候回来。所以,我们通过传递参数的形式把我定义好的回调函数的名字给传递给后端。
4.前端定义好回调函数。
5.后端拿到我们传递过去的回调函数的名字,然后帮我们拼接成函数指向的形式,并且把它要给我们的数据传递到回调函数执行里面。
6.最后,我们我请求的资源回来的时候,里面肯定是包含一个我们前端定义好的函数执行,里面传递的数据是后台的数据。
7.jsonp是一个get请求
串起来讲一下:
就是script, img, iframe这类标签上的src在请求资源的时候,不会受同源策略的限制,所以,我们跨域利用src这个属性来帮我们实现跨域。
那跟json有什么关系呢?你想一下,我在前后端传递数据的时候,传递什么类型的数据可以携带最大的数据量,同时可以根据命名需要取值呢?肯定是对象,而且现在我们前后端传递的数据格式基本上就是json格式,json格式本质就是一个对象呀。
前端在使用jsonp跨域时,前端需要和后端协商一下,前端传递给后端的回调函数的key值是什么(eg:例子的callback),然后后端通过前端传递的参数,获取到前端一个定义好的函数名(eg:例子的addList),然后后端通过这个函数名和要传递给前端的参数进行拼接,拼接成一个函数执行的形式(eg:例子的addLIst({…})),然后传递给前端,前端获取到就直接执行了。
图解:
简单例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>淘宝联想词-jsonp</title>
</head>
<body>
<div class="warpper">
<label for="inp">搜索关键字:</label>
<input type="text" class="inp" id="inp">
<ul class="list"></ul>
</div>
<script>
// 简单实现
function addList(data) {
console.log(data.result);
var str = '';
data.result.forEach(ele => {
str += `<li>${ele[0]}</li>`
})
oList.innerHTML = str;
}
var oList = document.getElementsByClassName('list')[0];
var inp = document.getElementsByClassName('inp')[0];
inp.oninput = function() {
var oScript = document.createElement('script');
// 调用淘宝的接口 参数拼接
oScript.src = `https://suggest.taobao.com/sug?q=${inp.value}&callback=addList`;
//插入到页面中 只有插入到页面,才会发送请求呀
document.body.append(oScript);
//重页面删除 避免多次调用jsonp。在页面结构中积累大量script元素
document.body.removeChild(oScript);
}
</script>
</body>
</html>
jsonp函数封装实现:
(当然,这个封装是借鉴其他大佬的,但是当时年轻无知,忘记保存人家的链接了,所以,对不住了大佬)
/**
url: string
params: obj
cb: function
cbN: string
**/
function jsonp(url, params, cb, cbN) {
// 兼容处理
let queryString = url.indexOf('?') === -1 ? '?' : '&';
// 拼接参数
for(let k in params) {
if(params.hasOwnProperty(k)) {
queryString += `${k}=${params[k]}&`;
}
}
// 产生回调函数名子
const cbName = 'jsonp' + Math.random().toString().replace('.', '');
// 生成script标签
const oScript = document.createElement('script');
// 请求资源
oScript.src = `${url}${queryString}${cbN}=${cbName}`;
// 全局注册回调函数
window[cbName] = function() {
// 调用回调
cb(...arguments);
// 从body中删除
document.body.removeChild(oScript)
}
// 插入到body里
document.body.appendChild(oScript);
}
//下面部分,代码测试,可以直接把上面例子的script标签内容替换为下面代码段 + jsonp函数
const inp = document.getElementsByClassName('inp')[0];
function addList(data) {
const list = document.getElementsByClassName('list')[0];
let str = '';
data.result.forEach(ele => {
str += `<li>${ele[0]}</li>`
})
list.innerHTML = str;
}
inp.oninput = function() {
jsonp('https://suggest.taobao.com/sug', {
q: inp.value
}, addList, 'callback')
}
上面就是jsonp分享,喜欢前端的同学,喜欢分享交流的同学,欢迎关注我。
如果有错误的地方,麻烦指正,谢谢各位。