Vue.js學習筆記

Vue.js學習筆記

img

目錄

1. 前端技術簡介

1.1 Vue概述

​ Vue(讀音 /vjuː/,相似於 view),做者尤雨溪,是一套用於構建用戶界面的漸進式框架。與其它大型框架不一樣的是,Vue 被設計爲能夠自底向上逐層應用。Vue 的核心庫只關注視圖層,不只易於上手,還便於與第三方庫(如:vue-rounter:跳轉vue-resource:通訊vuex:管理)或既有項目整合。另外一方面,當與現代化的工具鏈以及各類支持類庫結合使用時,Vue也徹底可以爲複雜的單頁應用提供驅動。javascript

官網:https://cn.vuejs.org/css

1.2 前端知識體系

​ 想要成爲真正的「互聯網 Java 全棧工程師」 還有很長的一段路要走,其中「我大前端」 是繞不開的一門必修課。Java 程序員認識前端、瞭解前端、掌握前端,爲實現成爲「互聯網 Java 全棧工程師」 再向前邁進一步。html

1.3 前端原生技術

將前端頁面比做一棟房子前端

  • HTML :超文本標記語言(Hyper Text Markup Language)。HTML 就像房子的雛形,決定網頁的結構和內容。
  • CSS:層疊樣式表(Cascading Style Sheets)。CSS 就像是房子的裝修工人,負責修飾房子的樣式和外觀,以及決定裝修顏色和風格。在前端頁面中,CSS 負責設定前端的樣式表現。
  • JavaScript:JavaScript 就像是屋子裏的智能家居,可以給主人(用戶)提供更溫馨和人性化的居住體驗。JavaScript 是一種弱類型腳本語言,其源代碼不須要通過編譯,而是由瀏覽器解釋運行,用於控制網頁的行爲,給用戶提供更溫馨的體驗。

1.3.1 HTML(結構層)

  • HTML 是用來描述網頁的一種語言,使用標籤來描述網頁。vue

  • 標記標籤一般被稱爲 HTML 標籤,java

    • 標籤是由尖括號包圍的關鍵詞,好比<html>
    • 一般是成對出現
    • 第一個標籤是開始標籤(開放標籤),第二個標籤是結束標籤(閉合標籤)
  • HTML 文檔描述網頁,包含 HTML 標籤和純文本。HTML 文檔也稱爲網頁node

1.3.2 CSS(表現層)

CSS 層疊樣式表是一門標記語言,並非編程語言,所以不能夠自定義變量,不能夠引用等,不具有任何語法支持。python

優勢:jquery

  • 豐富的樣式定義:CSS 提供了豐富的文檔樣式外觀,能夠改變元素的背景顏色,設置元素之間的距離,以及改變字體的顏色,大小等各類各樣修飾網頁效果的方法。
  • 易於修改:對於 CSS 文件中的某一處的元素的樣式進行修改,那麼全部應用到這個 CSS 的文件的樣式都會發生變化。
  • 結構清晰,易被搜索引擎搜索到。
  • 易於編寫,能夠像寫 HTML代碼同樣輕鬆的編寫。
  • 表現和內容分離:將設計部分剝離出來放在一個獨立樣式文件中,能夠下降將來修改代碼的複雜度。
  • 多頁面使用:將 CSS 樣式放置到一個文件夾中,能夠屢次重複應用到多種 HTML 頁面中。

缺點:webpack

  • CSS 沒有父層選擇器。
  • 語法不強大,好比沒法嵌套書寫,致使模塊化開發中須要書寫不少重複的選擇器。
  • 沒有變量和何理的樣式複用機制,使得邏輯上相關的屬性必須以字面量的形式重複輸出,致使難以維護。

這就致使了咱們在工做中增長了許多工做量。

爲了解決這個問題,前端開發人員會使用一種稱之爲【CSS 預處理器】的工具,提供CSS 確實的樣式層複用機制、減小冗餘代碼,提升樣式代碼的可維護性。大大提升了前端在樣式上的開發效率。

什麼是 CSS 預處理器

​ CSS 預處理器定義了一種新的語言。其基本思想是:用一種專門的編程語言,爲 CSS 增長一些編程的特性,將 CSS 做爲目表生成文件,而後開發者就只要使用這種語言進行 CSS 的編碼工做。也就是說「用一種專門的編程語言,進行 Web 頁面樣式設計。再經過編譯器轉化爲正常的 CSS 文件,以供項目使用

經常使用的 CSS預處理器:

  • SASS:基於 Ruby,經過服務端處理,功能強大。解析效率高。但須要學習 Ruby 語言,上手難度高於 LESS。
  • LESS:基於 Node.js 。經過客戶端處理,使用簡單。功能比 SASS 簡單,解析效率也低於 SASS,但在實際開發中足夠了。因此咱們後臺人員若是須要使用的話,建議使用 LESS。

1.3.3 JavaScript(行爲層)

​ JavaScript 是一門弱類型語言,其源代碼在發往客戶端運行以前不需通過編譯,而是將文本格式的字符代碼發送給瀏覽器,由瀏覽器解釋運行。

原生 JavaScript 開發

​ 原生 JavaScript 開發,也就是讓咱們按照【ECMAScript】 標準的開發方式,簡稱 ES,特色是全部瀏覽器都支持。

ES 標準已發佈以下版本:

  • ES3
  • ES4(內部、未正式發佈)
  • ES5(全瀏覽器支持)
  • ES6(經常使用,當前主流版本。能夠用 webpack 打包成 ES5支持)
  • ES7
  • ES8
  • ES9(草案階段)

區別就是逐步增長新特性。

TypeScript 微軟的標準

