JavaScript 進階知識 - Ajax篇

image

Ajax

前言

前面咱們已經學習了js基礎知識和一些簡單的特效,基本上已經可以寫出一個帶有特效的靜態頁面了,爲何還要稱之爲靜態頁面呢?由於網頁裏的數據都是寫死的,真正的工做中,咱們是要經過Ajax技術,去後臺獲取數據的。因此在本篇文章,我會向你們介紹下什麼是Ajax技術,而且它的實現原理是什麼。javascript

1. 服務器端技術基礎

1.1 服務器

在學習 Ajax以前,咱們首先須要知道什麼是服務器。

一、什麼是服務器?php

服務器的本質其實就是一臺電腦,不過它不像通常的電腦同樣擁有鼠標鍵、鍵盤、顯示器等輸入設備,它直接就是一個主機,裏面只有主板、硬盤、 cpu、內存而且性能比通常計算機的性能更高,穩定性更強。
  • 經過網絡爲其餘計算機提供應用服務的計算機就是服務器。
  • 有別於普通的PC,服務器性能更好、安全性更高、穩定性更強。
  • 服務器運行在有特定環境要求的地方
  • IDC(對氣候、能源、消防、建築、安保等要求。

服務器外觀圖:css

image

image

二、服務器提供什麼服務html

根據需求的不一樣,服務器的種類也有所不一樣。
  • 網頁服務器(Web Server)
  • 郵件服務器(Mail Server)
  • 數據庫服務器(Database Server)
  • FTP服務器(FTP Server)
  • 域名服務器(DNS Server)

三、服務器操做系統:前端

  • Windows Server
  • LinuxDebianUbuntuCentOSFedora

四、服務器的應用軟件:java

  • Web服務器(又稱:http服務器,主要提供文檔的瀏覽功能,文本、圖片、視頻、音頻)。mysql

    • IISWindows
    • Apache
    • Nginx
  • 數據庫服務器jquery

    • SQL Server
    • Oracle
    • MySQL

1.2 客戶端

客戶端: 經過網絡向服務器請求服務的計算機就是客戶端(手機、電腦);web

客戶端軟件: 在客戶端計算機上運行的與服務器通信的軟件就叫客戶端軟件;ajax

單機軟件: 在客戶端計算機上運行的不訪問網絡的軟件叫作單機軟件;

1.3 軟件開發架構

軟件開發架構分爲兩種,分別是 C/S架構和 B/S架構。

一、C/S架構:

C/S,是 Client:(客戶端)和 Server(服務器)兩個單詞的簡寫,指的是客戶端應用程序與服務器端應用程序通信的軟件開發架構。

對於C/S架構,最爲常見的例子就是網絡遊戲,好比LOL,若是不聯網就沒法使用。

優勢:

  • 因爲是原生的應用,因此顯示的效果會更加酷炫;
  • 性能較高,能夠將一部分計算的工做放在客戶端上,這樣服務器只須要處理數據便可。

缺點:

  • 重量級,必須要安裝app
  • 軟件須要用戶去更新,而且要考慮不一樣的設備訪問。

二、B/S架構

B/S,是 Browser:(瀏覽器)和 Server(服務器),兩個單詞的簡寫,指的是 Web瀏覽器與服務器端應用程序通信的軟件開發架構。

如今全部的網站都是B/S架構,好比知乎、網易雲音樂、百度...,用戶只需使用瀏覽器就能訪問服務器;

優勢:

  • 輕量級,不須要安裝客戶端,用戶不須要主動去更新內容,只須要開發人員更改服務器的內容便可;
  • 多設備同步,全部數據都在網上。

缺點:

  • 性能較低,若是是很酷炫的頁面,那麼現階段還實現不了;
  • 移動設備兼容性較好,可是瀏覽器兼容性較差。

image

1.4 網絡基礎

一、IP地址

IP地址是網絡上每一臺設備通信時的身份標識(就像身份證、手機號)。

IP地址長什麼樣子呢?

192.168.10.10

好比,百度的IP地址就是:

119.75.213.61

特殊的IP地址-表明本機:

127.0.0.1

如何查看當前IP地址?

打開命令行工具,直接輸入「ipconfig」
ipconfig 命令

二、域名

域名簡單的說,就是給 IP地址起一個容易記憶的名字(就比如人的名字同樣)例如百度的域名: www.baidu.com

由於IP地址記憶起來很是不方便,因此平常生活中用戶經過域名來訪問服務器更加方便。

特殊的域名:localhost(表明本機)。

三、DNS 服務器

什麼是 DNSDNS( Domain Name Server),其實就是域名服務器。

輸入網址後的訪問流程(域名->DNS->IP地址)

查看域名與IP地址的對應關係(ping 命令)

能夠用Hosts文件讓本身的電腦變成一個屬於本身的DNS服務器。

image

四、網絡端口(Port)

端口是指計算機與外界進行通信的數據出口(入口),每一個端口爲不一樣的應用傳輸不一樣數據。

端口號: 每個端口都有一個端口號。範圍是從065535

端口號一般跟在IP地址後面,用冒號分隔。例如:192.168.1.1:80www.jd.com:80

經常使用端口號: 80(HTTP)3306(MySQL)21(FTP)

查看本機被佔用的端口狀況(命令行輸入:netstat

image

五、數據庫

按照數據結構來組織、存儲和管理數據的倉庫,軟件開發行業通常指的是數據庫軟件,常見的有 OracleMySQL等。

特色:

  • 數據共享,多用戶同時訪問數據的穩定性;
  • 故障恢復,數據庫軟件,提供了一套方法,能夠用來發現錯誤,而且修復錯誤。
  • 減小數據冗餘,因爲你們均可以使用同一套數據,沒有必要重複建立。

DBA數據庫管理員:

從事管理和維護數據庫管理系統(DBMS)的相關工做人員的統稱。保證數據庫的穩定性、安全性、完整性和高性能。

2. Web 服務器

2.1 Web服務器的做用

  • 能夠經過瀏覽器訪問或查看Web服務器上的文件資源。
  • 文件資源能夠是HTML網頁、文本、圖片、視頻、音頻、Web服務器程序等。

2.2 AMP 集成環境

AMPA:ApacheM:MySQLP:PHP

一、Apache:

世界排名第一的服務器軟件,特色是:簡單速度快,性能穩定。

二、MySQL:

體積小、速度快、使用成本低,並且仍是開源。

三、PHP:

超文本預處理器,直接將代碼嵌入到HTML文檔中執行,簡單易學,容易上手。

2.3 Web服務器軟件的安裝

在本身的Windows電腦上Web服務器軟件 - Wamp

WampServer: Wamp就是 WindowsApacheMysqlPHP集成安裝環境,即在 window下的 apache
phpmysql的服務器軟件。 PHP擴展、 Apache模塊,開啓/關閉鼠標點點就搞定,不再用親自去修改
配置文件了, WAMP它會去作。不再用處處詢問 php的安裝問題了, WAMP一切都搞定了,這個軟件
windows平臺上使用的較多。

下載WampWamp官網

安裝Wamp:安裝的時候要區分版本(64位,32位),點擊下一步下一步。

注意:安裝目錄的路徑不能出現中文。

程序安裝成功以後,任務欄裏面的小圖標是綠色的話,說明安裝成功。

image

剛剛上面提到過,域名:localhostIP地址:127.0.0.1均可以打開本地服務器:

image

image

當出現wamp頁面的時候說明軟件安裝成功。

2.4 安裝的建議與問題

  • 問題1:沒法安裝軟件(請檢查安裝軟件的版本與操做系統匹配)
  • 問題2:安裝完成後,web服務器沒有正常運行(測試web服務器的端口號是否被佔用)
  • 建議1:64位版本、32位版本要分清
  • 建議2:安裝目錄的路徑不要有中文
  • 建議3:提示默認瀏覽器和默認編輯器的設置可忽略
  • 建議4:安裝時建議關閉防火牆
  • 建議5:若是已安裝其餘的Web服務器軟件請先關閉

2.5 Wamp服務器的使用

一、基本功能使用:

修改語言 右擊任務欄中的軟件小圖標==> language ==> chinese

image

Web服務器的啓動、中止、運行: 左擊小圖標 (修改配置文件以後,必定要重啓服務器);

image

功能介紹:Apache

image

其中兩個配置文件後面可能須要修改,因此這裏須要知道在哪找到它們。

看下它的配置文件-httpd.conf,其中 #表示的是註釋的意思。

image

功能介紹:MySQL

image

看下它的配置文件-my.ini,其中 ;表示的是註釋的意思:

image

功能介紹:PHP Apache是一個web服務器,它自己是不能解析PHP語言的,因此這裏也集成了一個PHP解析器

image

看下它的配置文件-php.ini,其中 ;表示的是註釋的意思:

image

2.6 Wamp服務器的簡單配置

一、爲Web服務配置一個域名(僅限本機使用的域名)

找到C:\Windows\System32\drivers\etc\hosts文件並修改

image

將本地的IP設置一個新的域名lxh.com,重啓Wamp服務器,在地址欄裏輸入lxh.com就會跳轉到服務器頁面:

image

二、自定義Web服務器的根目錄

咱們能夠看到,當咱們輸入本地域名或者 IP的時候,都會彈出來服務器的界面,假如我想要打開一個文件的時候怎麼辦呢?這時候咱們就須要配置服務器的根目錄,只要是在根目錄裏面的文件,均可以經過服務器打開。

查找並打開安裝目錄D:\wamp64\bin\apache\apache2.4.23\conf\extra\httpd-vhosts.conf文件:

image

打開修改配置文件,其中ServerName指的是域名,咱們能夠將第一步配好的本地域名地址寫上去;DocumentRoot D:/lxhAjax<Directory "D:/lxhAjax/">是自定義Web服務器的根目錄爲D:/lxhAjax文件夾

image

image

三、爲Web服務器配置虛擬主機(一臺Web服務器當多臺用)

在同一局域網下別人能夠經過你的 IP訪問你的 Web服務器文件夾。
  • httpd-vhosts.conf 文件中查找 Require local
  • Require local 改爲 Require all granted

image

不過建議你們不要這樣作,安全性不高,電腦裏面的東西會被別人看到。

四、注意事項

  • php5.6 如下版本要設置php默認編碼,default_charset = UTF-8,不然PHP程序可能沒法正確顯示中文。
  • httpd.conf文件設置DocumentRoot前,先檢查是否已經關閉了虛擬主機,不然可能致使設置無效。
  • 默認狀況下Wamp服務器只能被本機訪問,若是向被局域網的其餘電腦訪問須要修改配置

    • httpd-vhosts.conf 文件中查找 Require local
    • Require local 改爲 Require all granted
  • 檢查網絡是否是通的 ping 對方IP
  • 檢查防火牆是否開啓,若是開啓將不能正常被訪問
  • 確保端口沒有被其它程序佔用
  • #」表示註釋
  • 配置文件每一行不要增長多於的空格。不然服務器容易報錯。
  • 修改配置要格外當心,禁止無心修改其它內容

3. HTTP傳輸協議

網絡協議約定了網絡計算機之間數據的傳輸的方式、數據的格式等。

常見的網絡應用底層協議:

  • HTTPHTTPS超文本傳輸協議
  • FTP文件傳輸協議
  • SMTP簡單郵件傳輸協議

HTTP協議:

HTTP即超文本傳輸協議,網站是基於 HTTP協議的,好比咱們在開發網站中常用 cssjs、圖片等等都是基於該協議傳輸的。

組成部分:

HTTP協議是對請求(Request)和響應(Response)的報文內容進行了約束和規範。

請求: 客戶機向服務器發送數據

響應: 服務器向客戶機發送數據

image

發送並請求請求報文,接收響應報文,這種獲取數據的方式咱們稱之爲HTTP協議。

3.1 請求報文

請求是由客戶端發起,其規範格式爲:請求行、請求頭、請求主體。

image

一、請求行:

由請求方法、請求 URLHTTP協議及版本構成
GET /code/login.php?username=123&password=123 HTTP/1.1
POST /code/login.php HTTP/1.1

二、請求頭:

這裏設置的主要是一些信息,包含客戶端,服務器。
  • User-Agent:瀏覽器的具體類型,如:User-Agent:Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0
  • Accept:瀏覽器支持哪些數據類型,如:Accept: text/html,application/xhtml+xml,application/xml;q=0.9;
  • Accept-Charset:瀏覽器採用的是哪一種編碼,如:Accept-Charset: ISO-8859-1
  • Accept-Encoding:瀏覽器支持解碼的數據壓縮格式,如:Accept-Encoding: gzip, deflate
  • Accept-Language:瀏覽器的語言環境,如:Accept-Language zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
  • Host:請求的主機名,容許多個域名同處一個IP地址,即虛擬主機。Host:www.baidu.com
  • Connection:表示是否須要持久鏈接。Keep-Alive/closeHTTP1.1默認是持久鏈接,它能夠利用持久鏈接的優勢,當頁面包含多個元素時(例如Applet,圖片),顯著地減小下載所須要的時間。要實現這一點,Servlet須要在應答中發送一個Content-Length頭,最簡單的實現方法是:先把內容寫入ByteArrayOutputStream,而後在正式寫出內容以前計算它的大小。如:Connection: Keep-Alive
  • Content-Length:表示請求消息正文的長度。對於POST請求來講Content-Length必須出現。
  • Content-Type:WEB服務器告訴瀏覽器本身響應的對象的類型和字符集。例如:Content-Type: text/html; charset='gb2312'
  • Content-EncodingWEB服務器代表本身使用了什麼壓縮方法(gzip,deflate)壓縮響應中的對象。例如:Content-Encoding:gzip
  • Content-LanguageWEB服務器告訴瀏覽器本身響應的對象的語言。
  • Cookie:最經常使用的請求頭,瀏覽器每次都會將cookie發送到服務器上,容許服務器在客戶端存儲少許數據。
  • Referer:包含一個URL,用戶從該URL表明的頁面出發訪問當前請求的頁面。服務器能知道你是從哪一個頁面過來的。Referer: http://www.baidu.com/

三、請求體:

這裏是提交給服務器的數據

須要注意的是,若是是往服務器提交數據,須要在請求頭中設置Content-Type:application/x-www-form-urlencoded(在ajax中須要手動設置);

3.2 響應報文

響應報文是服務器發回給客戶端的。組成部分有狀態行,響應頭,響應主體。

image

一、狀態行:

由協議版本號、狀態碼和狀態信息構成
HTTP/1.1 200 OK

常見的狀態碼:

  • 1XX:信息狀態碼

    • 100 Continue 繼續,通常在發送post請求時,已發送了http header以後服務端將返回此信息,表示確認,以後發送具體參數信息
  • 2XX:成功狀態碼

    • 200 OK 正常返回信息
    • 201 Created 請求成功而且服務器建立了新的資源
    • 202 Accepted 服務器已接受請求,但還沒有處理
  • 3XX:重定向

    • 301 Moved Permanently 請求的網頁已永久移動到新位置。
    • 302 Found 臨時性重定向。
    • 303 See Other 臨時性重定向,且老是使用 GET 請求新的 URI。
    • 304 Not Modified 自從上次請求後,請求的網頁未修改過。
  • 4XX:客戶端錯誤

    • 400 Bad Request 服務器沒法理解請求的格式,客戶端不該當嘗試再次使用相同的內容發起請求。
    • 401 Unauthorized 請求未受權。
    • 403 Forbidden 禁止訪問。
    • 404 Not Found 找不到如何與 URI 相匹配的資源。
  • 5XX: 服務器錯誤

    • 500 Internal Server Error 最多見的服務器端錯誤。
    • 503 Service Unavailable 服務器端暫時沒法處理請求(多是過載或維護)。

二、響應頭:

  • Date:響應時間
  • Server:服務器信息
  • Last-Modified:資源最後修改時間 由服務器自動生成
  • ETag:資源修改後生成的惟一標識,由服務器自動生成
  • Content-Length:響應主體長度
  • Content-Type:響應資源的類型

三、響應主體:

即服務端返回給客戶端的內容;

4. Ajax 編程

Asynchronous Javascript And XML(異步的 JavascriptXML)。

4.1 Ajax的基本概念

思考:

咱們訪問一個普通網站時,當瀏覽器加載完HTMLCSSJS之後,網站就固定了,若是網站內容發生改變,必須刷新網頁後,才能看到更新內容。

Ajax概念:

在瀏覽器中,咱們可以不刷新頁面,經過Ajax的方式去獲取一些新的內容。

  • Ajax 不是一門的新的語言,而是對現有技術的綜合利用。
  • 本質是在HTTP協議的基礎上以異步的方式與服務器進行通訊。
  • 核心是經過瀏覽器端的js幫咱們預約義的一個異步對象XMLHttpRequest來完成的

AJAX是一種用於建立快速動態網頁的技術。經過在後臺與服務器進行少許數據交換,AJAX可使網頁實現異步更新。這意味着能夠在不從新加載整個網頁的狀況下,對網頁的某部分進行更新。

優勢:

  • 頁面無刷新,用戶體驗好;
  • 異步通訊,更加快的響應能力;
  • 減小冗餘請求,減輕了服務器負擔;
  • 基於標準化的並被普遍支持的技術,不須要下載插件或者小程序

缺點:

  • 瀏覽器對XMLHttpRequest對象的支持度不足,存在兼容性;
  • Ajax幹掉了back按鈕,即對瀏覽器後退機制的破壞;
  • 對搜索引擎的支持比較弱;
  • 存在必定的安全問題;
  • 沒法用URL直接訪問;
  • 開發調試工具的缺少。

Ajax應用場景:

  • 場景1 數據驗證
  • 場景2 按需取數據
  • 場景3 自動更新頁面

Ajax 包含如下五個部分:

Ajax並不是一種新的技術,而是幾種原有技術的結合體。它由下列技術組合而成。
  • 使用CSSXHTML來表示。
  • 使用DOM模型來交互和動態顯示。
  • 數據互換和操做技術,使用XMLXSLT
  • 使用XMLHttpRequest來和服務器進行異步通訊。
  • 使用javascript來綁定和調用。

傳統Web應用程序與Ajax Web應用程序對比:

image

主要的差異,其實不是JavaScript,不是HTML/XHTMLCSS,而是採用了XMLHttpRequest來向服務器異步的請求XML數據。

同步:

  • 必需要等前面的任務完成,才能繼續後面的任務,必定要按順序執行。

異步:

  • 指某段程序執行時不會阻塞其它程序執行,其表現形式爲程序的執行順序不依賴程序自己的書寫順序。
  • 其優點在於不阻塞程序的執行,從而提高總體執行效率。
  • XMLHttpRequest能夠以異步方式的處理程序。

4.2 建立Ajax

Ajax的原理簡單來講,就是經過 XMLHttpRequest對象來向服務器發送異步請求,從服務器得到數據,而後用 javascript來操做 DOM而更新頁面。其中最關鍵的一步就是從服務器得到請求數據。

一、建立XMLHttpRequest對象:

Ajax的核心是 XMLHttpRequest對象,它是 Ajax實現的關鍵,發送異步請求、接受響應以及執行回調都是經過它來完成。

現代瀏覽器:

全部現代瀏覽器( IE7+FirefoxChromeSafari 以及 Opera)均內建 XMLHttpRequest 對象。
var xhr = new XMLHttpRequest();

老版本IE:

老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 對象:
var xhr = new ActiveXObject("Microsoft.XMLHTTP");

爲了應對全部的現代瀏覽器,包括IE5IE6,請檢查瀏覽器是否支持XMLHttpRequest對象。若是支持,則建立 XMLHttpRequest 對象。若是不支持,則建立ActiveXObject

兼容性處理:

var xhr = null;
if(window.XMLHttpRequest){
     //  IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執行代碼
    xhr = new XMLHttpRequest();
}else{
    // IE6, IE5 瀏覽器執行代碼
    xhr = new ActiveXObject("Microsoft.XMLHTTP");
}

XMLHttpRequest對象的屬性和方法:

image

二、準備請求,設置請求的url等參數:

首先經過 open()方法初始化 XMLHttpRequest對象,接受三個參數:
// 規定請求的類型、URL 以及是否異步處理請求。
xhr.open(method,url,async);

method: 表示的是請求類型的字符串,能夠是「GET」或者「POST」。

GET請求:

xhr.open("GET","demo.php",true);

POST請求:

xhr.open("POST","demo.php",true);

url: 第二個參數是要做爲請求發送目標的URL

async: 第三個參數是truefalse,表示請求是以異步仍是同步的模式發出。(默認爲true,通常不建議爲false

  • false:同步模式發出的請求會暫停全部javascript代碼的執行,直到服務器得到響應爲止,若是瀏覽器在鏈接網絡時或者在下載文件時出了故障,頁面就會一直掛起。
  • true:異步模式發出的請求,請求對象收發數據的同時,瀏覽器能夠繼續加載頁面,執行其餘javascript代碼

三、發送請求:

經過 XMLHttpRequest對象的 send()方法,向服務器發送請求。
xhr.send();

GET請求:

通常狀況下,使用 Ajax提交的參數多數是些簡單的字符串,能夠直接使用 GET方法將要提交的參數寫到 open方法的 url參數中,此時 send方法的參數爲 null或爲空。
// get請求是將數據拼接在url後面的
xhr.open("GET",demo.php?name=tsrot&age=24,true);
xhr.send(null);

POST請求:

若是須要像 HTML表單那樣 POST數據,請使用 setRequestHeader()來添加 HTTP頭。而後在 send()方法中規定你但願發送的數據:
// post請求須要加一個請求頭,而且使用send方法將數據進行發送
xhr.open("POST",demo.php,true);
xhr.setRequestHeder("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
xhr.send(...);

四、處理響應:

當服務器收到瀏覽器發送的數據後,會響應一個內容,由於不知道何時數據響應回來,因此提供了一個事件方法 onreadystatechange。每當 readyState改變的時候就會觸發 onreadystatechange事件, readyState屬性:存有 XMLHttpRequest的狀態信息。
xhr.onreadystatechange = function(){
    // 爲了保證數據完整回來,咱們通常會判斷兩個值
     if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
    }
}

onreadystatechange:當處理過程發生變化的時候執行裏面的函數

readyStateajax處理過程

  • 0:請求未初始化(尚未調用 open())。
  • 1:請求已經創建,可是尚未發送(尚未調用 send())。
  • 2:請求已發送,正在處理中(一般如今能夠從響應中獲取內容頭)。
  • 3:請求在處理中;一般響應中已有部分數據可用了,可是服務器尚未完成響應的生成。
  • 4:響應已完成;您能夠獲取並使用服務器的響應了。

status狀態碼屬性(詳見上面狀態碼類型):

  • 200:」OK
  • 404: 未找到頁面

responseText:得到字符串形式的響應數據;

4.3 Ajax實現一個簡單的聊天室

基本html結構:

<h3>簡單的Ajax實例聊天室</h3>
<div class="chatbox">
    <!-- 聊天記錄界面 -->
    <div class="messages"></div>
    <!-- 輸入界面 -->
    <div class="form">
        <div class="input"><textarea></textarea></div>
        <div class="btn">
            <input type="button" class="send" value="發送">
            <input type="button" class="clear" value="清屏">
        </div>
    </div>
</div>

image

js部分:

// 1-發送按鈕註冊點擊事件
var send = document.querySelector(".send");
var clear = document.querySelector(".clear");
var messages = document.querySelector(".messages");
var textarea = document.querySelector(".input").children[0];
send.onclick = function() {
    // 1-獲取輸入的內容 動態建立一個p標籤 添加到 messages中
    var p = document.createElement("p");
    var content = textarea.value;
    if (content != "" && content.trim()) {
        p.innerText = content + ":Levi";
        messages.appendChild(p);
        p.className = "self";
        textarea.value = "";
    }

    // 2-建立Ajax請求
    var xhr;
    if (window.XMLHttpRequest) {
        //  IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執行代碼
        xhr = new XMLHttpRequest();
    } else {
        // IE6, IE5 瀏覽器執行代碼
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }

    xhr.open('post', 'chat.php', true);
    // post請求的時候,須要使用setRequestHeader()添加響應頭
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
    xhr.send("message=" + content);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var reply = xhr.responseText;
            var p = document.createElement("p");
            p.innerText = "網友:" + reply;
            p.className = "other";
            messages.appendChild(p);
        }
    }

}

// 3-清屏按鈕
clear.onclick = function() {
    messages.innerHTML = "";
}

// 4-回車鍵觸發發送按鈕
textarea.onkeydown = function(e) {
    e = window.event || e;
    if (e.keyCode == 13) {
        send.onclick();
        e.preventDefault();
    }
}

PHP部分:

<?php 
     header('Content-Type:text/html;charset=utf-8');

        /*建立 對話的隊列 */
        $message = array(
            '你好呀!',
            '幹嗎?',
            '我在睡覺。',
            '上課吧',
            '騙你的',
        );

        /*隨機的取了一句話*/
        /*array_rand 去某個數組的隨機索引*/
        echo $message[array_rand($message)];

        sleep(1);
?>

PHP部分咱們能夠不用深究,只須要知道請求的數據message,在php裏其實就是一個隨機字符串。

效果圖:

image

4.4 複雜的數據格式介紹

HTTP協議中,全部數據最終的傳輸格式所有都是字符串。若是想要在 HTTP協議中傳輸一些複雜類型的數據,如數組、對象等,沒法直接實現。

後臺只有一個,可是開發語言卻有不少種,一種後臺格式的數據,如何適應所有開發語言的需求呢?因此須要一個統一的數據格式來在各個語言之間傳遞數據。

4.4.1 XML數據格式

XML( Extensible Markup Language),可擴展標記語言。它也是一個標記語言,因此它裏面也是標籤,而且也有文檔聲明。

XML文件的基本格式:

<!-- 1-聲明文檔 version:版本 encoding:編碼 -->
<?xml version = "1.0" encoding="UTF-8"?>

<!-- 2-xml必需要有根節點 root-->
<root>
    <!-- name age相對於對象 -->
    <name>Levi</name>
    <age>18</age>
</root>

注意:

  • 必須有一個根元素
  • 不能夠有空格、標籤不能夠以數字、下劃線、或其餘特殊符號開頭,大小寫敏感;
  • 不可交叉嵌套;
  • 特殊符號要使用實體;
  • 註釋和HTML同樣

雖然能夠描述和傳輸複雜數據,可是其解析過於複雜而且體積較大,因此實際開發已經使用不多了。

Ajax請求XML數據:

首先,新建一個XML數據格式的文件-data.xml

<?xml version = "1.0" encoding="UTF-8"?>

<root>
    <name>Levi</name>
    <age>18</age>
</root>

新建一個PHP文件-xml.php

<?php
    // 設置數據解析格式爲xml解析方式
    header("Content-Type:application/xml");
    
    // 將數據返回給前端
    $xml = file_get_contents("data.xml");
    echo $xml;
?>

html裏面經過Ajax得到數據:

var xhr = new XMLHttpRequest();
xhr.open("get","xml.php");
xhr.send();
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4 && xhr.status ==200){
        console.log(xhr.responseXML); // 返回XML形式的響應數據
        // DOM裏面的api在xml裏面一樣適用
        console.log(xhr.responseXML.getElementByTagName("name")[0].innerHTML);  // 打印 Levi
    }
}

