前端筆記之伺服器&Ajax(下)資料請求&解決跨域&三級聯動&session&堆疊

mufengsm發表於2019-04-15

一、請求後端的JSON資料

JSON是前後端通訊的互動格式,JSON(JavaScript Object Notation, JS 物件標記) 是一種輕量級的資料交換格式。

JSON是網際網路各個後臺與前代溝通必備格式,取代了原來的XML

XML資料格式特別“噁心”,現在市場上99%以上的資料格式都是JSON

工作中都是後端(JavaPHPNode)給我們提供JSON格式的資料,然後我們前端用Ajax去請求得到JSON資料,將JSON資料渲染在前端頁面中。但是伺服器給我們返回的資料是字串JSON,因此沒辦法打點呼叫屬性,下面我們要學習如何解析後端給我們返回的JSON


1.1 JSON解析方法1

獲取PHP中的JSON介面資料:

會發現伺服器給我們返回的資料是字串JSON,因此沒辦法打點呼叫屬性

l PHP中可以將陣列變為JSON,使用方法json_encode(陣列)

 

json_db.php後端提供JSON資料:

<?php
    header("Content-type","application/json");

    //用陣列模擬,然後給客戶端返回JSON格式的資料
    $arr = array("result"=> array(
            array("name" => "李白", "age" => 31, "sex"=>"男"),
            array("name" => "蘇軾", "age" => 32, "sex"=>"男"),
            array("name" => "王安石", "age" => 33, "sex"=>"男"),
            array("name" => "杜甫", "age" => 34, "sex"=>"男"),
            array("name" => "李清照", "age" => 35, "sex"=>"女")
        )
    );

    echo json_encode($arr); //將陣列變為JSON
?>

 

 前端請求php提供的介面,得到資料渲染在頁面

 $.get("php/json_db.php", function(data){
var dataObj = JSON.parse(data); //將後端返回的字串轉為JSON物件

//迴圈遍歷輸出
    for(var i = 0; i < dataObj.result.length;i++){
        var arr = dataObj.result[i];
        //上樹
        $("ul").append("<li>"+ arr.name + arr.age + arr.sex +"</li>")
        console.log(dataObj.result[i].age)
        console.log(dataObj.result[i].sex)
    }
 })

JSON.parse()        將JSON形式的字串轉換為JSON物件
JSON.stringify()   將JSON物件轉換為字串

 

獲取資料庫中的資料,以JSON的格式返回給前端

data_db.php後端提供JSON資料:

<?php
    //連線資料庫,引數:資料庫地址、使用者名稱、密碼
    mysql_connect('localhost', 'root', '123456');
    //選擇要操作的資料庫
    mysql_select_db("student");
    //設定編碼
    mysql_query("SET NAMES utf8");
    //寫執行插入的SQL語句,儲存到資料庫的表中
    $sql = "SELECT * FROM gz0902";
    //執行SQL語句,會返回成功插入的結果(條數)
    $result = mysql_query($sql);

    $arr = array(); //空陣列,迴圈遍歷新增進來的

    //迴圈遍歷賦值,新增到陣列
    while($row = mysql_fetch_array($result)){
        array_push($arr, $row);
    }
    //輸出JSON
    $resultJSON = array("result" => $arr);
    echo json_encode($resultJSON);

?>

 

 前端解析JSON

$.get("php/data_db.php", function(data){
   //將JSON形式的字串轉為真的JSON物件
   var dataObj = typeof data == "object" ? data : JSON.parse(data);
   for(var i = 0; i < dataObj.result.length;i++){
       var arr = dataObj.result[i];
       $("ul").append("<li>"+ arr.name + arr.age + arr.sex +"</li>")
       console.log(dataObj.result[i].age)
       console.log(dataObj.result[i].sex)
   }
})

 


1.2 JSON解析方法2

概述:eval()是系統預設的函式,是window物件方法,因此可以省略window直接使用。

      eval()函式可以將字串變為語句,把它作為JavaScript程式碼執行。

      eval()儘量少用,但是由於相容性好,所以該用的時候也要用

JavaScript為什麼不推薦使用eval

https://www.zhihu.com/question/20591877

