淺談SPA

  最近一直在學習關於Vue的一些知識,因爲遇到了問題,去網上查找資料,收穫頗豐,在此分享。javascript

1. 什麼是SPA?

  單頁Web應用(single page web application, SPA),就是隻有一張Web頁面的應用,是加載單個HTML頁面並在用戶與應用程序交互時動態更新該頁面的Web應用程序,是指在瀏覽器中運行的應用,在使用期間不會從新加載頁面。像全部的應用同樣,它旨在幫助用戶完成任務,好比「編寫文檔」或者「管理Web服務器」。能夠認爲單頁應用是一種從Web服務器加載的富客戶端。css

  速度:更好的用戶體驗,讓用戶在web app感覺native app的速度和流暢,
  MVC:經典MVC開發模式,先後端各負其責,後端只須要提供數據接口
  ajax:重前端,業務邏輯所有在本地操做,數據都須要經過AJAX同步、提交。
  路由:在URL中採用#號來做爲當前視圖的地址,改變#號後的參數,頁面並不會重載,這個也就是哈希。html

  

  SPA也是當今網站開發技術的一種趨勢和潮流,畢竟前端三大框架不是蓋的~~,不少的傳統網站都在或者已經轉型爲單頁Web應用,新的單頁Web應用網站(包括移動端平臺上面的)也雨後春筍涌現出來。前端

  單頁Web應用和前端工程師們息息相關,由於主要的變革發生在瀏覽器端,用到的技術其實仍是HTML+CSS+JavaScript,全部的瀏覽器都原生支持,固然有的瀏覽器由於具有一些高級特性,從而使得單頁Web應用的用戶體驗更上一層樓。關於單頁應用的優勢和缺點,下一個問題就說。 單頁Web應用,顧名思義,就是隻有一張Web頁面的應用。瀏覽器一開始會加載必需的HTML、CSS和JavaScript,以後全部的操做都在這張頁面上完成,這一切都由JavaScript來控制。所以,單頁Web應用會包含大量的JavaScript代碼,複雜度可想而知,模塊化開發和設計的重要性不言而喻。java

單頁Web應用程序的優勢:

  1.首先,最大的好處是用戶體驗,對於內容不改動的不須要加載整個頁面。這樣作好處頗多,由於數據層是和UI的分離,能夠從新編寫一個原生的移動設備應用程序而不用(對原有數據服務部分)大動干戈。ios

  2.單頁面Web應用層程序最根本的優勢是高效。它對服務器壓力很小,消耗更少的帶寬,可以與面向服務的架構更好地結合。web

單頁Web應用程序的缺點:

  雖然還有一些歷史遺留問題(大部分是針對HTML5的改進)以及SEO。若是你看中SEO,那你應該使用網站而不是Web應用。目前該技術還存在一些爭議,但這並非重點,由於這種類型的體系架構爲SAAS Web Apps提供了一個極大的可用性。ajax

  

程序結構 -- 重點

  單頁Web應用程序的結構很簡單:首先傳遞HTML文檔框架;而後使用JavaScript修改頁面;緊接着再從服務器傳遞更多數據而後再修改頁面,如此循環。從性能的角度看,在現代瀏覽器中單頁面Web App已經可以和普通應用程序相媲美,並且幾乎全部的操做系統都支持現代的瀏覽器。使用HTML+CSS+JavaScript編寫應用程序,能使更多的人們都加入到程序開發的行列。axios

  這足以說明,在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

4、改變#不觸發網頁重載

  單單改變#後的部分,瀏覽器只會滾動到相應位置,不會從新加載網頁。

  好比,從

  http://www.example.com/index.html#location1

   改變到

  http://www.example.com/index.html#location2

   瀏覽器不會從新向服務器請求index.html

5、改變#會改變瀏覽器的訪問歷史

  每一次改變#後的部分,都會在瀏覽器的訪問歷史中增長一個記錄,使用"後退"按鈕,就能夠回到上一個位置。

  這對於ajax應用程序特別有用,能夠用不一樣的#值,表示不一樣的訪問狀態,而後向用戶給出能夠訪問某個狀態的連接。

  值得注意的是,上述規則對IE6和IE7不成立,它們不會由於#的改變而增長曆史記錄

