什么是跨域

ajax请求具有同源策略(1.同协议。2.同域名/同IP。3.同端口号)。其中三项任何一项不满足都会发生跨域问题

jsonp原理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <img src="https://t7.baidu.com/it/u=1951548898,3927145&fm=193&f=GIF">
</html>

我们在本地打开这个页面,图片会加载出来。同样的我们可以通过<script></script>标签来引入外部的js文件。src并没有同源问题。我们就可以将数据放在一个js文件里,将数据作为一个函数打的实参,然后在页面中,通过该函数的形参来接收这个数据。示例:

js文件:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script> //预先声明函数准备形参准备接收实参 function start(data) {
      alert(data); } </script>
    <!-- 引入后函数执行将实参传到形参中去,即将数据传送过去 -->
    <script src="test.js"></script>
</head>

<body>
</html>

jsonp功能实现

从原理上看,我们还有两个问题

  • 1)如何控制什么时候开始下载数据

  • 2)src地址的文件后缀名只能传.js吗?

首先看第一个问题

我们是通过script标签来引入数据,所以我们只需要决定什么时候创建这个script标签就能决定什么时候下载改数据。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script> function start(data) {
      alert(data); } </script>
    <!-- -->
    <!-- <script src="test.js"></script> -->
    <script> window.onload = function() {
      var bt1 =document.getElementById("bt1"); bt1.onclick = function() {
      //点击按钮后创建一个script标签 var script = document.createElement("script"); script.src = "test.js"; document.body.appendChild(script); } } </script>
</head>

<body>
    <button id="bt1">下载数据</button>
</body>
</html>

第二个问题

文件的后缀名有什么作用?

文件的后缀名只会告诉计算机用什么方式打开,对于计算机来说只有0和1,所以就算我们将test.js的后缀名该位.mp4等其它的格式,一样可以拿到我们的数据。

所以我们可以引入任何类型的文件,只要文件里面是我么你想要的代码。

根据上述过程总结出jsonp跨域的步骤

  • 1.先声明一个函数,该函数要有一个形参
  • 2.在需要下载数据的时候动态创建script标签,并设置script标签的src
  • 3.script标签插入完成后,执行声明的函数,将数据传到函数的形参中。

jsonp跨域传的数据必须是函数调用的格式。

天气查询案例

我们先看效果图

首先我们得有一个接口来获取数据,提供一个链接,天气数据接口

将API地址复制,然后在浏览器中打开会出现这样一段数据

我们也可以通过get请求直接在地址后面拼接?city=武汉,拿到想要的城市的天气。

然后我们再继续在后面拼接

访问的数据也发生变化,成为了函数调用

这样我们就能拿到想要的数据,接下来将数据展现在页面上

通过https://www.bejson.com/将数据格式化以下方便我们查看

我们只需要将weather里面的数组取出来放在表格中就可以了

我们在请求的时候同样的动态创建一个script标签并设置它的src

var script = document.createElement("script");
script.src = `https://query.asilu.com/weather/baidu/?city=${
     city.value}&callback=show`;
document.body.appendChild(script);

然后通过show()函数的形参接收数据,然后取出我们想要的内容,最后将内容添加的页面上去

		function show(data) {
   
            var t1 = document.getElementById("t1");
            var info = document.getElementById("info");
            info.innerHTML = data.city;
            var arr = data.weather;
            var str = ``;
            for(var i = 0;i < arr.length;i ++) {
   
                str += `<tr> <td>${
     arr[i].date}</td> <td>${
     arr[i].weather}</td> <td>${
     arr[i].wind}</td> <td>${
     arr[i].temp}</td> </tr>`;
            }
            t1.innerHTML = str;
        }

整个页面使用的是bootstrap,完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>天气查询</title>
    <link rel="stylesheet" href="bootstrap.css">
    <script> function show(data) {
      var t1 = document.getElementById("t1"); var info = document.getElementById("info"); info.innerHTML = data.city; var arr = data.weather; var str = ``; for(var i = 0;i < arr.length;i ++) {
      str += `<tr> <td>${
       arr[i].date}</td> <td>${
       arr[i].weather}</td> <td>${
       arr[i].wind}</td> <td>${
       arr[i].temp}</td> </tr>`; } t1.innerHTML = str; } </script>
    <script> window.onload = function () {
      var search = document.getElementById("search"); var city = document.getElementById("city"); search.onclick = function () {
      if (!city.value) {
      alert("请输入城市名"); } else {
      var script = document.createElement("script"); script.src = `https://query.asilu.com/weather/baidu/?city=${
       city.value}&callback=show`; document.body.appendChild(script); } } } </script>
</head>

<body>
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2>天气查询---当前城市为:<span id="info"></span></h2>
                <span id="info"></span>
            </div>
            <div class="panel-body">
                <div class="form-group">
                    <label for="city">城市名字</label>
                    <input type="text" class="form-control" id="city">
                </div>
                <button type="button" class="btn btn-primary form-control" id="search">点击查询</button>
            </div>
            <div class="panel-footer">
                <table class="table table-bordered table-hover">
                    <thead>
                        <tr>
                            <th>日期</th>
                            <th>天气</th>
                            <th>风向</th>
                            <th>气温</th>
                        </tr>
                    </thead>
                    <tbody id="t1">
                        
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</body>

</html>