responseXML:得到XML形式的響應數據。

Ajax中獲取到XML數據以後,須要經過xhr.responseXML這個屬性來獲取數據,獲取數據的時候能夠直接使用DOM提供的APIresponseText也能夠獲取到數據,可是獲取到的是字符串,沒法經過dom`api`來操做。

4.4.2 JSON數據格式

JSON( JavaScript Object Notation),是一種輕量級的數據交換格式,獨立語言。

json有別於通常的對象,雖然json也是鍵值對的存在,可是json的鍵必需要加雙引號,而通常的js對象能夠不用加。

json數據的基本格式:

data:[
    { "name":"zs", "age":18, "skill":"吹牛" },
                       ...
    { "name":"ww", "age":28, "skill":"睡覺" }
]

Ajax請求json數據:

前面咱們知道了,前端在拿後臺數據的時候,對後臺數據處理提供了兩個方法,一個是對字符串處理的 responseText方法,還有一個是對 XML格式處理的 responseXML方法,可是惟獨沒有處理 json數據的方法,因此咱們須要藉助於 json內置對象的 JSON.parse方法,將後臺的返回的 json字符串,轉換成 json對象。
JSON.parse(xhr.responseText);

新建一個PHP文件-json.php

<?php
    // 設置數據解析格式爲json格式
    header("Content-Type:application/json");
    
    $person = array('name' =>'Levi' ,'age'=>18,'skill'=>'帥' );
    
    // json_encode 將對象數據轉換成json格式的數據返回前端
    echo json_encode($person);