6、window.location.hash讀取#值

  window.location.hash這個屬性可讀可寫。讀取時,能夠用來判斷網頁狀態是否改變;寫入時,則會在不重載網頁的前提下,創造一條訪問歷史記錄。

7、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的變化。

8、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應用就是根據上述的#,監控#值的改變去對應的改變頁面。

 

路由:頁面跳轉與模塊關係

  要提及路由,那但是有很長的故事。當咱們在瀏覽器上輸入網址的時候,咱們就已經開始了各類路由的旅途了。

  1. 瀏覽器會檢查有沒有相應的域名緩存,沒有的話就會一層層的去向 DNS服務器 尋向,最後返回對應的服務器的 IP 地址。
  2. 接着,咱們請求的網站將會將由對應 IP 的 HTTP 服務器處理,HTTP 服務器會根據請求來交給對應的應用容器來處理。
  3. 隨後,咱們的應用將根據用戶請求的路徑,將請求交給相應的函數來處理。最後,返回相應的 HTML 和資源文化

  當咱們作後臺應用的時候,咱們只須要關心上述過程當中的最後一步。即,將對應的路由交給對應的函數來處理。這一點,在不一樣的後臺框架的表現形式都是類似的。

  雖然表現形式有一些差異,可是整體來講也是差很少的。而對於前端應用來講,也是如此,將對應的 URL 的邏輯交由對應的函數來處理。

  使用規則引擎來處理路由與函數的關係。稍有不一樣的是,後臺的路由徹底交由服務器端來控制,而前端的請求則都是在本地改變其狀態,而且同時在不一樣的前端框架上,他們在行爲上還有一些區別。這取決於咱們是否須要後臺渲染,即刷新當前頁面時的表現形式。

數據:獲取與鑑權

  實現路由的時候,只是將對應的控制權交給控制器(或稱組件)來處理。而做爲一個單頁面應用的控制器,當執行到相應的控制器的時候,就能夠根據對應的 blog/12 來獲取到用戶想要的 ID 是 12。這個時候,控制器將須要在頁面上設置一個 loading 的狀態,而後發送一個請求到後臺服務器。

  對於數據獲取來講,咱們能夠經過axios,咱們仍然是寫相似於的形式:

1 axios.get(url)
2     .then(res=>{
3         console.log(res.data)
4     })
5     .catch(err=>{
6         console.log(err);
7         throw err;
8     })

  模型麻煩的地方在於:轉變成想要的形式。後臺返回的值是可變的,它有可能不返回,有多是 null,又或者是與咱們要顯示的值不同——想要展現的是 54%,然後臺返回的是 0.54。與此同時,咱們可能還須要對數值進行簡單的計算,顯示一個範圍、區間,又或者是不一樣的兩種展現。

  同時在必要的時候,咱們還須要將這些值存儲在本地,或者內存裏。當咱們從新進入這個頁面的時候,咱們再去讀取這些值。

  一旦談論到數據的時候,不可避免的咱們就須要關心安全因素。對於普通的 Web 應用來講,咱們能夠作兩件事來保證數據的安全:

  1. 採用 HTTPS:在傳輸的過程當中保證數據是加密的。
  2. 鑑權:確保指定的用戶只能能夠訪問指定的數據。

  目前,流行的前端鑑權方式是 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 就比較容易找到調用的地方。

用戶交互:事件

  事實上,對於用戶交互來講也只是改變狀態的值,即對狀態進行操做。

  一個例子,當用戶點擊登陸的時候,發送數據到後臺,由後臺返回這個值。由控制器一一的去修改這些狀態,最後確認這個用戶登陸,併發一個用戶已經登陸的廣播,又或者修改全局的用戶值。

  

  這裏先介紹這麼多。

  本文參考文章:

  一篇外國文章: HTML,JavaScript和Web的應用程序      

  做者:明銘之中  HTML中的hash(#號)   

  做者: mongkey_king  SPA   

  做者:劉貴生 關於Vue項目的seo問題

  

  這裏總結了一下他們的一些文章,方便之後查閱,看他們的文章讓我收穫頗多,一瞬間感慨萬千,技術發展太快,咱們只能默默堅持,學習新的技術,爭取本身也有機會作那一頭領頭羊。

  若是你看了個人文章感受學習到了一些知識,那我很是高興。做者水平有限,若有不足之處,還望指正。

相關文章
相關標籤/搜索