var str = "alert(1+2+3)";
console.log(eval(str));

var data = "({a:100,b:200})";
var data = "{a:100,b:200}";
console.log(eval("("+ data +")"))

var fun = "function fun(){alert(1)};fun()";
console.log(eval(fun))

$.get("php/json_db.php", function(data){
    //將JSON形式的字串轉為真的JSON物件
    var dataObj = eval("(" + data + ")");
})

1.3 JSON解析方法3

第三種方法:使用JS的內建建構函式new Function()

引數:從第一個開始到倒數第二個都是形參,最後一個引數是執行的程式。

Function()函式能把字串變為語句:

var sum = new Function("a","b","c","return a+b+c");
console.log(sum(3,4,5));

// 等價於
function sum(a,b,c){
   return a+b+c;
}

$.get("php/json_db.php", function(data){
   //將JSON形式的字串轉為真的JSON物件
   var dataObj = (new Function("return" + data)());
   console.log(dataObj)
})

 


 

二、B/S結構

 

概述:Ajax這門技術它遵循同源策略也就說Ajax不能跨域

同源策略:它是由Netscape提出的一個著名的安全策略現在所有支援JavaScript的瀏覽器都會使用這個策略。

所謂的同源策略:域名、協議、埠相同

當一個瀏覽器的兩個tab頁分別開啟:百度和谷歌的頁面

當瀏覽器的百度tab頁執行一個指令碼的時候會檢查這個指令碼是屬於哪個頁面的,

即檢查是否同源,只有和百度同源的指令碼才會被執行。

如果非同源,那麼在請求資料時,瀏覽器會在控制檯中報一個異常,提示拒絕訪問。

跨域:其實就是訪問不在同一個伺服器上的資料,就形成了跨域。

比如:老師的伺服器IP192.168.1.100,但是訪問某同學的伺服器中的檔案,造成了跨域,會報錯


2.1 Ajax不能跨域

概述:Ajax不能跨域,就比如我們的程式,不能獲取百度、淘寶、京東伺服器的資料。

<script type="text/javascript">
     $.get("http://127.0.0.88/result.txt", function(data){
        console.log(data)
     })
</script>

提示:剛才模擬兩個伺服器之間請求資料,會發現Ajax不能跨域


 

2.2 JSONP跨域

跨域請求資料也是可以的,只不過Ajax這技術不行,而JSONP這種資料格式可以進行跨域。很多年前,瀏覽器是沒有跨域限制的,可以正常跨域,瀏覽器為了安全和隱私限制了Ajax跨域。

我們可以通過一些資料手段解決:

為什麼使用跨域?當請求不在同一個伺服器資料的時候就用跨域,或者偷資料的時候。

實現方式:HTML中用script標籤引用這個js檔案,其實就是對引用檔案的函式執行,此時函式定義在HTML中。

 

JSONP原理就是:將函式執行的部分,放到了伺服器上面。

<script type="text/javascript">
    function fun(data){
        console.log(data)
    }
</script>
<script src="http://127.0.0.88/fun_info.txt"></script>

提示:這是老師的本地靜態頁面,當訪問某個同學伺服器的時候,返回的資料來源於某同學伺服器。

將函式執行的部分放在伺服器上。當自己伺服器想獲取其他伺服器上面的資料,你必須宣告一個和其他伺服器上同名的函式。

 

這是http://127.0.0.88/fun_info.txt的資料

fun({"name":"陳雪凝","age":16, "sex":"女"});

提示:怎麼實現的?

答:script標籤當中的src屬性指向一個地址,發起了一次請求。

 

JSONP的優缺點:

優點:

與利用XHR物件傳送Ajax請求不同,JSONP可以跨越同源策略;

l JSONP的相容性好,可以在眾多瀏覽器中執行。

缺點:

只支援GET一種型別的HTTP請求,應用場景有限;

l 呼叫失敗時缺少必要的提示資訊,不方便排查問題;

存在一定的安全風險,但可以使用RefererToken校驗進行規避;

l 不便於控制;

l 沒有回撥函式的功能。


2.3原生JSONP跨越請求資料

<body>
    <button id="btn">發起請求(JSONP)</button>