​ TypeScipt 是一種由微軟開發的自由和開源的編程語言。它是 JavaScript 的一個超集,並且本質上向這個語言添加了可選的靜態類型和基於類的面向對象編程。由安德斯-海爾斯伯格(C#、Delphi、TypeScrpt之父:.NET 創立者)主導。

​ 該語言的特色就是除了具有 ES 的特性以外,還歸入許多不在標準範圍內的新特性,因此會致使不少瀏覽器不能支持 TypeScript 語法,須要編譯後(編譯成 JS)才能被瀏覽器正確執行。

1.3.4 JavaScript框架

  • jQuery:你們熟悉的 JavaScript 框架,優勢事簡化了 DOM 操做,缺點是 DOM 操做太頻繁,影響前端性能;在前端眼裏使用它僅僅是爲了兼容 IE六、七、8。
  • Augular:Google 收購的前端框架。由一羣 Java程序員開發,其特色是將後臺的 MVC 模式搬到了前端,並增長了模塊化開發的理念,與微軟合做,採用 TypeScript 語法開發;對後臺程序員友好,對前端程序員不太友好;最大的缺點是版本迭代不合理(如1代 -> 2代除了名字,基本就是兩個東西)
  • React:Facebook 出品。一款高性能的 JS 前端框架;特色是提出了新概念 【虛擬 DOM】,用於減小真實 DOM 操做。在內存中模擬 DOM 操做,有效地提高了前端渲染效率;缺點是使用複雜,由於須要額外學習一門【JSX】語言。
  • Vue:一款漸進式 JavaScript 框架,所謂漸進式就是逐步實現新特性的意思,如實現模塊化開發、路由、狀態管理等新特性。其餘的是綜合了 Angular(模塊化)和 React(虛擬 DOM)的優勢。
  • Axios:前端通訊框架,由於 Vue 的邊界很明確,就是爲了處理 DOM,因此並不具有通訊能力。此時就須要額外使用一個通訊框架與服務器交互;固然也能夠直接選擇使用 jQuery 提供的 AJAX 通訊功能。

1.3.5 UI 框架

  • Ant-Design:阿里巴巴出品,基於 React 的 UI 框架。
  • ElementUI、iview、ice:餓了麼出品,基於 Vue 的 UI 框架。
  • Boostrap:Twitter 推出的一個用於前端開發的開源工具包。
  • AmazeUI:又叫"妹子UI",一款 HTML5 跨屏前端框架。
  • Layui:是一款採用自身模塊規範編寫的前端UI框架。

1.3.6 JavaScript 構建工具

  • Babel:JS 編譯工具,主要用於瀏覽器不支持的 ES 新特性,好比用於編譯 TypeScript。
  • WebPack:模塊打包器,主要做用是打包、壓縮、合併以及按序加載。

1.4 三端統一

1.4.1 混合開發(Hybird App)

主要目的是實現一套代碼三端統一(PC、Android:.apk、IOS:.ipa),並可以調用到設備底層硬件(如:傳感器、GPS、攝像頭等),打包方式主要由如下兩種:

  • 雲打包:HBuild -> HBuildX ,DCloud 出品;API Cloud。
  • 本地打包:Cordova(前生是 PhoneGap)

1.4.2 微信小程序

詳見微信官網,這裏就是介紹一個方便微信小程序 UI 開發的框架:WeUI

1.5 後端技術

​ 前端人員爲了方便開發也須要掌握必定的後端技術,但咱們 Java 後臺人員知道後臺知識體系極其龐大複雜,因此爲了方便前端人員開發後臺應用,就出現了 NodeJS 這樣的技術。

​ NodeJS 的做者已經聲稱放棄 NodeJS (說是架構作得很差再加上笨重的 node_modules,可能讓做者爽了吧),開始開發全新架構的 Deno (於2020年5月13日發佈1.0版本)

既然是後臺技術,那確定也須要框架和項目管理工具,NodeJS 框架及項目管理工具以下:

  • Express:NodeJS 框架
  • Koa:Express 簡化版
  • NPM:項目綜合管理工具,相似於 Maven
  • YARN:NPM 的替代方案,相似 Maven 和 Gradle 的關係

1.6 主流前端UI框架

1.6.1 iView

iView 是一個強大的基於 Vue 的 UI 庫,由不少使用的基礎組件,比 Element UI 的組件更豐富,主要服務於 PC 界面的中後臺產品。使用單文件的 Vue 組件化開發模式,基於 npm + webpack + babel 開發,支持 ES2015 高質量、功能豐富、友好的 API,自由靈活地使用空間

特色:移動端支持較多

1.6.2 Element UI

Element UI 是餓了麼前端開源維護的 Vue UI 組件庫,組件齊全,基本涵蓋後臺所需的全部組件,文檔講解詳細,例子也很豐富。主要用於開發 PC 端的頁面,是一個質量比較高的 Vue UI 組件庫。

特色:桌面端支持較多

1.6.3 ICE

飛冰是阿里巴巴團隊基於 React/Angular/Vue 的中後臺應用解決方案。在阿里巴巴內部,已經由270 多個來自幾乎全部 BU 的項目在使用。飛冰包含了一條從設計段到開發段的完整鏈路,幫助用戶快速搭建屬於本身的中後臺應用。

特色:主要組件仍是以 React 爲主,目前對 Vue 的支持還不太完善,目前尚處於官網階段。

1.6.4 VantUI

Vant UI 是有贊前端團隊基於有贊統一的規範實現的 Vue 組件庫,提供了一整套 UI 基礎組件和業務組件。經過 Vant ,能夠快速搭建出風格統一的頁面,提高開發效率。

1.6.5 AtUI

at-ui 是一款基於 Vue 2.x 的前端 UI 組件庫,主要用於快速開發 PC 網站產品,它提供了一套 npm + webpack + bable 前端開發工做流程,CSS 樣式獨立,即便採用不一樣的框架實現都能保持統一的 UI 風格。

1.6.6 CubeUI

cube-ui 是滴滴團隊開發的基於 Vue.js 實現的精緻移動端組件庫。支持按需引入和後編譯,輕量靈活,拓展性強,能夠方便地基於現有組件實現二次開發。

混合開發

1.6.7 Flutter

Flutter 是谷歌的移動端 UI 框架,可在極短的時間內構建 Android 和 IOS 尚高質量的原生級應用。Flutter 可與現有代碼一塊兒工做,它被世界各地的開發者和組織使用。而且 Flutter 是免費和開源的。

特色:Google 出品,能夠快速構建原生 APP 應用程序。作混合應用,該框架爲必選框架。

1.6.8 Ionic

Ionic 既是一個 CSS 框架,也是一個 JavaScript UI 庫。Ionic 是目前最有潛力的一款 HTML5 手機應用開發框架。經過 SASS 構建應用程序。它提供了不少 UI 組件 來邦族開發者開發強大的應用。它 使用 JavaScript MVVM 框架 和 AngularJS/Vue 來加強應用。提供給數據的雙向綁定,使用它稱爲 Web 和移動開發者的共同選擇。

微信小程序

1.6.9 mpvue

mpvue 是美團開發的一個使用 Vue.js 開發小程序的前端框架。目前支持 微信小程序百度智能小程序頭條小程序支付寶小程序。框架基於 Vue.js,修改了運行時框架 runtime 和代碼編譯器 compiler 實現。使其可運行在小程序環境中,從而爲小程序開發引入 Vue.js 開發體驗。

1.6.10 WeUI

WeUI 時一套同微信原生視覺體驗一致的基礎樣式庫。由微信官方設計團隊爲微信內網頁和微信小程序量身設計,令用戶的使用感知更加統一。包含 button、cell、dialog、toast、article、icon等各式元素。

官網:https://weui.io/

GitHub:https://github.com/Tencent/weui

2. 先後端分離的演變史

爲何須要先後端分離?

2.1 後端爲主的 MVC 時代

​ 爲了下降開發的複雜度,之後端爲出發點,!好比:Struts、SpringMVC 等框架的使用,就是後端的 MVC 時代;

下圖爲 MVC 模式流程圖:

image-20200512111319240

咱們這裏以 SpringMVC 流程圖 爲例:

image-20200512143317781

(圖引自狂神說公衆號)

圖爲 SpringMVC 的一個較完整的流程圖,實線表示 SpringMVC框架提供的技術,不須要開發者實現,虛線表示須要開發者實現。

須要分析執行流程

  1. DispatcherServlet 表示前置控制器,是整個 SpringMVC 的控制中心。用戶發出請求,DispatcherServlet 接收請求並攔截請求。

    咱們假設請求的url爲:http://localhost:8080/SpringMVC/hello

    如上url拆分紅三部分:

    http://localhost:8080:服務器域名

    SpringMVC: 部署在服務器上的 web 站點

    hello: 表示控制器

    經過分析,如上url表示爲:請求位於http://localhost:8080 上的 SpringMVC 站點的 hello 控制器

  2. HandlerMapping 爲處理器映射。DispatcherServlet 調用HandelerMapping,HandlerMapping 根據請求 url 查找 Handler。

  3. HandlerExecution表示具體的 Handler,其主要做用是根據 url 查找控制器,如上 url 被查找控制器爲 :hello。

  4. HandlerExecution 將解析後的信息傳遞給 DispatcherServlet,如解析控制器映射等。

  5. HandlerAdapter 表示處理器適配器,其按照特定的規則去執行 Handler。

  6. Handler 讓具體的 Controller 執行。

  7. Controller 將具體的執行信息返回給 HandlerAdapter ,如 ModelAndView。

  8. HandlerAdapter 將視圖邏輯名或模型傳遞給 DispatcherServlet。

  9. DispatcherServlet 調用視圖解析器(ViewResolver)來解析 HandlerAdapter 傳遞的邏輯視圖名。

  10. 視圖解析器將解析的邏輯視圖名傳給 DispatcherServlet。

  11. 視圖解析器將解析的邏輯視圖結果,調用具體的視圖。

  12. 最終視圖呈現給用戶。

若是看不懂上面的圖,這裏還有SpringMVC流程圖簡化版的圖:

​ 當發起請求時被前置的控制器攔截到請求,根據請求參數生成代理請求,找到請求對應的實際控制器,控制器處理請求,建立數據模型,訪問數據庫,將模型響應給中心控制器,控制器使用模型與視圖渲染視圖結果,將結果返回給中心控制器。再將結果返回給請求者。

image-20200512143002247

優勢:

​ MVC 模式時一個很是好的協做模式,可以有效下降代碼的耦合度。從架構尚可以讓開發者明白代碼應該寫在哪裏。爲了讓 View 更純粹,還能夠使用 Thymeleaf、Freemark 等模板引擎,使模板裏沒法寫入 Java 代碼,讓先後端分工更加清晰。

缺點:

  • 前端開發重度依賴開發環境,開發效率低,這種架構下,先後端協做由兩種模式:
    • 第一種是前端寫 DEMO ,寫好後,讓後端去套模板。好處是 DEMO 能夠本地開發,很高效。不足時還須要後端套模板,有可能套錯,套完後還須要前端肯定,來回溝通調整的成本比較大。
    • 另外一種協做模式時前端負責瀏覽器端的全部開發和服務器端的 View 層模板開發。好處是 UI 相關的代碼都是前端去寫,後端不用太關注。不足就是前端開發重度綁定後端環境,環境成爲影響前端開發效率的重要因素
  • 先後端職責糾纏不清:模板引擎功能強大,依舊能夠經過拿到的上下文變量來實現各類業務邏輯。這樣,只要前端弱勢一點,每每就會被後端要求在模板層寫出很多業務代碼。還有一個很大的灰色地帶是 Controller。頁面路由等功能本應該是前端最關注的,但倒是由後端來實現。Controller 自己與 Model 每每也會糾纏不清,看了讓人咬牙的業務代碼常常會出如今 Controller 層。這些問題不能歸結於程序員的素養,不然 JSP 就夠了。
  • 對前端發揮的侷限性:性能優化若是隻在前端作,空間很是有限。因而咱們常常須要後端合做。但因爲後端框架限制,咱們很難使用 【Content】、【BigPipe】等技術方案來優化性能。

2.2 基於 AJAX 帶來的 SPA 時代

​ 2005 年,AJAX(Asynchronous JavaScript And Xml,異步 JavaScript 和 XML)被正式提出,並開始使用 CDN 做爲靜態資源存儲。因而出現了 JavaScript 王者歸來(在這以前,JS 都是用來在網頁上貼狗皮膏藥廣告的)的 SPA (Single Page Application) 單頁面應用時代。

image-20200520134447447

優勢:

​ 這種模式下,先後端的分工很是清晰,先後端的關鍵協做點是 AJAX 接口,看起來是如此美妙。但回過頭來看的話,這與 JSP 時代區別不大。複雜度從服務端的 JSP 裏移到了瀏覽器的 JavaScript。瀏覽器端變得很複雜。相似 SpringMVC ,這個時代開始出現瀏覽器端的分層架構

缺點:

  • 先後端接口的約定:若是後端的接口一塌糊塗,若是後端業務模型不夠穩定,那麼前端開發會很痛苦;很多團隊也有相似嘗試,經過接口規則,接口平臺等方式來作。有了和後端一塊兒沉澱的接口規則,還能夠用來模擬數據,使得先後端能夠在約定接口實現高效並行開發。
  • 前端開發的複雜度控制:SPA 應用大多以功能交互型爲主,JavaScript 代碼過十萬行很正常,大量 JS 代碼的組織,與 View 層的綁定等,都不是容易的事情。

2.3 前端爲主的 MV* 時代

此處的 MV* 模式以下:

  • MVC(同步通訊爲主): Model、View、Controller
  • MVP(異步通訊爲主):Model、View、Presenter
  • MVVM(異步通訊爲主):Model、View、ViewModel

爲了下降前端開發的複雜度,涌現了大量的前端框架,好比:AngularJSReactVue.jsEmberJS 等,這些框架總的原則是先按類型分層,好比 Templates、Controllers、Models,而後再在層內作切分。

優勢:

  • 先後端職責很清晰:前端工做在瀏覽器端,後端工做在服務端。清晰的分工,可讓開發並行,測試數據的模擬不難,前端能夠本地開發。後端則能夠專一於業務邏輯的處理,輸出 RESTful 等接口。;
  • 前端開發的複雜度可控:前端代碼很重,但合理的分層,讓前端代碼各司其職。這一塊蠻有意思的。簡單如模板特性的選擇,就有不少講究。並不是越強大越好。限制什麼,留下哪些自由,代碼應該如何組織,全部這一切設計,得花一本書得厚度去說明。
  • 部署相對獨立:能夠快速改進產品體驗。

缺點:

  • 代碼不能複用。好比後端一就須要對數據作各類校驗,校驗邏輯沒法複用瀏覽器端得代碼。若是能夠複用,那麼後端得數據校驗能夠相對簡單化。
  • 會異步,對 SEO 不利。每每還須要服務端作同步渲染的降級方案。
  • 性能並不是最佳,特別是移動互聯網環境下。
  • SPA 不能知足全部需求,一就存在大量多頁面的應用。URL Design 須要後端配合,前端沒法徹底掌握。

2.4 NodeJS 帶來的全棧時代

​ 前端爲主的 MV* 模式解決了不少問題。但如上所述,一就存在很多不足之處。隨着 NodeJS 的興起,JavaScript 開始由能力運行在服務端。這意味着能夠有一種新的研發模式:

img

在這種研發模式下,先後端的職責很清晰。對前端來講,兩個 UI 各司其職:

  • Front-end UI layer 處理瀏覽器層的展示邏輯。經過 CSS 渲染樣式,經過 JavaScript 添加交互功能,HTML 的生成也能夠放在這層,具體看應用場景。
  • Back-end UI layer 處理路由、模板、數據獲取、Cookie 等。經過路由,前端終於能夠自主把控 URL Design。這樣不管是單頁面應用仍是多頁面應用,前端均可以自由調控。後端也終於能夠擺脫對展示的強關注了,轉而能夠專心於業務邏輯層的開發。

經過 Node、Web Server 層也是 JavaScript 代碼,這意味着部分代碼可先後複用,須要 Seo 的場景能夠在服務端同步渲染,因爲異步請求太多致使的性能問題也能夠經過服務端來緩解。前一種模式的不足,經過這種模式幾乎都能完美解決掉。

與 JSP 模式相比,全棧模式看起來是一種迴歸,也的確是一種向原始開發模式的迴歸,不過是一種螺旋上升式的迴歸。

基於 NodeJS 的全棧模式,依舊面臨不少挑戰:

  • 須要前端對服務器編程有更進一步的認識。好比 TCP/IP 等網絡知識的掌握。
  • NodeJS 層與 Java 層的高效通訊。NodeJS 模式下,都在服務器端,RESTful HTTP 通訊未必高效,經過 SOAP 等方式通訊更高效。一切須要在驗證中前行。
  • 對部署、運維層面的熟練了解,須要更多知識點和實操經驗。
  • 大量歷史遺留問題如何過分。這多是最大的阻力。

2.5 總結

綜上所述,模式也好,技術也罷,沒有好壞優劣之分,只有適合和不適合;先後端分離的開發思想主要是基於 SoC (關注度分離原則),上面種種模式,都是讓先後端的職責更清晰,分工更何理高效。

3. MVVM 模式

3.1 什麼是 MVVM 模式

​ MVVM (Model-View-ViewModel)是一種軟件架構設計模式,由微軟 WPF(用於替代 WinForm,之前就是用這個技術開發桌面應用程序的)和 Silverlight(相似於 JavaApplet,簡單點說就是在瀏覽器上運行 WPF)的架構師 Ken-Cooper 和 Ted-Peters 開發,是一種簡化用戶界面的事件驅動編程方式。由 John-Gossman(一樣也是 WPF 和 Silverlight 的架構師)於 2005 年在 它的博客上發表。

MVVM 源自於經典的 MVC(Model-View-Controller)模式。MVVM 的核心是 ViewModel 層,負責轉換 Model 中的數據對象來讓數據變得更容易管理和使用,其做用以下:

  • 該層向上與視圖層進行雙向數據綁定。
  • 向下與 Model 層經過接口請求進行數據交互。

image-20200520160314060

MVVM 已經至關成熟了,主要應用但不只僅在網絡應用程序開發中。當下流行的 MVVM 框架有 Vue.jsAngular.js 等。

3.2 爲何要使用 MVVM

MVVM 模式和 MVC 模式同樣,主要目的是分離視圖(View)和模型(Model)。有如下幾大好處:

  • 低耦合:視圖(View)能夠獨立於 Model 變化和修改。一個 ViewModel 能夠綁定到不一樣的 View 上,當 View 變化的時候 Model 能夠不變。當 Model 變化的時候 View 也能夠不變。
  • 可複用:你能夠把一些視圖邏輯放在一個 ViewModel 中,讓不少 View 重用這段視圖邏輯。
  • 獨立開發:開發人員能夠專一於業務邏輯和數據的開發(ViewModel),設計人員能夠專一於網頁設計。
  • 可測試:界面素來是比較難於測試的,而如今測試能夠針對 ViewModel 來寫。

3.3 MVVM 的組成部分

image-20200520165001894

3.3.1 View

​ View 是視圖層,也就是用戶界面。前端主要由 HTML 和 CSS 來構建,爲了更方便地展示 ViewModel 或者 Model 層的數據,已經產生了各類各樣的先後端模板語言,好比 FreeMark、Thymeleaf 等等,各大 MVVM 框架 如 Vue,js,AugularJS,EJS 等也都有本身用來構建用戶界面的內置模板語言。

3.3.2 Model

​ Model 是指數據模型,泛指後端進行的各類業務邏輯處理和數據操控。主要圍繞數據庫系統展開。這裏的難點主要在於須要和前端約定統一的接口規則

3.3.3 ViewModel

​ ViewModel 是由前端開發人員組織生成和維護的視圖數據層。在這一層,前端開發者對從後端獲取的 Model 數據進行轉換處理,沒作二次封裝。以生成符合 View 層使用於其的視圖數據模型。

須要注意的是 ViewModel 所封裝出來的數據模型包括視圖的狀態和行爲兩部分。而 Model 層的數據模型是隻包含狀態的

  • 好比頁面的這一塊展現什麼,那一塊展現什麼都屬於視圖狀態(展現)
  • 頁面加載進來時發生什麼,點擊這一塊發生什麼,這一塊滾動時發生什麼,這些都屬於視圖行爲(交互)

視圖狀態和行爲都封裝在了 ViewModel 中。這樣的封裝使得 ViewModel 能夠完整地去描述 View 層。因爲實現了雙向綁定,ViewModel 的內容會實時展示在 View 層,這是激動人心的,由於前端開發者不再必低效又麻煩地經過操縱 DOM 去更新視圖了。

MVVM 框架已經把最髒最累地一塊作好了,咱們開發者只須要處理和維護 ViewModel,更新數據視圖就會自動獲得相應更新,真正實現 事件驅動程序

View 層展示地不是 Model 層的數據,而是 ViewModel 的數據,由 ViewModel 負責與 Model 層交互,這就徹底解耦了 View 層和 Model 層,這個解耦是相當重要的,它是先後端分離方案實施的重要一環

3.4 MVVM 模式的實現者

  • Model:模型層,再這裏表示 JavaScript 對象。
  • View:視圖層,再這裏表示 DOM (HTML 操做的元素)。
  • ViewModel:鏈接視圖和數據的中間件,Vue.js 就是 MVVM 中的 ViewModel 層的實現者。

在 MVVM 架構中,是不容許數據和視圖直接通訊的,只能經過 ViewModel 來通訊,而 ViewModel 就是定義了一個 Observer 觀察者。

  • ViewModel 可以觀察到數據的變化,並對視圖對應的內容進行更新。
  • ViewModel 可以監聽到視圖的變化,並可以通知數據發生改變。

至此,咱們就明白了,Vue.js 就是一個 MVVM 的實現者,它的核心就是實現了 DOM 監聽與數據綁定

4. 第一個Vue程序

4.1 爲何要使用 Vue.js

  • 輕量級,體積小是一個重要指標。Vue.js 壓縮後只有 20 多 kb (Angular 壓縮後 56kb+,React 壓縮後 44kb+)
  • 移動優先。更適合移動端,好比移動端的 Touch 事件。
  • 易上手,學習曲線平穩,文檔齊全。
  • 吸收了 Augular(模塊化)和React(虛擬 DOM)的長處,並擁有本身獨特的功能,如:計算屬性
  • 開源,社區活躍度高
  • 用的人多

4.2 下載 vue.js

官網下載:

CDN:

  • 開發版本:

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  • 生產版本:

    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
  • 原生 ES Modules

    <script type="module">
      import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.esm.browser.js'
    </script>

注:開發版本中包含源代碼,生產版本是刪除註釋和警告後壓縮的js文件

4.3 編寫第一個Vue程序

  1. idea 安裝 Vue.js 插件

    image-20200520182954971

    如果搜索不到顯示search results are not loaded check the internet connection

    解決方案:

    • 檢查電腦防火牆是否關閉,若沒關閉,則將防火牆關閉

    image-20200408115148492

    • File -> Settings -> Appearance & Behavior -> System Settings ->HTTP Proxy -> 勾選Auto-detect proxy settings

    image-20200408115305483

    • File -> Settings -> Appearance & Behavior -> System Settings -> Updates -> 將User secure connection 勾選去掉

    image-20200408115510070

    • 重啓idea,而後從新進入plugins 搜索插件並下載

    若重啓idea後仍是不能搜索到插件,則重啓多幾回,若還不行,則電腦關機後等待5分鐘後重啓電腦去安裝插件。

    若都未解決,網上有人說改用開手機熱點來下載插件或離線安裝插件,能夠嘗試一下。

  2. 導入vue.min.js ,並編寫 demo1.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <!-- View 層 模板 -->
    <div id="app">
        // {{變量}},獲取Vue對象的屬性
        {{msg}}
    </div>
    
    <!-- 導入vue.js -->
    <script src="../js/vue.min.js"></script>
    <script>
        var vm = new Vue({
            el: "#app",
            data:{
                msg:"hello,Vue!"
            }
        });
    </script>
    
    </body>
    </html>
  3. 用瀏覽器打開這個 html 文件,並在控制檯中測試 Vue 的雙向綁定

    在控制檯中咱們使用 對象名.屬性 = "修改後的值" 來實現對 vm 對象的修改。在這裏,咱們輸入 vm.msg="hello",頁面顯示內容及控制檯以下圖:

    image-20200520183745266

    能夠看出,咱們在控制檯中修改 vm 對象,前端頁面會發生改變。也就是說,如今能夠在不刷新網頁的基礎上,實現改變後臺數據,前端頁面數據也改變,這就是雙向綁定。

    注意咱們再也不和 HTML 直接交互了。一個 Vue 應用會將其掛載到一個 DOM 元素上 (對於這個例子是 #app) 而後對其進行徹底控制。那個 HTML 是咱們的入口,但其他都會發生在新建立的 Vue 實例內部。

5. v-bind

​ 咱們已經成功建立了第一個 Vue 應用!看起來這跟渲染一個字符串模板很是相似。可是, Vue 在背後作了大量工做。如今數據和 DOM 已經創建了關聯,全部東西都是響應式的。咱們在控制檯操做對象屬性,界面能夠實時更新!

​ 咱們還能夠使用 v-bind 來綁定元素特性!

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <span v-bind:title="msg">
    鼠標懸停幾秒鐘查看此處動態綁定的提示信息!
    </span>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            msg:'頁面加載於' + new Date().toLocaleString()
        }
    });