?>

html裏面經過Ajax得到數據:

var xhr = new XMLHttpRequest();
    xhr.open("get", "01-json.php");
    xhr.send();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            // 前端拿後臺數據的時候,只有兩種方式 responseText和responseXML
            // 沒有單獨爲json數據提供一個方法,因此須要將json字符串經過JSON.parse()方法,轉換成對象jianrong
            var jsonStr = xhr.responseText;
            var jsonObj = JSON.parse(jsonStr);
            console.log(jsonObj);  // 打印的是一個對象
        }
    }

總結方法:

json字符串,轉換成一個對象:JSON.parse(jsonStr);

// 注意,json字符串裏面的屬性必須是雙引號包裹,單引號包裹會報錯
var jsonStr = '{"name":"Levi","age":18,"skill":"帥"}';
var obj = JSON.parse(jsonStr);
console.log(obj); // 打印對象 {name: "Levi", age: 18, skill: "帥"}

將對象轉換成json格式的字符串:JSON.stringify;

var obj = {
    name: "Levi",
    age: "18",
    skill: "帥"
};
var jsonStr = JSON.stringify(obj);
console.log(jsonStr); //打印{"name":"Levi","age":"18","skill":"帥"}

4.5 Ajax代碼的封裝

一個頁面中,確定不僅是一處須要 ajax請求,因此咱們能夠將它封裝成一個函數。