</body>
<script type="text/javascript">
     var btn = document.getElementById("btn");

     //函式的定義的
     function fun(data){
        console.log(data)
     }

     //發起請求,獲取到函式執行部分
     btn.onclick = function(){
        //建立script標籤,並指定請求資料地址
        var oscript = document.createElement('script');
        oscript.src = "http://127.0.0.88/fun_info.txt";
       
        //上樹
        document.body.appendChild(oscript);
        //過河拆橋,拿完下樹
        document.body.removeChild(oscript);
     }
</script>

提示:script標籤發起一次請求後,就可以獲取到資料,然後讓元素下樹,不影響返回的資料。

 

Url中的callback對應的是函式的名

提示:如果想獲取別人伺服器上的JSONP資料,你必須宣告一個和別人伺服器上的同名函式(也可以改名)

<script type="text/javascript">
    function fetchJSON_comment98(data){
        console.log(data)
    }
</script>
<!-- <script type="text/javascript" src="http://127.0.0.88/result.txt"></script> -->
<script src="http://127.0.0.88/fun_info.txt"></script>
<script src="https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=598283&score=1&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1"></script>

2.4原生JSONP函式封裝

概述:封裝一個函式,這個函式的作用就是跨域請求別人伺服器的資料,使用者只需要傳進來,url和函式名。

<script type="text/javascript">
     var btn = document.getElementById("btn");

     function JSONP(url, callback){
        //給傳進來的匿名函式起名,並定義在全域性
        window.fun = callback;
        //建立DOM
        var oscript = document.createElement('script');
        oscript.src = url;
        //上樹
        document.body.appendChild(oscript);
        //過河拆橋,拿完下樹
        document.body.removeChild(oscript);
     }

     //發起請求
     btn.onclick = function(){
        JSONP("http://127.0.0.88/fun_info.txt", function(data){
            console.log(data);  //data資料是從函式執行部分傳過來的
        })
     }
</script>

2.5 jQueryJSONP跨域

概述:jQueryJSONP進行了封裝,jsonCallback就是傳進去的函式名字

 

獲取某個伺服器的JSON資料:

$.ajax({
   url:"http://127.0.0.88/fun_info.txt",
   dataType:"jsonp",
   jsonpCallback:"fun", //函式名
   success:function(data){
       console.log(data)
   }
})

 

獲取京東評論的資料:

$.ajax({
   url:"https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=598283&scor
e=1&sortType=5&page=0&pageSize=10",
   dataType:"jsonp",
   jsonpCallback:"fetchJSON_comment98",
   success:function(data){
       console.log(data)
   }
})

jQuery跨域的時候,url中的callback後面是函式的名稱,也可以自己修改函式名。

如果urlcallback後面是?號,不用寫jsonpCallback回撥函式,jQuery會隨機的命名函式。

$.ajax({
  url:"https://sclub.jd.com/comment/
productPageComments.action?callback=?&productId=598283&score=1&sortType=5&page=0&pageSize=10",
  dataType:"jsonp",
  success:function(data){
      console.log(data)
  }
})

下面就是jQuery隨機的函式名。

 


2.6三級聯動

<body>
    <select id="province"></select>
    <select id="city"></select>
    <select id="area"></select>
</body>
<script type="text/javascript" src="js/jquery-2.2.4.min.js"></script>
<script type="text/javascript">
    $.get("data/city.txt",function(data){
        //轉JSON物件
        var dataObj = JSON.parse(data);
        //迴圈所有資料,讓省份上樹
        $.each(dataObj.all, function(key,value){
            // console.log(key,value);
            var $option = $("<option>"+ value.name +"</option>");
            $("#province").append($option);
        });

        //當省的資料傳送變化時,執行以下方法
        var cityArr = [];
        $("#province").on("change", function(){
            //拿到當前選擇的省的名字
            var pro = $("#province option:selected").text();

            //遍歷省,得到市
            $.each(dataObj.all, function(item,val){
                if(val.name == pro){
                    for(var i = 0; i < val.city.length;i++){
                        $("<option>" + val.city[i].name + "</option>").appendTo('#city');
                    }
                    cityArr.push(val.city)

                    //遍歷得到區
                    $.each(val.city[0].area, function(index,val){
                        $("<option>" + val + "</option>").appendTo('#area');
                    })
                }

            })
        })

        //當市改變時觸發,改變區‘
        $("#city").on("change", function(){
            $("#area").empty(); //清空內容
            //獲取當前被選中的城市名字
            var city = $("#city option:selected").text();

            for(var i = 0; i < cityArr[0].length;i++){
                if(cityArr[0][i].name == city){
                    $.each(cityArr[0][i].area, function(index, val){
                        $("<option>" + val + "</option>").appendTo('#area');
                    })
                }
            }
        })

        //頁面載入初始化城市資料
        $("#province").triggerHandler('change');
    })