</script>

</body>
</html>

這裏咱們遇到了一點新東西。你看到的 v-bind attribute被稱爲指令。指令帶有前綴 v- ,以表示他們是 Vue 提供的特殊 attribute。它們會在渲染的 DOM 上應用特殊的響應式行爲。在這裏,該指令是將這個元素的tittle和Vue 實例的 msg 保持一致。

若是咱們再像剛剛同樣再控制檯中修改 vm 對象中的 msg屬性,鼠標停留在這個 span 標籤的上方,內容也會相對應發生改變。

image-20200520192606161

6. 條件與循環

  • v-if :條件判斷
  • v-for :循環

6.1 條件

這個就很簡單了,v-if 等於的值若是是true,則顯示該標籤,不然則不顯示該標籤

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <span v-if="flag">
    這是條件判斷
    </span>
    <span v-if="falseFlag">
    由於是false,因此看不到
    </span>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            flag: true,
            falseFlag: false
        }
    });
</script>

</body>
</html>

頁面顯示以下:

image-20200520213214136

v-if 還能夠跟 v-else-ifv-else 搭配使用。(2.1.0新增的特性)實例代碼以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <span v-if="msg === 'A'">A</span>
    <span v-else-if="msg === 'B'">B</span>
    <span v-else-if="msg === 'C'">C</span>
    <span v-else>D</span>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var mv = new Vue({
        el: "#app",
        data: {
            msg : 'B'
        }
    });
</script>

</body>
</html>

這裏前端頁面顯示的結果是 B

6.2 循環

語法 v-for="數組中遍歷出來的元素名稱 in 數組名稱",而後能夠使用 {{...}}獲取遍歷出來的元素

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <li v-for="item in items">{{item.msg}}</li>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var mv = new Vue({
        el: "#app",
        data:{
            items:[
                {msg:"Java"},
                {msg:"Linux"},
                {msg:"Python"},
                {msg:"C++"}
            ]
        }
    });
</script>

</body>
</html>

在控制檯裏,輸入 app.items.push({msg: '新項目' }),你會發現列表最後添加了一個新項目。

循環中能夠有兩個參數,第二個參數爲循環時的下標。具體核心代碼以下:

<div id="app">
    <li v-for="(item,index) in items">{{item.msg}} --> {{index}}</li>
</div>

補充: v-for 會遍歷出來三個值:index,key,value ,有興趣的話能夠本身百度進行了解。這裏有一篇關於 這三個值對 v-bind:key 值形成差別的實驗:https://www.cnblogs.com/tim100/p/7262963.html?tdsourcetag=s_pcqq_aiomsg

7. 事件

7.1 爲何在 HTML 中監聽事件?

​ 你可能注意到這中事件監聽的方式違背了關注點分離(separation of concern) 這個長期依賴的優良傳統。但沒必要擔憂,由於全部的 Vue.js 使勁啊處理方法和表達式都嚴格綁定在當前視圖的 ViewModel 上,它不會致使任何維護上的困難。實際上,使用 v-on 有幾個好處:

  • 掃一眼 HTML 模板便能輕鬆定位在 JavaScript 代碼裏對應的方法。
  • 由於你無須在 JavaScript 裏手動綁定事件,你的 ViewModel 代碼能夠式很是存粹的邏輯,和 DOM 徹底解耦,更易於測試。
  • 當一個 ViewModel 被銷燬時,全部的事件處理器都會自動被刪除。你無許擔憂如何清理他們。

7.2 v-on

語法: v-on:事件名="方法名"

v-on 指令能夠監聽 DOM 事件,並在觸發時運行一些 JavaScript 代碼。

實例以下:

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <button v-on:click="hello">hello</button>
</div>

<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {

        },
        methods: { // 方法必須定義在 Vue 的 Methods 中
            hello: function (event) {
                alert("hello!");
            }
        }
    });
</script>

</body>
</html>

咱們在點擊 hello 這個按鈕的時候,會執行 vue 對象中 methods 屬性中的 hello 方法,hello 方法是用 JavaScript 寫的。也就是說,v-on 指令能夠監聽 DOM 事件,並在觸發時運行一些 JavaScript 代碼。

7.3 事件修飾符

在事件處理程序中調用 event.preventDefault()event.stopPropagation() 是很是常見的需求。儘管咱們能夠在方法中輕鬆實現這點,但更好的方式是:方法只有存粹的數據邏輯,而不是去處理 DOM 事件細節。

爲了解決這個問題, Vue.js 爲 v-on 提供了事件修飾符

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
<!-- 阻止單擊事件繼續傳播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件再也不重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修飾符能夠串聯 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件監聽器時使用事件捕獲模式 -->
<!-- 即內部元素觸發的事件先在此處理,而後才交由內部元素進行處理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只當在 event.target 是當前元素自身時觸發處理函數 -->
<!-- 即事件不是從內部元素觸發的 -->
<div v-on:click.self="doThat">...</div>

注:使用修飾符時,順序很重要;響應的代碼會以一樣的順序產生。所以,用 v-on:click.prevent.self 會阻止全部的點擊,而 v-on:click.self.prevent 只會阻止元素自身的點擊。

7.4 按鍵修飾符

在監聽鍵盤事件時,咱們常常須要檢查詳細的按鍵。 Vue 容許爲 v-on 在監聽鍵盤事件時添加按鍵修飾符:

<!-- 只有在 `key` 是 `Enter` 時調用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

你能夠直接將 KeyboardEvent.key 暴露的任意有效按鍵名轉換爲 kebab-case 來做爲修飾符。

<input v-on:keyup.page-down="onPageDown">

在上述示例中,處理函數只會在 $event.key 等於 PageDown 時被調用。

補充:

Vue 經常使用的7個屬性

  • el 屬性:用來指示 vue 編譯器從什麼地方開始解析 vue 的語法,能夠說是一個佔位符。
  • data 屬性:用來組織從 view 中抽象出來的屬性,能夠說將視圖的數據抽象出來存放在 data 中。
  • tamplate 屬性:用來設置模板,會替換頁面元素,包括佔位符。
  • methods 屬性:放置頁面中的業務邏輯,js 方法通常都放置在 methods 中
  • render 屬性:建立真正的 Virtual DOM
  • computed 屬性:用來計算
  • watch 屬性:
    • watch:function(new,old){}
    • 監聽 data 中數據的變化
    • 兩個參數,一個返回新值,一個返回舊值

8. 表單雙向綁定

8.1 什麼是雙向綁定

​ Vue.js 是一個 MVVM 框架,即數據雙向綁定。即當數據發生變化的時候,視圖也就發生變化,當視圖發生變化的時候,數據也會跟着同步變化。

​ 值得注意的是,咱們所說的數據雙向綁定,必定是對於 UI 控件來講的,非 UI 控件不會涉及到數據雙向綁定。單向數據綁定是使用狀態管理工具的前提。若是咱們使用 vuex ,那麼數據流也是單向的,這是就會和雙向數據綁定有衝突。

8.2 爲何要實現數據雙向綁定

​ 在 Vue,js 中,若是使用 vuex ,實際上數據仍是單向的。之因此說是數據雙向綁定,這是用的 UI 空間來講。對於咱們處理表單, Vue.js 的雙向數據綁定應用起來就特別舒服了。即二者並不互斥,在全局性數據流使用單向,方便跟蹤;局部性數據使用雙向,簡單易操做。

8.3 在表單中使用雙向數據綁定

​ 你能夠使用 v-model 指令在表單 <input><textarea><select> 元素上建立雙向數據綁定。它會根據控件類型自動選取正確的方法來更新元素。景觀有些神奇,但 v-model 本質上不過是語法糖。它負責監聽用戶的輸入事件以更新數據,並對一些極端場景進行一些特殊處理。

注: v-model 會忽略全部表單元素的 value、checked、selected 特性的初始值而老是將 Vue 實例的數據做爲數據來源。應該經過 JavaScript 在組件的 data 選項中聲明初始值。

8.3.1 單行文本

<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!-- 單行文本 -->
    <input v-model="message" placeholder="請輸入文本"/>
    <p>Message is: {{message}}</p>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            mess!age: '' // 必定先在 data 中聲明 v-model 中的初始化
        }
    });
</script>

</body>
</html>

8.3.2 多行文本

<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!-- 多行文本 -->
    <span>多行文本輸入的信息:</span>
    <p style="white-space: pre-line;">{{ mulMessage }}</p>
    <br>
    <textarea v-model="mulMessage" placeholder="請輸入多行文本"></textarea>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            mulMessage: ''
        }
    });
</script>

</body>
</html>

8.3.3 複選框

<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!-- 複選框 -->
    <div>
        <input type="checkbox" value="張三" v-model="checkName">
        <label>張三</label>
        <input type="checkbox" value="李四" v-model="checkName">
        <label>李四</label>
        <input type="checkbox" value="王五" v-model="checkName">
        <label>王五</label>
        <p>你選的是:{{checkName}}</p>
    </div>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            checkName: []
        }
    });
</script>

</body>
</html>

8.3.4 單選按鈕

<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!-- 單選按鈕 -->
    <div>
        <p>性別:</p>
        <input type="radio" value="男" v-model="sex">
        <label>男</label>
        <input type="radio" value="女" v-model="sex">
        <label>女</label>
        <p>你選擇了:{{sex}}</p>
    </div>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            sex: ''
        }
    });
</script>
    
</body>
</html>

8.3.5 單選框

<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!-- 單選框 -->
    <div>
        <select v-model="selected">
            <option  disabled>請選擇</option>
            <option >A</option>
            <option >B</option>
            <option >C</option>
            <option >D</option>
        </select>
        <p>你選擇了:{{selected}}</p>
    </div>
</div>

<!-- 導入vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            selected: ''
        }
    });
</script>

</body>
</html>

注:若是 v-model 表達式的初始值未能匹配任何選項, <select> 元素將被渲染爲「未選中」狀態。在 ios 中,這會使用戶沒法選擇第一個選項。由於這樣的狀況下, ios 不會觸發 change 事件。所以,更推薦像上面這樣提供一個值爲空的禁用選項。

能夠使用 v-for 動態渲染(綁定到一個數組),核心代碼以下:

<select v-model="selected">
  <option v-for="option in options" v-bind:value="option.value">
    {{ option.text }}
  </option>
</select>
<span>Selected: {{ selected }}</span>

new Vue({
  el: '...',
  data: {
    selected: 'A',
    options: [
      { text: 'One', value: 'A' },
      { text: 'Two', value: 'B' },
      { text: 'Three', value: 'C' }
    ]
  }
})

8.4 修飾符

  • .lazy

    在默認狀況下, v-model 在每次 input 事件觸發後將輸入框的值與數據進行同步(除了8.3.1輸入法組合文字時)。你能夠添加上 lazy 修飾符,從而轉爲在 change 事件以後進行同步:

    <!-- 在「change」時而非「input」時更新 -->
    <input v-model.lazy="msg">
  • .number

    若是像自動將用戶的輸入值轉爲數值類型,能夠給 v-model 添加 number 修飾

    <input v-model.number="age" type="number">

    這一般頗有用,由於即便在 type="number" 時,HTML 輸入元素的值也總會發揮字符串。若是這個值沒法被 parseFloat() 解析,則會返回原始的值

  • .trim

    若是要自動過濾用戶輸入的首尾空白字符,能夠給 v-model 添加 trim 修飾符:

9. Vue 組件

9.1 什麼是組件

組件是可複用的 Vue 實例,說白了就是一組能夠重複使用的模板,跟 JSTL 的自定義標籤、Thymeleaf 的 th:fragment 等框架有着殊途同歸之妙。一般一個應用會以一棵嵌套的組件樹的形式來組織:

Component Tree

例如,你可能會有頁頭、側邊欄、內容區等組件,每一個組件又包含了其它的像導航鏈接、博文之類的組件。

9.2 第一個 Vue 組件

注:在實際開發中,咱們並不會用上面的方式開發組件,而是採用 vue-cli 建立 .vue 模板文件的方式開發,如下方法知識爲了讓你們理解什麼是組件。

使用 Vue.component() 方法註冊組件,格式以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <li-list v-for="item in items" v-bind:language="item"></li-list>
</div>

<!-- 引入 vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    /* 使用 component() 方法註冊組件 */
    Vue.component('li-list',{
        props: ['language'],
        template: "<li>{{language}}</li>"
    });
    new Vue({
        el: "#app",
        data:{
            items: ["Java","Linux","JavaScript"]
        },
    });
</script>

</body>
</html>

說明:

  • Vue.component():註冊組件
  • li-list:自定義的組件名
  • template:組件的模板
  • props:接收組件傳遞的參數,默認規則下 props 屬性裏的值不能爲大寫
  • language:組件綁定的參數名

由於組件是可複用的 Vue 實例,因此他們與 new Vue 接收相同的選項,例如 datacomputedwatchmethods 以及生命週期鉤子等。僅有的例外是像 el 這樣根實例特有的選項。注:new Vue 必需要在所有組件註冊完後再建立!不然 new Vue 後面註冊的組件將不會生效。

9.3 組件的複用

你能夠將組件進行任意次數的複用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <click-component></click-component>
    <click-component></click-component>
    <click-component></click-component>
</div>