Ajax對象獲取響應頭屬性:

xhr.getAllResponseHeaders();   // 獲取所有響應頭信息 
xhr.getResponseHeader('key');  // 獲取指定頭信息

代碼封裝:

// 封裝前須要考慮的因素
// 1- 請求的方式
    // get: 須要將數據拼接在url以後
    // post: 須要加一個請求頭,而且使用send方法將數據進行發送
// 2- 請求的url地址
// 3- 須要發送的數據
// 4- 添加回調函數success,將請求到的數據返回給調用的函數
    // 判斷服務器返回的是什麼格式的數據(經過響應頭)
        // a- xhr.getAllResponseHeaders();  獲取所有響應頭信息 
        // b- xhr.getResponseHeader('key'); 獲取指定頭信息 
function ajax(options) {
    // 默認值處理
    // 設置默認的請求方式爲type
    options.type = options.type || "get";
    // 設置默認的請求地址爲當前地址欄地址
    options.url = options.url || location.href;
    // 設置默認的請求同步或者異步
    options.async = options.async || "true";
    // 設置請求參數data的默認值
    options.data = options.data || {};
    // 處理用戶傳進來的請求參數(data)對象
    var dataArr = [];
    for (var k in options.data) {
        dataArr.push(k + "=" + options.data[k]);
    }
    var dataStr = dataArr.join("&");

    // 異步請求對象兼容性處理
    var xhr;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        // IE6及其如下版本   
        xhr = new ActiveXObjcet('Microsoft.XMLHTTP');
    };

    // 判斷當前的請求方式,若是是get,將數據拼接在地址後面
    xhr.open(options.type, options.type == "get" ? options.url + "?" + dataStr : options.url, options.async);
    // 當是post請求的時候,須要設置請求頭
    if (options.type == "post") {
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    }
    // 發送數據,當是post方式的時候,發送數據
    xhr.send(options.type == "get" ? null : dataStr);
    if (options.async) {
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                // 判斷請求的數據是什麼類型的
                var type = xhr.getResponseHeader("Content-Type");
                var result;
                if (type.indexOf("json") != -1) {
                    // 若是是json格式的數據,就將其轉換成js對象
                    result = JSON.parse(xhr.responseText);
                } else if (type.indexOf("xml") != -1) {
                    // 若是是xml格式的數據,直接返回responseXML
                    result = xhr.responseXML;
                } else {
                    // 若是兩種格式都不是,直接返回responseText
                    result = xhr.responseText;
                }
                // 將處理好的數據進行傳遞
                options.success(result);
            }
        }
    } else {
        // 若是是同步的話就不須要在監測狀態改變的狀況了
        var type = xhr.getResponseHeader("Content-Type");
        var result;
        if (type.indexOf("json") != -1) {
            result = JSON.parse(xhr.responseText);
        } else if (type.indexOf("xml") != -1) {
            result = xhr.responseXML;
        } else {
            result = xhr.responseText;
        }
        options.success(result);
    }
}