</script>

三、效果

3.1載入完畢顯示-原生的套路

<style type="text/css">
    div{
        width: 300px;
        height: 300px;
        background: url('./images/loading.gif') no-repeat;
    }
    img{display: none;}
</style>
<body>
    <div>
        <img src="./images/19.png" >
    </div>
</body>
<script type="text/javascript">
     var img = document.getElementsByTagName('img')[0];
     //當圖片載入完畢後,顯示
     img.onload = function(){
        img.style.display = 'block';
     }
</script>

3.2載入完畢顯示-jquery的套路

Image是系統當中內建的建構函式,因此可以直接使用,返回的是一個img元素物件;

<body>
    <div id="box"></div>
</body>
<script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
    // var img = document.createElement('img');
    var img = new Image();
    img.src = "./images/18.png";

    //載入完畢上樹
    $(img).load(function(){
        $(this).appendTo($('#box'));
    })
</script>

四、聊天室

聊天室製作思路:

使用者點選登入把輸入的使用者名稱傳給Login.php,Login.php接收後正則驗證使用者名稱是否合法,如果不合法給前端返回一個-1,exit返回
前端接收到返回是-1就提醒使用者重新輸入,如果合法就開啟會話session_start(),並且儲存使用者名稱,$_SESSION[name]=$name;且返回一個1給前端,
前端收到是1就登入成功,跳轉到聊天頁面(有中文記得宣告utf-8編碼),再開啟會話,讀取使用者名稱,判斷使用者按下回車時,將使用者名稱和輸入內容寫進資料庫,
資料庫再開會話接受資料,連線資料庫,插入資料,執行這條資料$result=mysql_query($sql);如果他是真就返回1,否則返回-1,
聊天頁面請求裡的函式接受到時1就把輸入框清空,起初有滾動條且捲動值是自己的高,開一個定時器,清空聊天框的內容,向資料庫get請求JSON資料,資料庫連線,
讀取資料表且排序(記得宣告JSON)執行這個表,宣告一個陣列,他有一個最大的鍵,迴圈拿去資料表中的項,存在一個變數,將這個變數push到我們宣告的資料最大的鍵裡,
它的值就是一個陣列,在pint_r輸出,記得把這個陣列轉成JSON,聊天頁面接收返回值它最大的鍵再存一個變數,迴圈這個變數,並且打點取資料上樹,定時器間隔請求。

 

概述:HTTP超文字傳輸協議,屬於短輪詢連結,發起一次請求與一次響應之後就斷開連結

PHP session 變數用於儲存有關使用者會話的資訊,或更改使用者會話的設定。Session 變數儲存的資訊是單一使用者的,並且可供應用程式中的所有頁面使用。

http://www.w3school.com.cn/php/php_sessions.asp

提示:session PHP有,JS也有,它是一個後臺給前端使用者發的一個‘信物’,可以分辨出誰是誰;

 

Session 的使用:

Session 不同於cookie,必須先啟動Session_start();

當第一次訪問網站的時候,Session_start()函式就會建立一個唯一的Session_ID。並自動通過HTTP的響應頭,將這個Session_ID儲存到客戶端的coookie,同時,也在伺服器端建立了一個以Session_ID命名的檔案,用於儲存。