<!-- 引入 vue.js -->
<script src="../js/vue.min.js"></script>
<script>
    Vue.component('click-component',{
        data: function () {
            return{
                count: 0
            }
        },
        template: '<button v-on:click="count++">已經點擊了{{ count }}次</button>'
    });
    vm = new Vue({
        el: "#app"
    });
</script>

</body>
</html>

當點擊按鈕時,每一個組件都會各自獨立維護它的 count。由於每用一次組件,就會又它的新實例被建立

data

組件中的 data 選項必須是一個函數,所以每一個實例能夠維護一份被返回對象的獨立的拷貝。若是 Vue 沒有這條規則,點擊一個按鈕就可能會改變全部按鈕中的 count

10. Axios異步通訊

10.1 什麼是Axios

​ Axios 是一個開源的能夠用在瀏覽器端和 NodeJS 的異步通訊框架。它的主要做用就是實現 AJAX 異步通訊,其功能特色以下:

  • 瀏覽器中建立 XMLHttpRequest
  • 從 node.js 建立 http 請求
  • 支持 Promise API【JS中鏈式編程】
  • 攔截請求和響應
  • 取消請求
  • 自動轉換 JSON 數據
  • 客戶端支持防護 XSRF(跨域請求僞造)

GitHub:https://github.com/axios/axios

中文文檔:http://www.axios-js.com/

10.2 爲何要使用 Axios

​ 因爲 Vue.js 是一個視圖層框架,而且做者嚴格遵照 SoC(關注度分離原則),因此 Vue.js 並不包含 AJAX 的通訊功能。爲了解決通訊問題,做者單獨開發了一個名爲 vue-resource 的插件。不過在進入 2.x 版本之後中止了對該插件的維護並推薦了 Axios 框架,少用 jQuery,由於它操縱 DOM 太頻繁了!

10.3 第一個 Axios 應用程序

咱們開發的接口大部分都是採用 JSON 格式,能夠如今項目裏模擬一段 JSON 數據,數據內容以下:建立一個名爲 data.json 的文件並填入上面的內容,放在項目根目錄下:

data.json

{
  "name": "bilibili",
  "url": "www.bilibili.com",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "黃石路",
    "city": "廣州市",
    "country": "中國"
  },
  "links": [
    {
      "name": "百度",
      "url": "www.baidu.com"
    },
    {
      "name": "谷歌",
      "url": "www.google.com"
    }
  ]
}

引入 axios

  • npm安裝:npm install --save axios vue-axios -g
  • cdn:<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

經過 axios 獲取 data.json

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 解決閃爍問題 -->
    <style>
        [v-clack]{
            display: none;
        }
    </style>
</head>
<body>

<div id="app" v-clack>
    <div>
        {{info}}
    </div>
    <a v-bind:href="info.url">跳轉</a>
</div>

<!-- 導入 vue.js -->
<script src="../js/vue.min.js"></script>
<!-- 導入 axios -->
<script src="../js/axios.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data(){
            return {
                // 請求的返回參數格式,必須和json字符串同樣
                name: null,
                address: {
                    country: null,
                    city: null,
                    street: null
                },
                url: null
            }
        },
        mounted() {
            axios.get("../../data.json").then(response => (this.info = response.data))
        }
    });
</script>

</body>
</html>

說明:

  • 在這裏使用 v-bind 將 a:href 的屬性值與 Vue 實例中的數據進行綁定。
  • 使用 axios 框架的 get 方法請求 AJAX 並自動將數據封裝進了 Vue 實例的數據對象中。
  • 咱們在 data() 中的數據結構必需要和 AJAX 響應回來的數據格式匹配!

10.4 Vue 實例的生命週期

​ Vue 實例有一個完整的生命週期,也就是從建立、初始化數據、編譯模板、掛載 DOM、渲染 -> 更新 -> 渲染,卸載等一系列過程,咱們稱這是 Vue 的生命週期。通俗地說就是 Vue 實例從建立到銷燬的過程,就是生命週期。

​ 每一個 Vue 實例在被建立時都要通過一系列的初始化過程,例如,須要設置數據監聽、編譯模板、將實例掛載到 DOM 並在數據變化時更新 DOM 等。同時在這個過程當中也會運行一些叫作生命週期鉤子的函數,這給了用戶在不一樣階段添加本身的代碼的機會。

​ 好比 10.3 中就使用了鉤子函數 mounted 來實現 axios 獲取的數據綁定到 data() 的屬性。

​ 也有一些其它的鉤子,在實例生命週期的不一樣階段被調用,如 createdupdateddestroyed生命週期鉤子的 this 上下文指向調用它的 Vue 實例。

注:不要再選項 property 或回調上使用箭頭函數,好比 created: () => console.log(this.msg),或 vm.$watch('msg', newValue => this.myMethod())。由於箭頭函數並無 thisthis會做爲變量一致向上級語法做用域查找,直至找到爲止,常常致使Uncaught TypeError: Cannot read property of undefinedUncaught TypeError: this.myMethod is not a function 之類的錯誤。

生命週期圖示

下圖展現了實例的生命週期,隨着你的不斷學習和使用,它的參考價值會愈來愈高。

Vue 實例生命週期

11. 計算屬性

11.1 什麼是計算屬性

​ 計算屬性的重點突出在 屬性 兩個字上(屬性是名詞)。首先它是個 屬性 ,其次這個屬性有 計算 的能力(計算式動詞),這裏的 計算 就是個函數:簡單點說,它就是一個可以計算結果緩存起來的屬性(將行爲轉化成靜態屬性),僅此而已:能夠想象爲緩存!

​ 內存中運行:虛擬 DOM。計算屬性式 Vue 的特點!

11.2 計算屬性的應用

直接看代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">

    <div>當前時間1:{{currentTime()}}</div>
    <div>當前時間2:{{currentTime1}}</div>
    <div>{{msg}}</div>

</div>

<script src="../js/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            msg: '修改前,計算書屬性在緩存中不會改變'
        },
        methods: {
            currentTime: function () {
                return Date.now();
            }
        },
        computed: {
            /*
            methods 中的方法名和 computed 中的方法名不能重名
            重名的時候只會調用 methods 中的方法
            */
            currentTime1: function () {
                // 此處演示中,msg發生了修改
                this.msg;
                return Date.now();
            }
        }
    });
</script>


</body>
</html>

打開控制檯測試截圖以下:

image-20200521232448321

注意:methods 和 computed 中的方法名不能重名

說明

  • methods:定義方法,調用方法使用 currentTime(),須要帶括號。
  • computed:定義計算屬性,調用屬性使用 currentTime,不須要帶括號;this.msg 是爲了可以讓 currentTime1 觀察到數據變化而改變。
  • 若是方法中的值發生了變化,則緩存會刷新!能夠在控制檯中使用 vm.msg="修改的信息",改變數據的值,再次測試觀察效果。

經過上圖,咱們能很是清楚的看出:在調用方法時,methods 中方法的返回值一直在改變,而計算屬性中的方法的返回值並無發生改變,這是由於計算屬性在內存中運行,是虛擬 DOM。計算屬性只有在方法中內容修改的時候,纔會刷新緩存,方法的返回值纔會發生改變。

結論:

​ 調用方法時,每次都須要進行計算。既然有計算過程,則一定產生系統開銷。那若是這個結果是不常常變化的呢?此時就能夠考慮將這個結果緩存起來,採用計算屬性能夠很方便作到這一點。計算屬性的主要特性就是爲了將不常常變化的計算結果進行緩存,以節約咱們的系統開銷!

12. 內容分發

12.1 slot 插槽

​ 在 Vue.js 中咱們使用 <slot>元素做爲承載分發內容的出口,翻譯過來就是插槽,能夠應用在組合組件的場景中。實例代碼以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!-- view層 -->
<div id="app">
<todo >
    <!-- 往 slot 插槽中插入 language-title 組件
        slot="language-title" : 將組件 language-title(<language-title></language-title>) 綁定 todo組件中 name="language-title" 的插槽
        : 是 v-bind: 的簡寫,就像 $ 是 jQuery 的簡寫同樣
        :title="title" :title 是用來綁定組件language-title中的title屬性  ="title" 是給組件中的title屬性賦給 Vue實例中的data屬性中title變量的值
     -->
    <language-title slot="language-title" :title="title"></language-title>
    <!-- 往 slot 插槽中插入 language-li 組件
            slot="language-li" : 將組件 language-li(<language-li></language-li>) 綁定 todo組件中 name="language-li" 的插槽
        :language="language" :language 是用來綁定組件language-li中的language屬性  ="language" 是給組件中的title屬性賦給 v-for循環中獲取的language
    -->
    <language-li slot="language-li" :language="language" v-for="language in languages"></language-li>
</todo>
</div>

<script src="../js/vue.min.js"></script>
<script>

    /* todo組件 */
    Vue.component('todo',{
        template:
            /* ‘\’表明換行 */
            '<div>\
                <slot name="language-title"></slot>\
                <ul>\
                    <slot name="language-li"></slot>\
                </ul>\
            \</div>'
    });

    /* language-title 組件 */
    Vue.component('language-title',{
        props: ['title'],
        template: '<div>{{title}}</div>'
    });

    /* language-li 組件 */
    Vue.component('language-li',{
        props: ['language'],
        template: '<li>\
            {{language}}\
            \</li>'
    });

    /* Vue 實例 */
    new Vue({
        el: "#app",
        data: {
            title: '編程語言',
            languages: ['Java','C++','JavaScript','Python']
        }
    });
</script>

</body>
</html>

說明

  • 根據關注度分離原則(SoC),視圖只專一於視圖的功能,因此咱們沒法在視圖層中獲取組件中定義的數據,必須經過 v-bind 進行綁定。
  • template 的模板字符串中,‘\’(反斜槓)表明換行 。
  • v-bind 的簡寫是 : ':'(冒號) v-on 的簡寫是:'@'(@)。W
  • 在視圖層中,slot = "xxx" 中的值必需要提早在 組件的 template 屬性中使用 <slot></slot> 標籤訂義,上面代碼中 <slot name="language-title"></slot><slot name="language-li"></slot> 就是定義插槽名字。沒定義或者使用時寫錯插槽名字,則沒法使用該插槽。
  • v-bind 綁定的變量是組件中的變量,並非 Vue 實例中的變量:
    • :title="title":title 是用來綁定組件language-title中的title屬性 ="title" 是給組件中的title屬性賦給 Vue實例中的data屬性中title變量的值。
    • :language="language":language 是用來綁定組件language-li中的language屬性 ="language" 是給組件中的title屬性賦給 v-for循環中獲取的language

上面代碼書寫步驟

  1. 建立 Vue 實例,el: 綁定 View 層,在 data屬性中定義須要展現的數據。
  2. 編寫組件,經過 props 獲取 View 層的變量,並在 template 中寫好插槽中的模板或預留插槽。
  3. 編寫視圖層,將組件綁定到插槽,並將 View 層和 Vue 實例的數據和組件綁定。

12.2 自定義事件