// 調用ajax請求
ajax({
    url: "json.php",
    type: "get",
    data: {name: "levi",age: 18},
    success: function(data) {
        console.log(data);
    }
});
ajax({
    url: "xml.php",
    type: "get",
    data: {name: "levi",age: 18},
    success: function(data) {
        console.log(data);
    }
});

5. jQuery中的Ajax操做

前面的《 jQuery入門詳解》中已經講到了如何經過 jQuery操做 Ajax,這裏再爲你們總結一遍。

一、$.ajax()方式經常使用參數解析:

方法 做用
url 請求的地址
type 請求的方式
dataType 告訴jQuery,須要按照什麼格式對服務器返回的數據進行解析,默認json
data 數據
success 請求成功的回調函數
error 請求失敗的回調函數
beforeSend 請求發送以前調用的函數
complete 不論請求是成功仍是失敗的,只要請求完成就會調用
timeout 設置請求超時時間

示例代碼:

$.ajax({
    // 請求的地址
    url: "04-data.php",
    // 請求的方式
    type: "get",
    // 告訴jQuery,須要按照什麼格式對服務器返回的數據進行解析,默認json
    dataType: "json",
    // 數據
    data: {
        msg: "我是來請求數據的"
    },
    // 請求成功的回調函數
    success: function(data) {
        console.log(data);
    },
    // 請求失敗的回調函數
    error: function() {
        console.log("失敗了");
    },
    // 請求發送以前調用的函數
    beforeSend: function() {
        console.log("請求發送以前調用的函數");
        // 若是返回一個false,那麼就會阻止整個請求的發送
        // return false;
        // 用法:能夠用做表單驗證,當表單內容符合規範的時候發送ajax請求,當不符合的時候就不發送ajax請求
    },
    // 不論請求是成功仍是失敗的,只要請求完成就會調用
    complete: function() {
        console.log("請求完成了");
    },
    // 設置請求超時時間(單位:ms),超過這個時間後,就不會請求了
    timeout:2000
});

二、jQuery中的serialize方法:

serialize方法會將表單中全部的內容拼接成 key=value&key=value這樣的字符串。

經過這種方式就不要再去手動獲取表單中的內容的

<form id="form">
    <input type="text" name="username">
    <input type="text" name="pwd">
    <input type="text" name="phonenumber">
    <input type="text" name="email">

    <button id="btn">獲取數據</button>
</form>

<script src="jquery.min.js"></script>
<script>
    $(function() {
        $('#btn').click = function() {
            var dataStr = $('#form').serialize();
            $.ajax({
                url: "json.php",
                //data這個參數能夠接收對象,也能夠接受 key=value&key=value的這種字符串
                data: dataStr,
                type: "post"
            });
        }
    });
</script>

三、jQuery中的serializeArray方法:

上面的方法咱們能夠看到,獲取整個數據的時候,是很簡單,可是想要進行校驗的話就很難,由於上面的方法獲取的是一個字符串,不能進行校驗,因此此時咱們須要另一個方法, jQuery中的 serializeArray方法。
<form id="form">
    <input type="text" name="username">
    <input type="text" name="pwd">
    <input type="text" name="phonenumber">
    <input type="text" name="email">

    <button id="btn">獲取數據</button>
</form>

<script src="jquery.min.js"></script>
<script>
    $(function() {
        $('#btn').click = function() {
            // 獲取到的數組拼接成字符串
            var dataArr = $('#form').serializeArray();
            $.ajax({
                url: "json.php",
                data: dataArr,
                type: "post"
            });
        }
    });
</script>

示例代碼:ajax模擬表單校驗及註冊

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

<head>
    <meta charset="UTF-8">
    <title>sing in page</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background-color: #F7F7F7;
        }
        
        ul {
            margin: 0;
            padding: 50px;
            list-style: none;
        }
        
        .register {
            width: 800px;
            margin: 50px auto;
            background-color: #FFF;
            border: 1px solid #CCC;
            border-radius: 5px;
        }
        
        li {
            display: flex;
            margin: 20px 0;
        }
        
        label,
        input {
            display: block;
            float: left;
            height: 46px;
            font-size: 24px;
            box-sizing: border-box;
            color: #333;
        }
        
        label {
            width: 200px;
            line-height: 46px;
            margin-right: 30px;
            text-align: right;
        }
        
        input {
            width: 320px;
            padding: 8px;
            line-height: 1;
            outline: none;
            position: relative;
        }
        
        input.code {
            width: 120px;
        }
        
        input.verify {
            width: 190px;
            margin-left: 10px;
        }
        
        input.disabled {
            background-color: #CCC !important;
        }
        
        input[type=button] {
            border: none;
            color: #FFF;
            background-color: #E64145;
            border-radius: 4px;
            cursor: pointer;
        }
        
        .error {
            color: red;
            margin-left: 10px;
            font-size: 12px;
            line-height: 46px;
        }
        
        .tips {
            position: fixed;
            top: 0;
            width: 100%;
            height: 40px;
            text-align: center;
        }
        
        .tips p {
            min-width: 300px;
            max-width: 400px;
            line-height: 40px;
            margin: 0 auto;
            color: #FFF;
            display: none;
            background-color: #C91623;
        }
    </style>
</head>

<body>
    <div class="register">
        <form id="ajaxForm">
            <ul>
                <li>
                    <label for="name">用戶名</label>
                    <input type="text" name="name" class="name" id="name">
                    <span class="error"></span>
                </li>
                <li>
                    <label for="pass">請設置密碼</label>
                    <input type="password" name="pass" class="pass" id="pass">
                </li>
                <li>
                    <label for="repass">請確認密碼</label>
                    <input type="password" name="repass" class="repass" id="repass">
                </li>
                <li>
                    <label for="mobile">驗證手機</label>
                    <input type="text" name="mobile" class="mobile" id="mobile">
                </li>
                <li>
                    <label for="code">短信驗證碼</label>
                    <input type="text" name="code" class="code" id="code">
                    <input type="button" value="獲取驗證碼" class="verify">
                </li>
                <li>
                    <label for="submit"></label>
                    <input type="button" class="submit" value="當即註冊" id="submit">
                </li>
            </ul>
        </form>
    </div>
    <div class="tips">
        <p>用戶名不能爲空</p>
    </div>

    <script src="../05-Form-Validation/js/jquery.min.js"></script>
    <script>
        /*
         * 1.獲取短信驗證碼
         * 1.1 當沒有輸入手機號的時候  提示請輸入手機號
         * 1.2 手機號格式不正確        提示請輸入正確的手機號
         * 1.3 調獲取短信驗證碼接口
         * 1.4 顯示正在發送中  不能再次發送(防止重複提交)
         * 1.5 當接口成功  按照後臺的計時時間  進行倒計時
         * 1.6 當接口失敗  提示短信接口繁忙 恢復按鈕
         * 1.7 倒計時完成以後  恢復按鈕
         * */

        /*
         * 2.註冊
         * 2.1 當沒有輸入用戶名的時候  提示請輸入用戶名
         * 2.2 調註冊接口
         * 2.3 顯示正在提交 不能再次發送(防止重複提交)
         * 2.4 當接口成功
         *     狀態碼 10000 成功
         *     狀態碼 10001 失敗 提示用戶  用戶名已註冊  表單後
         *     狀態碼 10002 失敗 沒輸用戶  請輸入用戶名
         *     恢復按鈕
         * 2.5 當接口失敗  恢復按鈕
         * */
        $(function() {
            /* 警告顯示提示 */
            var showTip = function(tip) {
                $(".tips p").html(tip).fadeIn(500).delay(1000).fadeOut(500);
            };

            /* 1.獲取短信驗證碼 */
            $(".verify").on("click", function() {
                /* 當前按鈕指定變量 */
                var $btn = $(this);
                /* 判斷當前按鈕是否有disabled屬性,有的話說明已經被點擊了,就不讓再點擊了 */
                if ($btn.hasClass('disabled')) {
                    return false;
                }

                /* 獲取手機號 */
                var mobile = $.trim($('#mobile').val());
                /* 判斷是否輸入內容,沒有的話提示信息 */
                if (!mobile) {
                    showTip('請輸入手機號');
                    return false;
                }
                /* 判斷手機格式 不正確的話提示信息 */
                var regPhone = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/;
                if (!regPhone.test(mobile)) {
                    showTip('請輸入正確的手機號');
                    return false;
                }
                /* 調取短信驗證碼接口 */
                $.ajax({
                    url: 'registerCode.php',
                    type: 'post',
                    dataType: 'json',
                    data: {
                        mobile: mobile
                    },
                    success: function(data) {
                        if (data.code == 10000) {
                            /* 給發送成功的按鈕添加一個倒計時 */
                            var time = parseInt(data.result.time);
                            var timer = setInterval(function() {
                                time--;
                                $btn.val(time + '秒後再次獲取');
                                /* 倒計時完成以後  恢復按鈕*/
                                if (time <= 0) {
                                    $btn.val('獲取驗證碼').removeClass('disabled');
                                    clearInterval(timer);
                                }
                            }, 1000);
                        } else {
                            /* 邏輯上的失敗 */
                            $btn.val('獲取驗證碼').removeClass('disabled');
                        }
                    },
                    error: function() {
                        /* 當接口失敗,提示短信接口繁忙 */
                        showTip('短信接口繁忙');
                        $btn.val('獲取驗證碼').removeClass('disabled');
                    },
                    beforeSend: function() {
                        /* 點擊以後,顯示正在發送 */
                        $btn.val('正在發送...').addClass('disabled');
                    }
                });
                $btn.addClass('disabled');
            });
            /* 2.註冊功能的實現 */
            $('.submit').on('click', function() {
                /* 當前點擊的按鈕 */
                var $btn = $(this);
                /* 正在請求當中 不能再次點擊 */
                if ($btn.hasClass('disabled')) {
                    return false;
                }
                var username = $("#name").val().trim();
                var password = $("#pass").val().trim();
                var repeatPassword = $("#repass").val().trim();
                var code = $("#code").val().trim();
                var phoneNum = $("#mobile").val().trim();

                /* 調註冊接口 */
                $.ajax({
                    type: 'post',
                    url: 'register.php',
                    data: {
                        name: username,
                        pass: password,
                        repass: repeatPassword,
                        code: code,
                        mobile: phoneNum
                    },
                    dataType: 'json',
                    // beforeSend: function() {
                    //     /* 顯示正在提交 不能再次發送(防止重複提交)*/
                    //     $btn.val('正在提交...').addClass('disabled');
                    // },
                    success: function(data) {
                        /* 當接口成功 */
                        /* 狀態碼 10000 成功 */
                        if (data.code == 10000) {
                            /* 提示+跳轉登陸頁 */
                            showTip('恭喜' + data.result.name + '註冊成功,3後秒自動前往登陸頁');
                            setTimeout(function() {
                                location.href = 'http://www.baidu.com/';
                            }, 3000);
                        } else if (data.code == 10001) {
                            /* 輸入框提示 */
                            $('.error').html('用戶名已註冊');
                            /* 恢復按鈕 */
                            $btn.val('當即註冊').removeClass('disabled');
                        } else if (data.code == 10002) {
                            showTip('請輸入用戶名');
                            /* 恢復按鈕 */
                            $btn.val('當即註冊').removeClass('disabled');
                        }
                    },
                    error: function() {
                        showTip('系統繁忙!');
                        $btn.val('當即註冊').removeClass('disabled');
                    }
                })
            });
        });
    </script>
