封装jsonp函数需要考虑的因素:
(涉及到传参->函数+请求参数,需要为封装的jsonp添加形参)
function jsonp(options) {}
1、script标签的创建
var script = document.createElement('script');
2、请求地址中需要传递的参数、对参数进行拼接
var params = '';
// options中的data值为需要传递的请求参数,是要以key=value&key1=value1进行传递的,所以要进一步操作
for (var attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
3、避免同名函数的多次调用造成的函数覆盖-->采用随机命名法;需要将随机数小数点去掉
【注意】:下面提到的myJsonp是随意的,主要目的就是让函数名不相同,但是又不能只是数字
// 将生成的随机数中的点给去掉,再和函数名'myJsonp'拼接赋值给fnName
var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
4、 将函数变为script可以调用的函数
函数给到success意味着执行success()也就可以执行这个函数。
but:script脚本是执行不到success的,因为它并非全局作用域函数
so:要改为全局作用域,也就是window下,要以 [ ] 的格式,不能以 . 的格式
对象确实存在的属性才可以使用.,而变量只能使用 [ ]
window[fnName] = options.success;
5、将函数名、参数拼接到请求地址中,再将请求地址赋值给script的src值
将函数名同参数一起传递可以避免“手动控制服务器端和客户端的函数名一致”的麻烦
这样依赖,服务器端一个req.query.callback就可以获取到动态的函数名
script.src = options.url + '?callback=' + fnName + params;
6、将script追加到页面中
document.body.appendChild(script);
7、避免多次的调用而造成script的多次创建,当触发onload事件之后就给它从页面中删除
script.addEventListener('load', function() {
document.body.removeChild(script);
})
调用封装好的jsonp函数
服务器3000客户端html代码:
<body>
<button id="btn1">点我发送请求1</button>
<script>
var btn1 = document.getElementById('btn1');
btn1.addEventListener('click', function() {
jsonp({
// 请求地址
url: 'http://localhost:3001/better',
// 请求参数
data: {
firstname: 'xibing',
age: 18
},
success: function(data) {
alert('My name is:' + data.name);
}
})
})
</script>
</body>
服务器3001代码:(将函数名和(参数)进行拼接,然后通过send响应给客户端)
const express = require('express');
const jsonp = express();
jsonp.get('/better', (req, res) => {
const fnName = req.query.callback;
// 对客户端发来的数据进行改造
const name = req.query.firstname + '_G';
// 注意格式:对象内的key对应的value需要以双引号包裹哦
// const result = fnName + '({name:"xibing_G"})';
const result = fnName + '({name:"' + name + '"})';
res.send(result);
})
jsonp.listen(3001);
console.log('3001已监听');
(1)、客户端传送请求参数中有firstname:xibing
(2)、服务端通过req.query.firstname接收并进行改造,再放在函数中作为实参响应给客户端
(3)、客户端执行响应函数(已存在服务端加入的实参)
(4)、最后:函数体中的弹窗弹出客户端的内容+服务端对客户端传入的参数改造后的数据。
(5)、其中:客户端获取到响应内容【函数fnName(.....)】后开始调用响应结果,
因为已经将success放到全局中,所以这里调用到success完全没问题。
原理就是:
script会向服务器端发送请求之后去执行服务器端响应的内容
客户端端传递函数,函数经由服务器端进行改造(例如:传递实参)
客户端再将实参传递进去并调用这个函数(为了可以调用到,提前将函数放到全局下)