​ 經過上面代碼能夠發現,數據項在 Vue 得實例中,但刪除操做要在組件中完成,那麼組件如何才嗯那個刪除 Vue 實例中得數據呢? 此時就涉及到參數傳遞與事件分發了。Vue 爲咱們提供了自定義事件得功能能很好地幫助咱們解決這個問題。使用 this.$emit('自定義事件名',參數),操做具體以下:

  1. 在 Vue 實例中,增長 methods 對象並定義一個名爲 removeLanguage1 的方法

    new Vue({
        el: "#app",
        data: {
            title: '編程語言',
            languages: ['Java','C++','JavaScript','Python','PHP']
        },
        methods: {
            removeLanguage1 : function (index) {
                this.languages.splice(index,1);
            }
        }
    });
  2. 在組件 language-li 增長 methods 對象,並定義一個名爲 removeLanguage2 的方法

    Vue.component('language-li',{
        props: ['language','index','key'],
        // 只能綁定當前組件的方法
        template: '<li>{{index}} --->  {{language}}<button @click="deleteLanguage2">刪除</button></li>',
        methods: {
            deleteLanguage2: function (index) {
                // this.$emit : 自定義事件分發
                this.$emit('remove',index)
            }
        }
    });
  3. 在 Vue 層定義自定義事件,並綁定 Vue 實例中的事件方法

    <div id="app">
        <todo>
            <language-title slot="language-title" :title="title"></language-title>
            <!-- @remove="removeLanguage1(index)" 綁定自定義事件,使得組件能夠使用 Vue 實例中的方法 -->
            <language-li slot="language-li" v-for="(language,index) in languages" :language="language" :index="index" @remove="removeLanguage1(index)"></language-li>
        </todo>
    </div>

完整測試代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <todo>
        <language-title slot="language-title" :title="title"></language-title>
        <!-- @remove="removeLanguage1(index)" 綁定自定義事件,使得組件能夠使用 Vue 實例中的方法 -->
        <language-li slot="language-li" v-for="(language,index) in languages" :language="language" :index="index" @remove="removeLanguage1(index)"></language-li>
    </todo>
</div>

<script src="../js/vue.min.js"></script>
<script>

    Vue.component('todo',{
        template:
            '<div>\
                <slot name="language-title"></slot>\
                <ul>\
                    <slot name="language-li"></slot>\
                </ul>\
            </div>'
    });

    Vue.component('language-title',{
        props: ['title'],
        template: '<div>{{title}}</div>'
    });

    Vue.component('language-li',{
        props: ['language','index','key'],
        // 只能綁定當前組件的方法
        template: '<li>{{index}} ---> {{key}} --->  {{language}}<button @click="deleteLanguage2">刪除</button></li>',
        methods: {
            deleteLanguage2: function (index) {
                // this.$emit : 自定義事件分發
                this.$emit('remove',index)
            }
        }
    });

    new Vue({
        el: "#app",
        data: {
            title: '編程語言',
            languages: ['Java','C++','JavaScript','Python','PHP']
        },
        methods: {
            removeLanguage1 : function (index) {
                this.languages.splice(index,1);
            }
        }
    });
</script>

</body>
</html>

13. 第一個 vue-cli 項目

13.1 什麼是 vue-cli

​ vue-cli 官方提供的一個腳手架,用於快速生成一個 vue 的項目模板;

​ 預先定義好的目錄結構及基礎代碼,就比如咋門在建立 Maven 項目時能夠選擇建立一個骨架項目,這個骨架項目就是腳手架,讓咱們的開發更加的快速;

主要的功能:

  • 統一的目錄結構
  • 本地調試
  • 熱部署
  • 單元測試
  • 集成打包上線

13.2 須要的環境

傻瓜式安裝 Node.js,除了安裝路徑不想安裝c盤外,所有均可以點 下一步。

確認 node.js 是否安裝成功:

  • cmd dos 命令窗口輸入 node -v,查看是否可以正確打印版本信息。
  • cmd dos命令窗口輸入 npm -v,查看是否可以正確打印版本信息。

這個 npm,就是一個軟件包管理工具,就和 python 中 pip,Linux 中 apt 軟件安裝差很少。

Node.js 換源:使用淘寶鏡像加速器 (cnpm)

換國內源,可讓下載速度提高。

# -g 就是全局安裝
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 永久更換源(使用淘寶鏡像下載時能夠直接使用npm而非cnpm)
npm config set registry https://registry.npm.taobao.org

安裝 vue-cli

npm install vue-cli -g

13.3 第一個 vue-cli 程序

​ dos 窗口以管理員身份運行,而後進入須要建立程序的目錄,這裏演示路徑 D:\Code\code\h5\first-vue-cli

  1. 輸入命令 vue init webpack "項目名"(這裏演示項目名爲 myvue)

    vue init webpack myvue
  2. 進入 myvue 目錄,並安裝項目依賴。安裝項目的依賴信息存在項目的 package.json 文件中,執行命令後,會去 package.json 文件中查找依賴安裝。

    # 進入myvue 目錄
    cd myvue
    # 安裝依賴
    npm install
  3. 啓動 vue-cli 程序,並查看是否啓動成功

    # 啓動 vue-cli 程序
    npm run dev

    啓動程序後,根據啓動的地址去訪問,若出現以下頁面,則表明程序建立啓動成功。咱們的第一個 vue-cli 程序就建立好了!

    image-20200522232431439

14. Webpack

14.1 什麼是 Webpack

​ 本質上, webpack 是一個現代 JavaScript 應用的靜態模塊打包器(modeule bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個木塊,而後將全部這些模塊打包成一個或多個bundle。

​ Webpack 是當下熱門的前端資源模塊化管理和打包工具,它能夠將許多鬆散耦合的木塊按照依賴和規則打包稱符合生產環境部署的前端資源。還能夠按需加載的木塊進行代碼分離,等到實際須要時再異步加載。經過 loader 轉換,任何形式的資源均可以看成模塊。好比 ComminsJS、AMD、ES六、CSS、JSON、CoffeeScript、LESS等。

​ 伴隨着移動互聯網的大潮,當今愈來愈多的網站已經從網頁模式進化到了 WebApp 模式。他們運行在現代瀏覽器裏,使用 HTML五、CSS三、ES6 等新的技術來開發豐富的功能。網頁已經不只僅是完成瀏覽器的基本需求。WebApp 一般是一個 SPA (單頁面應用),每個視圖經過異步的方式加載,這致使頁面初始化和使用過程當中會加載愈來愈多的 JS 代碼,這給前端的開發流程和資源組織帶來了巨大挑戰。

​ 前端開發和其它開發工做的主要區別:首先是前端基於多語言、多層次的編碼和組織工做;其次,前端產品的交互式基於瀏覽器的,這些資源式經過增量加載的方式運行到瀏覽器端。如何在開發環境組織好這些碎片化的代碼和資源,而且保證他們在瀏覽器端快速、優雅地加載和更新,就須要一個模塊化系統,這個理想中地模塊化系統式前端工程師多年來一直探索地難題。

14.2 模快化的演進

14.2.1 Script 標籤

<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="module3.js"></script>

​ 這是最原始的 JavaScript 文件加載的方式。若是把每個文件看做是一個模塊,那麼他們的接口一般是暴露在全局做用域下。也就是說定義在 window 對象中,不一樣模塊的調用都是一個做用域。

​ 這種原始的加載方式暴露了一些顯而易見的弊端:

  • 全局做用域下容易形成變量衝突
  • 文件只能按照 <script> 的書寫順序進行加載
  • 開發人員必須主觀解決模塊和代碼庫的依賴關係
  • 在大型項目中,各類資源難以管理,長期積累的問題致使代碼庫混亂不堪

14.2.2 ComminsJS

​ 服務器端的 NodeJS 遵循 ConmmonsJS 規範,該規範核心思想是容許模塊經過 require 方法來同步加載所需依賴的其它模塊,而後經過 exportsmodule.exports 來導出須要暴露的接口。

優勢

  • 服務器端模塊便於重用
  • NPM 中已經有超過 45 萬個能夠使用的模塊包
  • 簡單易用

缺點

  • 同步模塊加載方式不適合在瀏覽器環境中,同步意味着阻塞加載,瀏覽器資源是異步加載的
  • 不能非阻塞的並行加載多個模塊

實現

  • 服務端的 NodeJS
  • Browserify,瀏覽器的 CommonsJS 實現,能夠使用 NPM 的模塊,可是編譯打包後的文件體積較大
  • modules-webmake,相似 Browserify,但不如 Browserify 靈活
  • wreq,Browserify 的前身

14.2.3 AMD

​ Asynchronous Module Definition 規範其實主要是一個主要接口 define(id?。dependencies?,factory);它要生命模塊的時候指定全部的依賴 dependencies ,而且要看成形參傳到 factory 中,對於模塊提早執行。

define("module",["dep1","dep2]),function(d1,d2){
                 return someExportedBalue;
});
require(["module","../file,js"]),function(module, file {});

優勢

  • 適合在瀏覽器環境中異步加載模塊
  • 能夠運行並行加載多個模塊

缺點

  • 提升了開發成本,代碼的閱讀和書寫比較困難,模塊定義方式的語義不順暢
  • 不符合通用的模塊化思惟方式,是一種妥協的實現

實現

  • RequireJS
  • curl

14.2.4 CMD

Commons Modules Definition 規範和 AMD 很類似,儘可能保持簡單,並與 CommonsJS 和 NodeJS 和 Modules 規範保持了很大的兼容性

define(function(require,exports,module)){
    var $ = require("jquery");
	var Spinning = require("./spinning");
	exports.doSomething = ....;
}

優勢

  • 依賴就近,延遲執行
  • 能夠很容易在 NodeJS 中運行

缺點

  • 依賴 SPM 打包,模塊的加載邏輯偏重

實現

  • Sea.js
  • coolie

14.2.5 ES6模塊

​ EcmaScipt6 標準增長了 JavaScript 語言層面的模板體系定義。 ES6 模塊的設計思想,是儘可能靜態化,使編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonsJS 和 AMD 模塊都只能在運行時肯定這些東西。

import "jquery";
exports function doStuff(){}
module "locaModule" {}

優勢

  • 容易進行靜態分析
  • 面向將來的 EcmaScript 標準

缺點

  • 原生瀏覽器尚未實現該標準
  • 全新的命令,新版的 NodeJS 才支持

實現

  • Babel

你們指望的模塊系統

​ 能夠兼容多種模塊風格,儘可能能夠利用已有代碼,不只僅是 JavaScript 模塊化,還有 CSS、圖片、字體等資源也須要模塊化

14.3 安裝 Webpack

​ WebPack 是一款模塊加載器兼打包工具,它能把各類資源,入 JS、JSX、ES六、SASS、LESS、圖片等都做爲模塊來處理和使用。

安裝

npm install webpack -g
npm install webpack-cli -g

測試安裝成功

webpack -v
webpack-cli -v

配置

建立 webpack.config.js 配置文件

  • entry:入口文件,指定 WebPack 用哪一個文件做爲項目的入口
  • output:輸出,指定 WebPack 把處理完成的文件放置到指定路徑
  • module:模塊,用於處理各類類型的文件
  • plugins:插件。如:熱更新、代碼重用等
  • resolve:設置路徑指向
  • watch:監聽,用於設置文件改動後直接打包
module.exports = {
    entry = "",
    output: {
    path: "",
    filename: ""
	},
    module:{
		loaders: {
			{test: /\.js$/, loader: ""}
		}
	},
	plugins:{},
	resolve:{},
	watch: true
}

直接運行 webpack 命令打包

14.4 使用 Webpack

  1. 建立項目(跟 vue-cli 項目差很少,先建立一個文件夾,而後用idea打開)

  2. 建立一個名爲 modules 的目錄,用於放置 JS 模塊等靜態資源

  3. 在 modules 目錄下建立模塊文件,如 hello.js ,用於編寫 JS 模塊相關的代碼

    // 暴露一個方法:hello
    exports.hello = function () {
        document.write("<h1>hello,webpack</h1>");
    };
  4. 在 modules 目錄下建立一個名爲 main.js 的入口文件,用於打包時設置 entry 屬性

    // require 導入一個模塊,就能夠調用這個模塊中的方法了
    var hello = require("./hello");
    hello.hello();
  5. 在項目根目錄下建立 webpack.comnfig.js 配置文件,使用 webpack 命令打包

    module.exports = {
      entry: './modules/main.js',
      output:{
          filename: "./js/bundle.js"
      }
    };

    注:webpack.config.js 的名字不能寫錯,還有 webpack.config.js 文件必須放在項目根目錄下!

    此時,項目會生成 dist/js 目錄,並生成了 bundle.js 文件,bundle.js 文件就是打包後的 js 文件,裏面的代碼是用 ES5 規範書寫的

  6. 在項目根目錄下建立 index.html,測試打包是否成功

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!-- 加載模塊主入口 -->
        <script src="dist/js/bundle.js"></script>
    </body>
    </html>

說明:webpack --watch 能夠對 webpack 項目進行熱部署,即修改源代碼後,會自動打包。

15. vue-router 路由

15.1 簡介

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,讓構建單頁面應用變得易如反掌。包含的功能有:

  • 嵌套的路由/視圖表
  • 模塊化的、基於組件的路由配置
  • 路由參數、查詢、通配符
  • 基於 Vue.js 過渡系統的視圖過渡效果
  • 細粒度的導航控制
  • 帶有自動激活的 CSS class 的連接
  • HTML5 例時模式或 hash 模式,在 IE9 中自動降級
  • 自定義的滾動條行爲

15.2 安裝

基於第一個 vue-cli 進行測試學習,先看 node——modules 中是否存在 vue-router

vue- router 是一個插件包,因此咱們仍是須要用 npm/cnpm 來進行安裝。打開命令行工具,進入你的項目目錄,輸入下面命令。

npm install vue-router --save-dev

若是這裏 error 的話,就使用 cnpm 執行這個命令。

若是在一個模塊化工程中使用它,必須 經過 Vue.use() 明確地安裝路由功能:

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter);