</body>

</html>

效果圖:

image

6. 模板引擎的使用

模板引擎,就是將一段已經寫好模板,使用數據進行填充以後生成 html

6.1 模板引擎的使用步驟

一、引入模板引擎插件:

<script src="template-web.js"></script>

二、建立script標籤,注意類型是type="text/template",而且要有一個id,模板內部是須要渲染的內容:

<script type="text/template" id="tpl">
    <div>我叫  </div>
    <div>我今年  歲</div>
</script>

三、調用template方法,將數據渲染到模板內:

var obj = {
    name:"Levi",
    age:18
}

// template("模板的id",要將什麼數據渲染到模板中)
var html = template("tpl",obj);

四、回到上面的模板部分,在裏面添加佔位符:

<script type="text/template" id="tpl">
    // {{}} ==> 就是佔位符
    // name 和 age 對應的就是對象obj裏面的兩個屬性
    <div>我叫{{name}}</div>
    <div>我今年{{age}}歲</div>
</script>

五、打印調用的字符串:

var html = template("tpl",obj);
console.log(html);  // 打印的就是div字符串

6.2 模板引擎的其餘用法

一、$data:

模板一級特殊變量可使用 $data,指的就是獲取的數據;
<!-- 能夠經過$data拿到 template函數傳進來的數據 -->
{{$data["name"]}}

二、條件語句:

{{if value}}...{{/if}}
{{if value1}}...{{else if value2}}...{{/if}}

示例:

<!-- 注意結束必需要有{{/if結尾}} -->
{{if age >= 18}}
    <div>我成年了</div>
{{else}}
    <div>我沒有成年了</div>
{{/if}}

三、循環語句:

$index指的是獲取當前遍歷的索引值; $value指的是獲取當前遍歷的元素。
{{each target}}
    {{$index}} {{$value}}
{{/each}}

示例:

<script type="text/template" id="tpl">
    {{each idol}}
        <!--$index 獲取當前遍歷的索引-->
        <!--$value 獲取當前正在遍歷的元素-->
        <div>第{{$index}}號偶像:{{$value.name}}</div>
    {{/each}}
</script>

<script>
    var obj = {
        name: "Levi",
        age: 18,
        idol:[
            {name : "劉德華"},
            {name : "張學友"},
            {name : "古天樂"}
        ]
    }
    var html = template("tpl", obj);
    // 引入jQuery
    $('body').append(html);
</script>

效果圖:

image

注意:這裏介紹一個語法as v i,能夠手動指定$index$value的量

<script type="text/template" id="tpl">
    {{each idol as v i}}
        <!--i 獲取當前遍歷的索引-->
        <!--v 獲取當前正在遍歷的元素-->
        <div>第{{i}}號偶像:{{v.name}}</div>
    {{/each}}
</script>

四、變量:

<!--能夠在模板引擎中聲明變量-->
{{set temp = data.content}}

示例:

<script type="text/template" id="tpl">
    <!-- 設置一個變量val 用來接收數據的name值 -->
    {{set val = name}}
    <!-- 打印的就是對象的name屬性對應的值 -->
    {{val}}  
</script>

<script>
    var obj = {
        name: "Levi",
        age: 18,
        idol:[
            {name : "劉德華"},
            {name : "張學友"},
            {name : "古天樂"}
        ]
    }
    var html = template("tpl", obj);
    // 引入jQuery
    $('body').append(html);
</script>

五、標籤「@」的用法:

當一個標籤在頁面以字符串形式顯示的時候,加上「 @」後就會當成標籤去解析。

首先根據後臺數據,動態建立一個信息表格:

前端渲染:

<button id="btn">獲取數據生成表格</button>
<script type="text/template" id="tpl">
    <table width="600" border="1">
        <thead>
            <tr>
                <th>姓名</th>
                <th>年齡</th>
                <th>性別</th>
                <th>頭像</th>
            </tr>
        </thead>
        <tbody>
            <!-- $data 是個一級變量,表示的就是返回的數據 -->
            {{each $data as v i}}
            <tr>
                <td>{{v.name}}</td>
                <td>{{v.age}}</td>
                <td>{{v.gender}}</td>
                <td>{{v.avatar}}</td>
            </tr>
            {{/each}}
        </tbody>
    </table>
</script>

<script src="template-web.js"></script>
<script>
    $(function() {
        // 點擊按鈕,發送Ajax請求
        $("#btn").click(function() {
            $.ajax({
                url: "tableData.php",
                type: "get",
                success: function(data) {
                    var htmlStr = template("tpl", data);
                    $("body").append(htmlStr);
                }
            });
        });
    });
</script>

後臺數據:

<?php 
    header("Content-Type:application/json;charset=utf-8");

    echo '[{"name": "小喬", "age": 18, "gender": "male", "avatar": "<img src=\"1.jpg\" />"}, {"name": "大喬", "age": 18, "gender": "female", "avatar": "<img src=\"1.jpg\" />"}, {"name": "甄姬", "age": 18, "gender": "male", "avatar": "<img src=\"1.jpg\" />"}]';
 ?>

根據上面的代碼,咱們能夠動態生成一個表格:

image

看到問題所在了,在後臺請求回來的圖片地址直接以字符串的形式渲染到頁面上了。

解決辦法:只須要在頭像佔位那一欄裏面加一個@符號