這個使用者的會話資訊。當同一個使用者再次訪問這個網站的時候,也會自動的通過HTTP的請求頭將cookie中儲存的session_ID再次的攜帶過來,這時,Session_start()函式就不會再次的分配一個新的Session_ID,而是在伺服器端的硬碟中去尋找個這個Session_ID同名的Session檔案,將這之前的偽這個使用者儲存的會話資訊讀出來。在當前的指令碼中應用,達到跟蹤使用者的目的。

 

提示:PHP中的正則方法preg_match(正則字串,字串)返回一個布林值,exitPHPreturn語句。

免費API介面

https://www.zhihu.com/question/32225726

https://www.showapi.com/apiShow/apiMap

 


五、複習

5.1基本型別和引用型別

JavaScript語言有:語言核心、DOMBOM,複習語言核心部分。

JavaScript的資料型別有哪些:
    ● 基本型別值:number、string、boolean、undefined、null
    ● 引用型別值:Object、Array、Function、RegExp、Math、Date

為什麼要區分基本型別和引用型別?有以下兩點不一樣:

區分的方式是根據記憶體中儲存的位置而區分。

基本型別:在記憶體中佔用的空間是固定大小的,它們的值儲存在棧記憶體,通過值來訪問。

引用型別:大小不固定,棧記憶體中存放它們的地址指向的是堆記憶體中的物件,是按引用訪問。


5.2棧記憶體和堆記憶體

棧(stack)會自動的分配空間,會自動的釋放空間。

堆(heap)會動態的分配記憶體空間,大小不固定,也不會自動釋放空間。

計算機中儲存的媒介:

硬碟:文件、音樂、視訊、文件等(計算機斷電後,資料還保留),儲存空間【240G500G1T2T

記憶體:儲存的介質,讀取和寫入速度比硬碟快(計算機斷電後資料就沒了)。儲存空間【2G4G8G

CPU快取(cache):是位於CPU與記憶體之間的臨時儲存器,計算機斷電後資料也沒了,儲存空間【256KB2M4M8M】。

 

記憶體有五大空間:堆、棧、自由儲存空間、全域性、常量

區別1:基本型別在記憶體中都是“棧記憶體”儲存,引用型別值都是“堆記憶體”儲存。

先說說什麼是記憶體?

 

計算機的記憶體能存多少東西?

計算機系統有位數:32位、64

64位舉例:記憶體條一條內容有64位的2進位制的值,就是8bytes

記憶體條4G空間等於 4 * 1024 * 1024 * 1024bytes,也等於4 * 1024 * 1024 * 1024 ÷ 8個位元組。536870912

記憶體條8G空間等於 8 * 1024 * 1024 * 1024bytes,也等於8 * 1024 * 1024 * 1024 ÷ 8個位元組。1073741824

 

記憶體中儲存的資訊都有對應的地址。

 

基本型別值,都是記憶體中的一個小單元格中,字串如果太長,此時會用“連結串列”的形式去規劃記憶體,此時就會認為在一個地址中。

什麼是“棧”,類似光碟架的結構、或羽毛球筒。先放進去的,一定是最後被取出來的,進出都在一端,屬於“first in last out”【FILO】

 

 

記憶體條叫做做“棧記憶體”,本質原因就是記憶體會維持一個“空白區域”的清單:

 

現在根據上圖,如果程式設計師要var a=1;此時這個1被寫入到45533地址上,因為目前它是棧頂,45533就“出棧”。

var b=2;此時b被寫入在45534上,因為此時的棧頂是45533,就“出棧”。

此時寫var a =“哈哈”,此時a被釋放,45533重新回到棧頂,被改寫為“哈哈”的時候,此時再次出棧。等於45533的小單元格從1變為“哈哈”。

 

引用型別值,此時記憶體處理辦法是堆記憶體:

 var arr=[1,2,3,"J","Q","小王"];

 

此時稱為堆記憶體。

區別2:基本型別在進行賦值的時候,此時會在記憶體中克隆一份;引用型別,只傳地址。

 

 var arr=[1,2,3,"J","Q","小王"];

 var b = a;

 

a的更改也會影響b

注意:基本型別在當執行環境結束時被銷燬,而引用型別不會隨著執行環境結束而銷燬,只有當所有引用它的變數不存在時,這個物件才被垃圾回收機制回收。

 


 

相關文章