15.3 測試

  1. 刪除沒有用的東西

  2. component 目錄下存放咱們本身的組件

    • Content.vue

      <template>
          <h1>123</h1>
      </template>
      
      <script>
          export default {
              name: "Content"
          }
      </script>
      
      <style scoped>
      
      </style>
    • Main.vue

      <template>
          <h1>首頁</h1>
      </template>
      
      <script>
          export default {
              name: "Main"
          }
      </script>
      
      <style scoped>
      
      </style>
  3. 建立文件加 router ,並在該文件夾下建立 index.js 配置路由

    index.js

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    // 導入組件
    import Content from '../components/Content'
    import Main from '../components/Main'
    
    // 安裝路由
    Vue.use(VueRouter);
    
    // 配置導出路由
    export default new VueRouter({
      routes: [ // 這裏是routes,不是routers,單詞不要寫錯!不然 router-view 將不會渲染
        {
          // 路由路徑
          path: '/content',
          // 路由名字,能夠省略 
          name: 'content',
          // 路由組件
          component: Content
        },
        {
          path: '/main',
          name: 'main',
          component: Main
        }
      ]
    });
  4. 在 main.js 中配置路由

    main.js

    import Vue from 'vue'
    import App from './App'
    // 導入router
    import router from './router'
    
    Vue.config.productionTip = false;
    
    new Vue({
      el: '#app',
      // 配置路由
      router, // 這裏是 router,自定義命名須要以鍵值對的形式在 vue 實例中聲明
      components: { App },
      template: '<App/>'
    });
  5. 在 App.vue 中測試路由是否配置成功

    <template>
      <div id="app">
        <h1>hello,vue</h1>
        <router-link to="/main">首頁</router-link>
        <router-link to="/content">內容頁</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'App',
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>

說明:

  • 配置路由的 index.js 中,vue-router 的屬性是 routes 而不是 routers,注意單詞拼寫,不然 <router-view></router-view> 視圖將不會渲染
  • 在 main.js 中配置路由時,Vue 實例中默認屬性是 router,若是要使用自定義命名,則須要以鍵值對的形式聲明。不然將會報 Vue | Error in render: "TypeError: Cannot read property 'matched' of undefined" 的錯

15.4 路由模式與 404

路由模式有兩種

修改路由配置,代碼以下:

export default new Router({
  mode: 'history',
  routes: [
   ....   
  ]
});

處理 404

  1. 建立一個名爲 NotFound.vue 的視圖組件

    <template>
        <h1>404,你的頁面走丟了!</h1>
    </template>
    
    <script>
        export default {
            name: "NotFound"
        }
    </script>
    
    <style scoped>
    
    </style>
  2. 在路由的中配置一個 404 的路由

    import NotFound from '../components/NotFound';
    {
      path: '*',
      component: NotFound
    }

16. Vue 實戰快速上手

​ 咱們結合 ElementUI 組件庫,將所須要的知識點應用到實際中,以最快的速度來掌握 Vue 的使用。

  1. dos 窗口進入到須要建立工程的文件夾

  2. 建立工程,導入依賴

    # 建立工程項目
    vue init webpack 工程名
    # 安裝開發環境
    npm install vue-router // 安裝 vue-router
    npm i element-ui -S	  // 安裝 element-ui
    cnpm install sass-loader node-sass --save-dev	// 安裝 SASS,建議使用 國內員安裝
    npm install // 安裝依賴
  3. 啓動項目,查看是否安裝成功

    npm run dev
  4. 刪除多餘的配置和組件,編寫須要的組件

    • Main.vue

      <template>
          <h1>主頁</h1>
      </template>
      
      <script>
          export default {
              name: "Main"
          }
      </script>
      
      <style scoped>
      
      </style>
    • Login.vue

      <template>
        <div>
        <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
          <h3 class="login-title">歡迎登陸</h3>
          <el-form-item label="帳號" prop="username">
            <el-input type="text" placeholder="請輸入帳號" v-model="form.username"/>
          </el-form-item>
          <el-form-item label="密碼" prop="password">
            <el-input type="password" placeholder="請輸入密碼" v-model="form.password"/>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" v-on:click="onSubmit('loginForm')">登陸</el-button>
          </el-form-item>
        </el-form>
      
        <el-dialog
          title="舒適提示"
          :visible.sync="dialogVisible"
          width="30%"
          :before-close="handleClose">
          <span>請輸入帳號和密碼</span>
          <span slot="footer" class="dialog-footer">
              <el-button type="primary" @click="dialogVisible = false">確 定</el-button>
            </span>
        </el-dialog>
        </div>
      </template>
      
      <script>
        export default {
          name: "Login",
          data() {
            return {
              form: {
                username: '',
                password: ''
              },
      
              // 表單驗證,須要在 el-form-item 元素中增長 prop 屬性
              rules: {
                username: [
                  {required: true, message: '帳號不可爲空', trigger: 'blur'}
                ],
                password: [
                  {required: true, message: '密碼不可爲空', trigger: 'blur'}
                ]
              },
      
              // 對話框顯示和隱藏
              dialogVisible: false
            }
          },
          methods: {
            onSubmit(formName) {
              // 爲表單綁定驗證功能
              this.$refs[formName].validate((valid) => {
                if (valid) {
                  // 使用 vue-router 路由到指定頁面,該方式稱之爲編程式導航
                  this.$router.push("/main");
                } else {
                  this.dialogVisible = true;
                  return false;
                }
              });
            }
          }
        }
      </script>
      
      <style scoped>
        .login-box {
          border: 1px solid #DCDFE6;
          width: 350px;
          margin: 180px auto;
          padding: 35px 35px 15px 35px;
          border-radius: 5px;
          -webkit-border-radius: 5px;
          -moz-border-radius: 5px;
          box-shadow: 0 0 25px #909399;
        }
      
        .login-title {
          text-align: center;
          margin: 0 auto 40px auto;
          color: #303133;
        }
      </style>
  5. 建立文件夾 router ,並配置路由 index.js

    index.js

    import Vue from 'vue';
    import Router from 'vue-router';
    
    import Login from '../components/Login';
    import Main from '../components/Main';
    
    Vue.use(Router);
    
    
    export default new Router({
      routes: [
        {
          path: '/main',
          name: 'main',
          component: Main
        },
        {
         path: '/login',
          name: 'login',
         component: Login
        }
      ]
    });
  6. 在 main.js 中註冊 Element-UI 和 路由器

    import Vue from 'vue'
    import App from './App'
    
    // 導入element-ui
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    
    import router from './router'
    
    Vue.use(ElementUI);
    
    Vue.config.productionTip = false;
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      components: { App },
      template: '<App/>'
    });
  7. 驗證

    App.vue

    <template>
      <div id="app">
        <h1>app</h1>
        <router-link to="/main">主頁</router-link>
        <router-link to="/login">登陸</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'App',
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>

17. 嵌套路由

17.1 elementUI 的 el 標籤解釋

標籤 解釋
el-col 總體,默認佔24柵格
el-container 主題區域
el-tooltip 提示框信息
el-header 內容頭部區域
el-aside 左側內容區域
el-main 主要內容區域
el-menu 整個導航欄
el-submenu 單獨一個導航欄
el-menu-item 單獨一個導航欄裏面的單獨一個欄目
el-menu-item-group 一組導航欄 el-date-picker 組件事件格式化方式
el-dialog 彈出對話框
el-table 表格
el-table-column 表格列
el-pagination 新增分頁
el-select 選擇框
el-button 按鈕
el-form 表單提交
el-form-item lable = "活動區域" 表單域
el-input-number : (@change = handlechange -- change 事件) 數字輸入框,能夠實現加減
el-tab-pane 是 el-table 的分頁

17.2 什麼是嵌套路由

嵌套路由又稱子路由,在實際應用中,一般由多層嵌套的組件組合而成。一樣的,URL 中各端動態路徑也按某種結構對應嵌套的各層組件。

17.3 嵌套路由的使用