{{each $data as v i}}
<tr>
    <td>{{v.name}}</td>
    <td>{{v.age}}</td>
    <td>{{v.gender}}</td>
    <td>{{@v.avatar}}</td>
</tr>
{{/each}}

再看效果圖:

image

此時頭像就能夠顯示了。

6.3 模板引擎原生語法

一、原生語法:

<%= name %>

二、原生語法判斷語句:

<%= if(age == 18){ %>
<div>我滿18歲了</div>
<% } %>

三、原生語法循環語句:

<% for(var i = 0; i < arr.length; i++){ %>
    <!-- 遍歷數據數組arr,將它裏面的name屬性顯現出來 -->
    <div><%= arr[i].name %></div>
<% } %>

6.4 案例:Ajax模擬請求json數據案例

json數據模擬後臺數據:

{
    "code": 200,
    "msg": "OK",
    "result": [{
            "tc_id": "193",
            "tc_name": "一代天驕葫蘆娃",
            "tc_roster": "攻城獅",
            "tc_gender": "1",
            "tc_cellphone": "",
            "tc_email": "",
            "tc_status": "0",
            "tc_birthday": "1970-01-01",
            "tc_join_date": "2017-06-15"
        },
        {
            "tc_id": "194",
            "tc_name": "用愛感化司馬ad",
            "tc_roster": "攻城獅",
            "tc_gender": "0",
            "tc_cellphone": "",
            "tc_email": "",
            "tc_status": "0",
            "tc_birthday": "1970-01-01",
            "tc_join_date": "1970-01-01"
        }
    ]
}

html頁面Ajax請求部分:

<!-- 引入jQuery -->
<script src="jquery.min.js"></script>
<!-- 引入模板引擎 -->
<script src="template-web.js"></script>
<!-- 模板引擎渲染數據 -->
<script type="text/template" id="tpl">
    <table>
        <thead>
            <tr>
                <th>序號</th>
                <th>暱稱</th>
                <th>性別</th>
                <th>生日</th>
                <th>花名</th>
            </tr>
        </thead>
        <tbody>
            {{each $data.result as v i}}
            <tr>
                <!-- 序號從1開始,因此就是遍歷的下標加1 -->
                <td>{{i + 1}}</td>
                <!-- 暱稱 -->
                <td>{{v.tc_name}}</td>
                <!-- 後臺數據返回的是數字字符串。判斷下以男女顯示 -->
                <td>{{if v.tc_gender == "1"}}男{{else}}女{{/if}}</td>
                <!-- 生日 -->
                <td>{{v.tc_birthday}}</td>
                <!-- 花名 -->
                <td>{{v.tc_roster}}</td>
            </tr>
            {{/each}}
        </tbody>
    </table>
</script>
<script>
    $(function() {
        $.ajax({
            url: "teacher.json",
            type: "get",
            success: function(data) {
                // 通常後臺都會提供接口文檔,能夠知道數據的名字,也能夠直接打印數據在控制檯中查看
                console.log(data);
                // 當數據成功返回以後,將數據以表格的形式打印在頁面當中
                if (data.code == 200) {
                    var htmlStr = template("tpl", data);
                    $('body').append(htmlStr);
                }
            }
        });
    });
</script>

效果圖:

image

6.5 案例:Ajax提供數據實現瀑布流

經過後臺提供的圖片信息,以及圖片連接,動態的生成瀑布流。

首先須要後臺提供的接口文檔:

接口地址:waterfull.php
請求方式:get
接口參數:page:當前是第幾頁 pageSize:當前頁面須要顯示數據的條數
返回類型:json
返回數據:{page: 2,items:[{path:"./images/0011.jpg",text:"文本信息"}...]}  
          page:下一頁的頁碼
          items:返回當前頁的數據
                path:圖片地址
                text:圖片下方的文本

後臺程序以及數據(僅攻參考,不是前端的活):

waterfull.php:

<?php
    header('Content-Type:text/html; charset=utf-8');
    
    /*獲取數據  字符串*/
    $data = file_get_contents('data.json');

    /*轉化php對象? 須要對其操做*/
    $data = json_decode($data);

    /*頁碼*/
    $page = $_GET['page'];
    /*條數*/
    $pageSize = $_GET['pageSize'];

    /*獲取數據的起始索引*/
    $offset = ($page - 1) * $pageSize;

    /*slice 從什麼位子開始切割 切割多少條*/
    $result = array_slice($data, $offset, $pageSize);

    /*下一頁的頁碼*/
    $page++;

    /*轉化json字符串 輸出到前端*/
    echo json_encode(array('page'=>$page, 'items'=>$result));/*{items:[]}*/

    /*延時1秒返回數據*/
    sleep(1);

?>

data.json:

[
    {
        "path": "./images/001.jpg",
        "text": "一支素筆,一杯花茶,一段時光,淺笑又安然一場盛世的繁華,願不傾城,不傾國,只傾我全部。只爲過簡單安穩的生活,單純不平凡。一支素筆,一杯花茶,一段時光,淺笑又安然。早安!"
    },
                    ...
    {
        "path": "./images/100.jpg",
        "text": "青春,青春,一場盛世不平凡。一支素筆,一杯花茶,一段時光,淺笑又安然一場盛世的繁華,願不傾城,不傾國,只傾我全部。只爲過簡單安穩的生活,單純不平凡。一支素筆,一杯花茶,一段時光,淺笑又安然。早安!"
    }
]

Ajax請求後臺數據,動態渲染瀑布流:

  • 經過接口文檔,以及活動模板將數據渲染到頁面;
  • 利用jQuery裏面封裝的瀑布流插件,實現瀑布流的佈局;
  • 經過頁面中的「加載更多」按鈕,控制顯示的數據數量;

Ajax請求數據:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>瀑布流</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: "Microsoft Yahei";
            background: #f5f5f5;
        }
        .box {
            width: 1200px;
            margin: 0 auto;
            padding-top: 40px
        }
        .box > .items {
            position: relative;
        }
        .box > .items > .item {
            width: 220px;
            box-shadow: 2px 2px 2px #999;
            position: absolute;
        }
        .box > .items > .item > p {
            margin: 0;
            padding: 10px;
            background: #fff;
        }
        /*目的是固定高度且不同*/
        .box > .items > .item > img {
            width: 100%;
            display: block;
            height:  px;
        }

        /*目的是固定高度且不同*/
        .box > .items > .item:nth-child(4n) > img {
            width: 100%;
            display: block;
            height: 450px;
        }
        .box > .btn {
            width: 280px;
            height: 40px;
            margin: 30px auto;
            text-align: center;
            line-height: 40px;
            background-color: #CCC;
            border-radius: 6px;
            font-size: 24px;
            cursor: pointer;
        }
        .box > .loading {
            background-color: transparent;
        }
    </style>
</head>

<body>
    <div class="box">
        <div class="items">
            
        </div>
        <div class="btn">加載更多</div>
    </div>

    <script type="text/template" id="tpl">
        {{each items as v i}}
        <div class="item">
            <img src="{{v.path}}" alt="">
            <p>{{v.text}}</p>
        </div>
        {{/each}}
    </script>

    <script src="jquery.min.js"></script>
    <script src="jquery.waterfull.js"></script>
    <script src="template-web.js"></script>

    <script>
    // ajax 請求,一進來先調用一次
    function render(){
        $.ajax({
            url:"waterfull.php",
            type:"get",
            dataType:"json",
            data:{
                // 3-首先去按鈕中,找下一頁的page屬性,若是沒有的話,給一個默認值1
                page:$(".btn").data("page") || 1,
                pageSize: 15
            },
            success:function(data){
                var htmlStr = template("tpl",data);
                $(".items").append(htmlStr);
                $(".items").waterfull();
                // 1-將請求回來的數據中表示下一頁的頁碼page存入btn的自定義屬性data-page中
                // 2-給按鈕加上一個自定義屬性page  值就是後臺返回的page屬性
                //   7-當數據加載完以後,還要將按鈕變成正在加載,而且要移除disabled這個類
                $(".btn").data("page",data.page).text("加載更多").removeClass("disabled");
                // 8-數據是有限的,假如請求不到數據以後,須要將按鈕置成disabled,而且加上文字「沒有更多數據了」
                if(data.items.length == 0){
                    $(".btn").text("沒有更多數據了").addClass("disabled");
                }
            }
        });
    }
    render();

    // 4-點擊加載更多的時候,調用Ajax請求
    $(".btn").click(function(){
        // 6- 一進來縣普安段一下按鈕有沒有disabled這個類,若是有的話讓它不能夠被點擊
        if($(this).hasClass("disabled")){
            return false;
        }
        render();
        // 5-點擊按鈕以後改變按鈕的狀態,和文本
        $(this).text("正在加載中");
        $(this).addClass("disabled");
    });
    </script>
