淺談SPA
最近一直在學習關於Vue的一些知識,由於遇到了問題,去網上查詢資料,收穫頗豐,在此分享。
1. 什麼是SPA?
單頁Web應用(single page web application, SPA),就是隻有一張Web頁面的應用,是載入單個HTML頁面並在使用者與應用程式互動時動態更新該頁面的Web應用程式,是指在瀏覽器中執行的應用,在使用期間不會重新載入頁面。像所有的應用一樣,它旨在幫助使用者完成任務,比如“編寫文件”或者“管理Web伺服器”。可以認為單頁應用是一種從Web伺服器載入的富客戶端。
速度:更好的使用者體驗,讓使用者在web app感受native app的速度和流暢,
MVC:經典MVC開發模式,前後端各負其責,後端只需要提供資料介面
ajax:重前端,業務邏輯全部在本地操作,資料都需要通過AJAX同步、提交。
路由:在URL中採用#號來作為當前檢視的地址,改變#號後的引數,頁面並不會過載,這個也就是雜湊。
SPA也是當今網站開發技術的一種趨勢和潮流,畢竟前端三大框架不是蓋的~~,很多的傳統網站都在或者已經轉型為單頁Web應用,新的單頁Web應用網站(包括移動端平臺上面的)也雨後春筍湧現出來。
單頁Web應用和前端工程師們息息相關,因為主要的變革發生在瀏覽器端,用到的技術其實還是HTML+CSS+JavaScript,所有的瀏覽器都原生支援,當然有的瀏覽器因為具備一些高階特性,從而使得單頁Web應用的使用者體驗更上一層樓。關於單頁應用的優點和缺點,下一個問題就說。 單頁Web應用,顧名思義,就是隻有一張Web頁面的應用。瀏覽器一開始會載入必需的HTML、CSS和JavaScript,之後所有的操作都在這張頁面上完成,這一切都由JavaScript來控制。因此,單頁Web應用會包含大量的JavaScript程式碼,複雜度可想而知,模組化開發和設計的重要性不言而喻。
單頁Web應用程式的優點:
1.首先,最大的好處是使用者體驗,對於內容不改動的不需要載入整個頁面。這樣做好處頗多,因為資料層是和UI的分離,可以重新編寫一個原生的移動裝置應用程式而不用(對原有資料服務部分)大動干戈。
2.單頁面Web應用層程式最根本的優點是高效。它對伺服器壓力很小,消耗更少的頻寬,能夠與面向服務的架構更好地結合。
單頁Web應用程式的缺點:
雖然還有一些歷史遺留問題(大部分是針對HTML5的改進)以及SEO。如果你看中SEO,那你應該使用網站而不是Web應用。目前該技術還存在一些爭議,但這並不是重點,因為這種型別的體系架構為SAAS Web Apps提供了一個極大的可用性。
程式結構 -- 重點
單頁Web應用程式的結構很簡單:首先傳遞HTML文件框架;然後使用JavaScript修改頁面;緊接著再從伺服器傳遞更多資料然後再修改頁面,如此迴圈。 從效能的角度看,在現代瀏覽器中單頁面Web App已經能夠和普通應用程式相媲美,而且幾乎所有的作業系統都支援現代的瀏覽器。使用HTML+CSS+JavaScript編寫應用程式,能使更多的人們都加入到程式開發的行列。
這足以說明,在Web設計過程中標誌著Web將呈現一種新的趨勢,它將一個分離的功能層作為API並將表示層用APP的形式體現出來(HTML5或Native)
- 單頁面+API模式比基於應用程式的HTML多重頁面更加靈活,因為底層API可用於多種不同的上下文、形式因素和裝置型別。一旦網頁內建了API,能夠滿足客戶不同需求(比如合作伙伴vs終端使用者)。
- 該模式意味著本地Web應用能夠為使用者無論是基於什麼平臺提供更接近一個本地移動或桌面應用程式的體驗。
- 協議(如openAuth(oAuth))成為作為使用者授權的黃金標準已被廣泛採用,提供了一個共同的模式。從應用程式好餓內容中將單獨登入/授權問題分離出來。也就是說使用者的身份可以從內容、功能和使用者體驗中清晰的分離出。
一個單頁面Web應用程式就是一個Web應用程式,但結構哦不同。其中最重要的是:在第一次請求的時候,所有的標記語言(HTML)就已經傳輸到客戶端,其餘的請求都通過REST API獲取JSON資料,資料的傳輸通過Web Socket API或遠端過程呼叫。單頁面應用程式可以說是分拆Web技術的最後一步----通過分離(css)內容,改進架構(XML和XSLT)上的靈活性,呼叫伺服器(AJAX)再到解壓應用程式的導航頁面結構,因此,這在Web發展中是個歷史性的轉折點。
目前這只是單頁面Web應用開發的初期,但可以看出將單頁面應用、APIs以及JavaScript結合在一起將成為許多流行應用的規範。
所以,當被問到“HTML5是App+API?”,我們會說,“兩者皆是---”將兩者結合在一起要比以往快得多。“單頁面應用是一塊非常大的拼圖。當然,導航、歷史性和SEO等問題也成為單頁面Web應用的詬病”
單頁面應用的演進
在這裡介紹一些Hash的內容先,單頁面應用是如何實現不重新整理網頁而進行跳轉的呢?
HTML中的hash(#號)
1.#的含義
#代表網頁中的一個位置。右面的自負就是代表的位置資訊:如
http://localhost:8080/cbuild/index.html#one
就代表網頁index.html的one位置。瀏覽器讀取這個URL後,會自動將one位置滾動至可視區域。
為網頁制定識別符號:
一是使用錨點 比如 <a name="print"></a>
二是使用id屬性,比如<div id="print"></div>
2.HTTP請求不包括#
比如:http://localhost:8081/cbuild/index.html#first
瀏覽器實際發出的請求是這樣的
GET/index.html
而不包含 #first
3.#後的字元
在第一個#後面出現的任何字元,都會被瀏覽器解讀為位置識別符號。這意味著,這些字元都不會被髮送到伺服器端。
比如,下面URL的原意是指定一個顏色值:
http://www.example.com/?color=#fff
但是,瀏覽器實際發出的請求是:
GET/?color=
Host: www.example.com
可以看到,“#fff”被省略了,只有將#轉碼為$23,瀏覽器才會將其作為實義字元處理。也就是說,上面的網址應該被寫成:
http://www.example.com/?color=%23fff
四、改變#不觸發網頁過載
單單改變#後的部分,瀏覽器只會滾動到相應位置,不會重新載入網頁。
比如,從
http://www.example.com/index.html#location1
改變到
http://www.example.com/index.html#location2
瀏覽器不會重新向伺服器請求index.html
五、改變#會改變瀏覽器的訪問歷史
每一次改變#後的部分,都會在瀏覽器的訪問歷史中增加一個記錄,使用"後退"按鈕,就可以回到上一個位置。
這對於ajax應用程式特別有用,可以用不同的#值,表示不同的訪問狀態,然後向用戶給出可以訪問某個狀態的連結。
值得注意的是,上述規則對IE6和IE7不成立,它們不會因為#的改變而增加歷史記錄
六、window.location.hash讀取#值
window.location.hash這個屬性可讀可寫。讀取時,可以用來判斷網頁狀態是否改變;寫入時,則會在不過載網頁的前提下,創造一條訪問歷史記錄。
七、onhashchange事件
這是一個HTML5新增的事件,當#值發生變化時,就會觸發這個事件。IE8+、Firefox 3.6+、Chrome 5+、Safari 4.0+支援該事件。
它的使用方法有三種:
1 window.onhashchange = func; 2 <body onhashchange="func();"> 3 window.addEventListener("hashchange",func, false);
對於不支援onhashchange的瀏覽器,可以用setInterval監控location.hash的變化。
八、Google抓取#的機制
預設情況下,Google的網路蜘蛛忽視URL的#部分。
但是,Google還規定,如果你希望Ajax生成的內容被瀏覽引擎讀取,那麼URL中可以使用"#!",Google會自動將其後面的內容轉成查詢字串_escaped_fragment_的值。
比如,Google發現新版twitter的URL如下:
http://twitter.com/#!/username
就會自動抓取另一個URL:
http://twitter.com/?_escaped_fragment_=/username
通過這種機制,Google就可以索引動態的Ajax內容。
單頁面Web應用就是根據上述的#,監控#值的改變去對應的改變頁面。
路由:頁面跳轉與模組關係
要說起路由,那可是有很長的故事。當我們在瀏覽器上輸入網址的時候,我們就已經開始了各種路由的旅途了。
- 瀏覽器會檢查有沒有相應的域名快取,沒有的話就會一層層的去向 DNS伺服器 尋向,最後返回對應的伺服器的 IP 地址。
- 接著,我們請求的網站將會將由對應 IP 的 HTTP 伺服器處理,HTTP 伺服器會根據請求來交給對應的應用容器來處理。
- 隨後,我們的應用將根據使用者請求的路徑,將請求交給相應的函式來處理。最後,返回相應的 HTML 和資源文化
當我們做後臺應用的時候,我們只需要關心上述過程中的最後一步。即,將對應的路由交給對應的函式來處理。這一點,在不同的後臺框架的表現形式都是相似的。
雖然表現形式有一些差別,但是總體來說也是差不多的。而對於前端應用來說,也是如此,將對應的 URL 的邏輯交由對應的函式來處理。
使用規則引擎來處理路由與函式的關係。稍有不同的是,後臺的路由完全交由伺服器端來控制,而前端的請求則都是在本地改變其狀態,並且同時在不同的前端框架上,他們在行為上還有一些區別。這取決於我們是否需要後臺渲染,即重新整理當前頁面時的表現形式。
資料:獲取與鑑權
實現路由的時候,只是將對應的控制權交給控制器(或稱元件)來處理。而作為一個單頁面應用的控制器,當執行到相應的控制器的時候,就可以根據對應的 blog/12 來獲取到使用者想要的 ID 是 12。這個時候,控制器將需要在頁面上設定一個 loading 的狀態,然後傳送一個請求到後臺伺服器。
對於資料獲取來說,我們可以通過axios,我們仍然是寫類似於的形式:
1 axios.get(url) 2.then(res=>{ 3console.log(res.data) 4}) 5.catch(err=>{ 6console.log(err); 7throw err; 8})
模型麻煩的地方在於:轉變成想要的形式。後臺返回的值是可變的,它有可能不返回,有可能是 null,又或者是與我們要顯示的值不一樣——想要展示的是 54%,而後臺返回的是 0.54。與此同時,我們可能還需要對數值進行簡單的計算,顯示一個範圍、區間,又或者是不同的兩種展示。
同時在必要的時候,我們還需要將這些值儲存在本地,或者記憶體裡。當我們重新進入這個頁面的時候,我們再去讀取這些值。
一旦談論到資料的時候,不可避免的我們就需要關心安全因素。對於普通的 Web 應用來說,我們可以做兩件事來保證資料的安全:
- 採用 HTTPS:在傳輸的過程中保證資料是加密的。
- 鑑權:確保指定的使用者只能可以訪問指定的資料。
目前,流行的前端鑑權方式是 Token 的形式,可以是普通的定製 Token,也可以是 JSON Web Token。獲取 Token 的形式,則是通過 Basic 認證——將使用者輸入的使用者名稱和密碼,經過 BASE64 加密傳送給伺服器。伺服器解密後驗證是否是正常的使用者名稱和密碼,再返回一個帶有時期期限的 Token 給前端。
隨後,當用戶去獲取需要許可權的資料時,需要在 Header 裡鑑定這個 Token 是否有限,再返回相應的資料。如果 Token 已經過期了,則返回 401 或者類似的標誌,客戶端就在這個時候清除 Token,並讓使用者重新登入。
資料展示:模板引擎
現在,我們已經獲取到這些資料了,下一步所需要做的就是顯示這些資料。與其他內容相比,顯示資料就是一件簡單的事,無非就是:
- 依據條件來顯示、隱藏某些資料
- 在模板中對資料進行遍歷顯示
- 在模板中執行方法來獲取相應的值,可以是函式,也可以是過濾器。
- 依據不同的數值來動態獲取樣式
- 等等
不同的框架會存在一些差異。並且現代的前端框架都可以支援單向或者雙向的資料繫結。當相應的資料發生變化時,它就可以自動地顯示在 UI 上。
最後,在相應需要處理的 UI 上,綁上相應的事件來處理。
是在資料顯示的時候,又會涉及到另外一個問題,即元件化。對於一些需要重用的元素,我們會將其抽取為一個通用的元件,以便於我們可以複用它們,並且在這些元件裡,也會涉及到相應的引數變化即狀態改變。
互動:事件與狀態管理
完成一步步的渲染之後,我們還需要做的事情是:互動。互動分為兩部分:使用者互動、元件間的互動——共享狀態。
元件互動:狀態管理
使用者從 A 頁面跳轉到 B 頁面的時候,為了解耦元件間的關係,我們不會使用元件的引數來傳入值。而是將這些值儲存在記憶體裡,在適當的時候調出這些值。當我們處理使用者是否登入的時候,我們需要一個 isLogined 的方法來獲取使用者的狀態;在使用者登入的時候,我們還需要一個 setLogin 的方法;使用者登出的時候,我們還需要更新一下使用者的登入狀態。
在沒有 Redux 之前,我都會寫一個 service 來管理應用的狀態。在這個模組裡寫上些 setter、getter 方法來儲存狀態的值,並根據業務功能寫上一些來操作這個值。然而,使用 service 時,我們很難跟蹤到狀態的變化情況,還需要做一些額外的程式碼來特別處理。
有時候也會犯懶一下,直接寫一個全域性變數。這個時候維護起程式碼來就是一場噩夢,需要全域性搜尋相應的變數。如果是呼叫某個特定的 Service 就比較容易找到呼叫的地方。
使用者互動:事件
事實上,對於使用者互動來說也只是改變狀態的值,即對狀態進行操作。
一個例子,當用戶點選登入的時候,傳送資料到後臺,由後臺返回這個值。由控制器一一的去修改這些狀態,最後確認這個使用者登入,併發一個使用者已經登入的廣播,又或者修改全域性的使用者值。
這裡先介紹這麼多。
本文參考文章:
一篇外國文章:ofollow,noindex">HTML,JavaScript和Web的應用程式
作者:明銘之中HTML中的hash(#號)
作者: mongkey_kingSPA
作者:劉貴生關於Vue專案的seo問題
這裡總結了一下他們的一些文章,方便以後查閱,看他們的文章讓我收穫頗多,一瞬間感慨萬千,技術發展太快,我們只能默默堅持,學習新的技術,爭取自己也有機會做那一頭領頭羊。
如果你看了我的文章感覺學習到了一些知識,那我非常高興。作者水平有限,如有不足之處,還望指正。