根據上面的路由工程項目爲基礎,增長嵌套路由。

  1. 增長鬚要使用的組件

    PrivateInfo.vue

    <template>
        <h1>信息頁</h1>
    </template>
    
    <script>
        export default {
            name: "info"
        }
    </script>
    
    <style scoped>
    
    </style>

    TeamInfo.vue

    <template>
        <h1>團隊信息</h1>
    </template>
    
    <script>
        export default {
            name: "Team"
        }
    </script>
    
    <style scoped>
    
    </style>
  2. 編寫路由展現頁面

    代碼是從 ElementUI 官網上拷貝後修改了一些內容,並放到 Main.vue 中

    Main.vue

    <template>
      <div class="mainDiv">
        <!-- 側邊欄 -->
        <div >
          <el-col :span="4" class="navMenuDiv">
            <el-menu
              default-active="2"
              class="el-menu-vertical-demo"
              @open="handleOpen"
              @close="handleClose">
              <el-submenu index="1">
                <template slot="title">
                  <i class="el-icon-location"></i>
                  <span>信息管理</span>
                </template>
                <el-menu-item-group>
                  <el-menu-item index="1-1" >
                    <router-link to="/privateInfo">我的信息</router-link>
                  </el-menu-item>
                  <el-menu-item index="1-2">
                    <router-link to="/teamInfo">團隊信息</router-link>
                  </el-menu-item>
                  <el-menu-item index="1-3">
                    <router-link to="/main">返回首頁</router-link>
                  </el-menu-item>
                </el-menu-item-group>
                <el-submenu index="1-4">
                  <template slot="title">選項4</template>
                  <el-menu-item index="1-4-1">選項1</el-menu-item>
                </el-submenu>
              </el-submenu>
              <el-menu-item index="2">
                <i class="el-icon-menu"></i>
                <span slot="title">導航二</span>
              </el-menu-item>
              <el-menu-item index="3">
                <i class="el-icon-document"></i>
                <span slot="title">導航三</span>
              </el-menu-item>
              <el-menu-item index="4">
                <i class="el-icon-setting"></i>
                <span slot="title">導航四</span>
              </el-menu-item>
            </el-menu>
          </el-col>
        </div>
    
        <!-- 導航欄 -->
        <div >
          <el-col :span="20">
          <el-menu
            :default-active="activeIndex2"
            class="el-menu-demo"
            mode="horizontal"
            @select="handleSelect"
            background-color="#545c64"
            text-color="#fff"
            active-text-color="#ffd04b" >
            <el-menu-item index="1">處理中心</el-menu-item>
            <el-submenu index="2">
              <template slot="title">個人工做臺</template>
              <el-menu-item index="2-1">選項1</el-menu-item>
              <el-menu-item index="2-2">選項2</el-menu-item>
              <el-menu-item index="2-3">選項3</el-menu-item>
              <el-submenu index="2-4">
                <template slot="title">選項4</template>
                <el-menu-item index="2-4-1">選項1</el-menu-item>
                <el-menu-item index="2-4-2">選項2</el-menu-item>
                <el-menu-item index="2-4-3">選項3</el-menu-item>
              </el-submenu>
            </el-submenu>
            <el-menu-item index="3" disabled>消息中心</el-menu-item>
            <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">訂單管理</a></el-menu-item>
          </el-menu>
          </el-col>
        </div>
    
        <!-- 展現信息 -->
        <el-main>
          <router-view/>
        </el-main>
    
      </div>
    
    </template>
    
    <script>
      export default {
        name: "Main",
        data() {
          return {
            activeIndex: '1',
            activeIndex2: '1'
          };
        },
        methods: {
          handleSelect(key, keyPath) {
            console.log(key, keyPath);
          },
          handleOpen(key, keyPath) {
            console.log(key, keyPath);
          },
          handleClose(key, keyPath) {
            console.log(key, keyPath);
          }
        }
      }
    </script>
    
    <style scoped>
      .navMenuDiv{
        text-align: left;
      }
      .mainDiv {
        margin-top: auto;
      }
    </style>
  3. 配置嵌套路由

    index.js

    import Vue from 'vue';
    import Router from 'vue-router';
    
    import Login from '../components/Login';
    import Main from '../components/Main';
    import PrivateInfo from '../components/PrivateInfo';
    import TeamInfo from '../components/TeamInfo'
    
    Vue.use(Router);
    
    
    export default new Router({
      routes: [
        {
          path: '/main',
          component: Main,
          children: [
            { path: '/privateInfo', component: PrivateInfo },
            { path: '/teamInfo', component: TeamInfo}
          ]
        },
        {
         path: '/login',
         component: Login
        },
      ]
    });

    說明

    • children 屬性裏配置的就是嵌套路由,嵌套路由的路由格式和咱們以前配置的路由格式同樣
  4. 啓動項目,測試是否跳轉

    npm run dev

18. 數據傳輸

18.1 經過 URL 傳輸數據

18.1.1 RESTful

概念

RESTful 就是一個資源定位及資源操做的風格。不是標準,也不是協議,只是一種風格。基於這個風格設計的軟件能夠更簡潔,更由層次,更易於實現緩存機制。

功能

資源:互聯網全部事物均可以被抽象爲資源。

資源操做:使用 POST、DELETE、PUT、GET,使用不一樣方法對資源進行操做。分別對應 添加、刪除、修改、查詢。

傳統方式操做資源

http://localhost:8080/item/action?id=1http://localhost:8080/item/action?id=1&age=18http://localhost:8080/item/action

使用 RESTful 操做資源

http://loaclhos:8080/item/1http://localhost:8080/item/1/18http://loaclhost:8080/item/action

經過對比能夠看出,RESTful 風格更加簡潔,且不會把咱們的參數信息暴露給用戶,更加安全。如今大部分網站都是使用 RESTful 風格。

18.1.2 示例代碼

在上面代碼的基礎上進行修改

  1. 在 index.js 中修改路由的 path,使用path接收參數

    import Vue from 'vue';
    import Router from 'vue-router';
    
    import Login from '../components/Login';
    import Main from '../components/Main';
    import PrivateInfo from '../components/PrivateInfo';
    import TeamInfo from '../components/TeamInfo';
    import NotFound from '../components/NotFound';
    
    Vue.use(Router);
    
    
    export default new Router({
      mode: 'history',
      routes: [
        {
          path: '/main',
          component: Main,
          children: [
            // :id :接收 URL 中傳來的 id 參數 , name :視圖層經過name綁定路由
            { path: '/privateInfo/:id', name: 'privateInfo', component: PrivateInfo },
            { path: '/teamInfo', component: TeamInfo}
          ]
        },
        {
         path: '/login',
         component: Login
        },
        {
          path: '/goHome',
          redirect: 'main'
        },
    
        {
          path: '*',
          component: NotFound
        }
      ]
    });

    說明

    • /privateInfo/:id:id 表示接收 URL 中傳來的 id 參數
    • name :視圖層經過 name 綁定路由
  2. 修改 router-link 標籤內的內容,使其可以經過 URL 將參數傳到路由,而且能讓 vue 實例獲取到參數

    <el-menu-item index="1-1" >
      <!-- 
    	:to :讓 params 中的參數綁定到 vm 中,讓組件能夠經過 props 獲取到,
    	默認是不用寫 name 的,但若是須要數據傳輸,則須要 name 綁定路由
    	parms: 傳遞參數
      -->
      <router-link :to="{name: 'privateInfo', params:{id: 1}}">我的信息</router-link>
    </el-menu-item>

    說明

    • :to :讓 params 中的參數綁定到 vm 中,讓組件能夠經過 props 獲取到
    • 默認是不用寫 name 的,但若是須要數據傳輸,則須要 name 綁定路由
    • parms :傳遞參數
  3. 能夠使用兩種方式來獲取參數

    • 經過路由得到參數 $route.params.id

      <template>
        <div>
          <h1>信息頁</h1>
          {{ $route.params.id }}
        </div>
      </template>
      
      <script>
        export default {
          name: "info",
        }
      </script>
      
      <style scoped>
      
      </style>
    • 經過 props 得到參數

      使用這種方式前,須要在路由中開啓 props 傳參,讓其值爲 true 則是開啓

      // props:true  :開啓 props 傳參,只有等於 true,組件才能經過 props 接收到路由的參數
      { path: '/privateInfo/:id', name: 'privateInfo', component: PrivateInfo, props: true },

      修改 PrivateInfo 的內容,讓組件經過 props 接收參數。而後經過 {{ id }} 獲取參數

      <template>
        <div>
          <h1>信息頁</h1>
          {{ id }}
        </div>
      </template>
      
      <script>
        export default {
          name: "info",
          props: ['id']
        }
      </script>
      
      <style scoped>
      
      </style>

    第二種更符合咱們 java 程序員的思惟。

18.2 axios 異步通訊傳輸數據

18.2.1 路由鉤子

beforRouteEnter :在進入路由前執行

beforRouteLeave :在離開路由前執行

示例代碼:

<script>
    export default {
      name: "info",
      /*
      * 跟 Java 的過濾器差很少
      * to:去哪裏
      * from:從哪來
      * next:跟過濾器的 chain 差很少,若是不調用next方法,則會停在這裏不會繼續前進
      * */
      beforeRouteEnter: (to,from,next)=>{
        console.log('進入路由以前');
      },
      beforeRouteLeave: (to,from,next)=>{
        console.log('離開路由以前');
        next();
      },
    }
</script>

在開發者工具的控制檯中查看效果

image-20200525220434728

咱們每進一次路由,就會觸發路由鉤子的beforRouteEnter ,跳轉到其它頁面時會觸發路由鉤子的beforRouteLeave

參數說明

  • to:路由將要跳轉的路徑信息
  • from:路徑跳轉前的路徑信息
  • next:路徑的控制參數
    • next() 跳入下一個頁面
    • next('/path') 改變路由的跳轉方向,使其跳到另外一個路由
    • next(false) 返回原來的頁面
    • next((vm) => {}) 僅在 beforeRouteEnter 中可用,vm 是組件實例

18.2.2 在鉤子函數中使用 Axios 異步請求

  1. 安裝 Axios

    npm install --save axios vue-axios
  2. main.js 引入 Axios

    // 引入 Axios
    import axios from 'axios';
    import VueAxios from 'vue-axios';
  3. 將data.json 文件放在 static/mock 文件夾內,並在 beforRouteEnter 中進行異步加載

    data.json

    {
      "name": "bilibili",
      "url": "www.bilibili.com",
      "page": 1,
      "isNonProfit": true,
      "address": {
        "street": "黃石路",
        "city": "廣州市",
        "country": "中國"
      },
      "links": [
        {
          "name": "百度",
          "url": "www.baidu.com"
        },
        {
          "name": "谷歌",
          "url": "www.google.com"
        }
      ]
    }

    beforRouteEnter 中進行異步加載

    <template>
      <div>
        <h1>信息頁</h1>
        {{ id }}
      </div>
    </template>
    
    <script>
      export default {
        name: "info",
        props: ['id'],
        /*
        * 跟 Java 的過濾器差很少
        * to:去哪裏
        * from:從哪來
        * next:跟過濾器的 chain 差很少
        * */
        beforeRouteEnter: (to,from,next)=>{
          console.log('進入路由以前');
          next(vm => {
            vm.getData(); // 進入路由以前執行 getData
          });
          next();
        },
        beforeRouteLeave: (to,from,next)=>{
          console.log('離開路由以前');
          next();
        },
        methods: {
          getData : function () {
            this.axios.get('../static/mock/data.json').then(function (response) {
              console.log(response.data);
            });
          }
        }
      }
    </script>
    
    <style scoped>
    
    </style>
  4. 測試,並在控制檯中查看輸出

    image-20200525221434068

相關文章
相關標籤/搜索