</body>
</html>

其中jquery.waterfull.js爲封裝的jQuery瀑布流插件:

(function() {
    $.fn.waterFull = function() {
        //1. 肯定一共多少列
        var columns = 5;
        //2. 獲取每個元素的寬度
        var width = this.children().width();
        //3. 計算間隔
        var space = (this.width() - width * columns) / (columns - 1);
        //聲明數組來保存每一列當前的高度
        var heightArr = [];
        this.children().each(function(index, ele) {
            //4. 爲第一行的元素設置定位
            if (index < columns) {
                $(ele).css({
                    top: 0,
                    left: index * (width + space),
                });
                heightArr.push($(ele).height());
            } else {
                //除過第一行以外的全部的內容
                //先計算當前全部列中最短的列
                var minHeight = heightArr[0];
                var minIndex = 0;
                $.each(heightArr, function(index, value) {
                        if (minHeight > value) {
                            minHeight = value;
                            //找到了最短的列所在的索引
                            minIndex = index;
                        }
                    })
                    //將當前要擺放的元素的高度累加到當前列所對應的高度中
                heightArr[minIndex] += $(ele).height() + space;
                //就是最短列的高度加上間隔
                var top = minHeight + space;
                //由於已經找到了要把當前元素放在哪一列
                //因此直接使用列的索引計算便可
                var left = minIndex * (width + space);
                $(ele).css({
                    top: top,
                    left: left,
                })
            }
            //5. 將items的高度設置爲最高的那一列的高度
            var maxHeight = heightArr[0];
            $.each(heightArr, function(index, value) {
                maxHeight = maxHeight > value ? maxHeight : value;
            })
            console.log($(this));
            $(this).parent().height(maxHeight)
        });
    }
})()

效果圖:

image

除了手動點擊按鈕以外,咱們還能夠監聽滾動條的位置,當在底部的時候直接調用加載函數:

$(window).scroll(function(){
    // 獲取滾動條當前滾動的距離
    var scrollTop = $(this).scrollTop();
    // 獲取整個盒子的高度
    var boxHeight = $(".box").outerHeight();
    // 獲取可視區的高度
    var windowHeight = $(window).height();
    // 判斷當滾動條的高度大於等於盒子的高度減去可視區的高度的時候,調用加載函數
    if(scrollTop >= boxHeight - windowHeight){
        // 請求數據還須要判斷下有沒有disabled這個類,沒有的時候才能加載
        if(!$(".btn").hasClass("disabled")){
            render();
            $(".btn").text("正在獲取數據").addClass("disabled");
        }
    }
});

7. Ajax請求模擬軟件

Postman是一款模擬 Ajax請求的軟件,根據接口文檔,輸入請求地址,以及選擇請求的方式,再輸入須要請求的數據,就能模擬從後臺,獲取到數據。

image

根據圖片的註釋,咱們能夠大體瞭解這款軟件的用法,根據接口文檔填上信息,點擊右上角send,就會模擬發送Ajax請求,response返回請求的結果。

8. 同源策略

同源策略最初是在1995年時提出,到目前爲止全部瀏覽器都實行這個政策。

8.1 什麼是同源策略

最初它的含義是指,A網頁設置的 Cookie,B網頁不能打開,除非這兩個網頁"同源",所謂同源就是必需要知足三個條件:
  • 協議相同
  • 域名相同
  • 端口相同

舉個例子:

http://www.abc.com/home/index.html這個網址中,協議是http://,域名是www.abc.com,端口是80(默認端口能夠省略),下面看幾個例子:

URL 說明 是否容許通訊
http://www.a.com/a.html<br/>http://www.a.com/b.html 協議、域名、端口都相同 容許
http://www.a.com/a/a.html<br/>http://www.a.com/b/b.html 協議、域名、端口都相同,不一樣文件夾下 容許
http://www.a.com/a.html<br/>http://www.a.com:8000/b.html 協議、域名相同,端口不一樣 不容許
http://www.a.com/a.html<br/>https://www.a.com/b.html 域名、端口相同,協議不一樣 不容許
http://www.a.com/a.html<br/>https://www.b.com/b.html 協議、端口相同,域名不一樣 不容許
http://www.a.com/a.html<br/>http://70.32.92.74/b.html 協議、端口相同,域名和域名對應ip 不容許

8.2 同源策略的目的

同源策略的目的就是爲了保護用戶信息安全,防止惡意的網站竊取數據。

打個比方,你登陸了某個網站A,同時你又去瀏覽了另外一個網站B,若是B網站可以讀取你A網站裏存儲的cookie,會發生什麼?你在A網站裏面的信息,將會被泄露,更可怕的是,cookie每每用來保存用戶的登陸狀態,若是用戶沒有退出登陸,B網站就能夠冒充用戶進行操做。因此「同源策略」是必須得。

8.3 限制範圍

隨着互聯網的發展,「同源策略」愈來愈嚴格。目前若是非同源,共有三種行爲受到限制:
(1) Cookie、LocalStorage 和 IndexDB 沒法讀取。

(2) DOM 沒法得到。

(3) AJAX 請求不能發送。

雖然這些限制是必要的,可是有時很不方便,合理的用途也受到影響。

9. 跨域

同源策略規定, Ajax請求只能發給同源的網址,不然就報錯。
  • 因爲瀏覽器的同源策略,使用XHR對象進行跨域請求會直接被瀏覽器制止
  • html一些標籤中的src屬性也能夠發送請求,至關因而發送了一個get請求
  • src屬性中書寫的地址,發送出去的請求,是不會受到瀏覽器同源策略的限制的

下面介紹三種解決跨域的方法

9.1 JSONP

JSONP是服務器與客戶端跨源通訊的經常使用方法,最大的特色就是簡單適用。老式瀏覽器所有支持,服務器改造很是小。

實現原理:

jsonp的原理就是:動態的建立一個script標籤,將這個script標籤的src屬性設置爲要請求的地址url,將script標籤添加到頁面以後,src屬性會自動向url發送一個get請求,又因爲,後臺返回的數據格式比較特殊,是一個函數調用的語句,因此咱們提早定義好一個函數,那麼這個函數就會在請求成功以後自動被調用,數據也會被傳入到這個函數中,最終就相似於ajax請求的回調的效果!

<script>
    // url即請求的地址,賦值給動態建立的script標籤的src屬性
    function creatScriptTag(url,callback){
        // 一個頁面可能會有不少跨域請求,若是回調函數名寫死,那麼只能用一次
        // 隨機生成一個函數名,將回調函數以這個隨機生成的名字命名
        var callbackName = "jsonp" + new Data().getTime() + parseInt(Math.random() * 1000);
        // 將回調函數添加到window對象中,相似於添加了一個這個隨機函數名的一個全局函數
        window[callbackName] = callback;
        var script = document.createElement('script');
        script.setAttribute('type','text/javascript');
        // 注意,該請求的查詢字符串有一個callback參數,用來指定回調函數的名字,這對於JSONP是必需的。
        script.src = url + "?callback=" + callbackName;
        document.body.appendChild(script);
    }
    creatScriptTag("http://api.ajax.com/data.php", function(data){
        console.log(data);
    })
</script>

jQuery裏的JSONP:

jQuery中,發送 Ajax方法的時候,只要定義一個 dataType:"jsonp",便可實現跨域。

9.2 WebSocket

WebSocket是一種通訊協議,正常是由後臺操控,使用 ws://(非加密)和 wss://(加密)做爲協議前綴。該協議不實行同源政策,只要服務器支持,就能夠經過它進行跨源通訊。

下面是一個例子,瀏覽器發出的WebSocket請求的頭信息。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代碼中,有一個字段是Origin,表示該請求的請求源(origin),即發自哪一個域名。

正是由於有了Origin這個字段,因此WebSocket纔沒有實行同源政策。由於服務器能夠根據這個字段,判斷是否許可本次通訊。若是該域名在白名單內,服務器就會作出以下回應。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

(本篇完)

上一篇:JavaScript 進階知識 - 特效篇(二)

相關文章
相關標籤/搜索