1. 程式人生 > >用Vue開發仿旅遊站webapp專案總結 (下)

用Vue開發仿旅遊站webapp專案總結 (下)

用Vue開發仿旅遊站webapp專案總結 (上)

該說的話,該表明的上篇已經表明了。謝謝上篇評論區一些同學~ 很鼓勵我,不過下下篇估計沒了,這篇總結完,下下篇可能就是之後學習路的總結記錄啦。

有些話還是要說的

接觸vue不久的朋友應該會有收穫。此專案也才是萌新做的第二個Vue專案,使用了腳手架工具(vue-cli2.x非3),前輩老手們有時間看的話,有寫得不好的地方還請多多指導!~

專案中Vuex的不那麼低階的用法

因為這只是總結操作/思路,沒一步步講程式碼,還是先給個官網的圖,這樣方便看點:

前提假設,在腳手架中,我們跟路由引入全域性的方法一致去在全域性中引入Vuex。建立一個資料夾store,在資料夾下建立個index.js指令碼。在store/index.js裡面寫Vuex的一些用法邏輯,然後在入口函式main.js裡引入就行了。如下:

先忽略馬賽克...

在入口函式main.js中引入:

此時index.js裡面的邏輯

拆分

以此專案中為例,隨著專案的開發,index.js裡的邏輯會越來越複雜,所以選擇拆分。

所以,我們建立兩個指令碼(state.js、mutations.js)來分別儲存這兩段程式碼。

然後在index.js中引入:

這樣拆分完成,簡潔不少。

mapState輔助函式

在專案中,如下圖用法去取得state裡面city的資料,是不是顯稍長了點?

Vuex為我們提供了一個方便的API -> mapState

這樣用:

mapState是指,我把State區域裡面的公有屬性值對映到這個計算屬性裡。

在這裡是:把state裡city這個公有屬性的值對映到這裡的計算屬性city裡。

這樣子的話,就可以把

變成可以直接呼叫這個計算屬性:

...mapState({}/[])這裡面可以是陣列也可以是物件。是陣列的話,那我們就等於直接給計算屬性取名city了,和公有屬性的名稱一樣。

是物件的話,我們就可以給計算屬性自定義取名。

舉個...mapState(物件)的例子:

在當前城市這裡也可以改:

這裡就是傳物件給mapState,等於把公有屬性city的值對映到計算屬性currentCity裡。

此時就可以這樣用:

這樣子就不用寫的那麼複雜了。

mapMutations輔助函式

利用Vuex提供的這個API可以簡化下列程式碼:

這樣用:

mutations裡面是有changeC2()這個函式的(這個命名就....僅當測試,輕噴)。我們想在元件中呼叫mutations裡的這個函式去改變公有資料區域state裡的值,運用mapMutations可以這樣簡潔地在元件中呼叫。

這什麼意思呢?

mutations裡有個叫做changeC2這個方法,這裡在該元件的methods中是把這個mutations裡的changeC2方法對映到了該元件中methods的changeC2方法裡。

...mapMutations()引數也是可接收[]/{}的。

還是用...mapMutations(物件寫法)好理解一點,如下,做個測試:

(亂入的小姐姐~)

這樣子寫也是可以的。也更容易理解這裡的對映。

Getter、Module

Getter和Module該專案中都沒有用到。

Getter

假如我們想根據state的值,通過一些計算得到新的值的話,就可以用getter來提供新的資料,避免資料冗餘。它的定義也和computed一樣。

getter可以認為是store的計算屬性。就像計算屬性一樣,getter 的返回值會根據它的依賴被快取起來,且只有當它的依賴值發生了改變才會被重新計算。

Getter 接受 state 作為其第一個引數,也可以接收其他 getter 作為第二個引數。可以屬性訪問(store.getters),可以通過方法訪問,也有 mapGetters輔助函式(該輔助函式主要也是對映關係,將store中的getter對映到區域性元件的計算屬性中)。官方文件給的例子也比較好理解,可以自行看文件。

Module

Module的話,看得勉強理解,Vuex允許我們將store分割成模組(module)。每個模組擁有自己的state、mutation、action、getter、甚至是巢狀子模組。

當應用變得非常複雜時,可以使用Module避免store物件變得相當臃腫。

我覺得Module具體的應用要在複雜專案中親自練手過才能熟練,目前不敢輕易下手記錄,暫且記一筆。

使用keep-alive優化效能

我們可以在 開發者工具 network 的xhr 中看到

每次我們路由切換的時候(從Home元件頁面跳轉到City元件頁面或反之的時候)都要傳送ajax請求資料。

這樣子就重複請求ajax資料了,因為每次路由切換到一個元件的時候,都要重新執行該元件鉤子函式,如果該元件有在mounted鉤子裡請求ajax的話,就每次路由切換都要執行了。這樣效能不好。

此時就可以用vue內建的 keep-alive標籤來優化。

在全域性根元件App.vue中

代表的是顯示當前路由的元件,而在這個外面加個 vue 內建的 keep-alive標籤後,就可以實現這樣一個功能:

我的路由的內容被載入過一次之後,我的路由中的內容就都放到記憶體之中,下一次再進這個路由的內容的時候,就只需要從記憶體裡把以前的內容拿出來就可以了。

此時,不管切換多少次路由,都只有兩次ajax資料請求了。

因為使用了keep-alive標籤,導致有了新的生命週期函式activated(keep-alive元件啟用時呼叫)、deactivated(keep-alive 元件停用時呼叫)。

之後的路由切換不再請求ajax資料是因為元件內容是從記憶體取了不會再重新建立了,對應的mounted鉤子函式不會再執行了。

但每次切換、頁面重新顯示的時候,activated鉤子會執行。

此時可以利用這個鉤子實現一個需求:

當在列表頁選擇點選了哪個城市後,路由切換回到首頁時,首頁顯示的資料是對應著該城市的資料(意味著ajax只請求該城市對應的Home元件頁面的資料),然後如果在列表頁,選擇了與原本在Home頁相同的城市的話,就不傳送ajax請求新資料。

之前,發ajax請求的時候,是直接這樣子發:

實際上,在傳送ajax請求的時候,應該帶一個引數的。帶的這個引數應該是 Vuex 中公有的這個資料。也就是當點選哪個城市的時候,這個引數就是對應哪個城市的名稱。

怎麼在請求中帶引數呢?

在請求的連線後面 加上 ?=引數資料

如:

在網頁上試一試,傳送的引數就在下面

實現需求的思路是:

在每一次頁面重新顯示的時候(activated鉤子函式觸發)我們判斷此時頁面上的城市是否和上一次顯示的城市相同 如果不相同 就傳送ajax請求

然後我們設定個空字串 lastCity (當做一箇中間快取值用於判斷)

緊接著,當頁面掛載完畢的時候,我們給它賦予當前頁面的城市資料。

然後在頁面更新的時候,判斷上一次的 this.lastCity 的值 是否等於 更新後的 this.city 的值。如果不等於的話,就傳送新的ajax請求,請求相應city的資料,如果等於的話就不傳送。

此時,通過keep-alive新增的生命週期鉤子函式以及lastCity這個快取值就實現了我們要的功能了。

詳情頁想記錄下來的東西

實現畫廊元件功能的主要思路

先看個gif說明此功能啥樣:

就這個玩意兒。這個就是畫廊。上面有輪播,下面有頁碼。

因為這不僅僅只有一個頁面會用到,可能以後很多頁面都會用到,所以 寫個全域性公用的元件Gallary.vue。

需要在詳情頁的一個元件 Banner.vue 裡面去使用這個公共元件

gallary用fixed佔滿全屏。

利用flex佈局,讓這個如下wrapper區域垂直居中

然後使用 Vue-awosome-swiper第三方外掛,先放入兩張圖

然後給那個.wrapper定義個寬高100%。按照如下這種寫法的話width先有個100%的寬度瞭然後height也100%的意思是針對於這個width的寬度來說的,所以這裡定義了這個100%的height的意思是這個height與width的寬度相等 意思是一個正方形。

此時頁面:

我們讓圖片按比例自適應這個正方形,再把wrapper下的背景顏色去掉,此時兩張圖片可以正常顯示輪播了:

然後加頁碼,其實這個頁碼就是該外掛的按鈕區和配置引數一起控制的。先加上按鈕區程式碼:

vue-awesome-swiper這個外掛是基於swiper實現的,這裡面的配置引數比如 pagination 可以去 swiper 官網找的。

我們去官網找找看能不能找到配置我們頁碼需求的引數(當然是能找到的,不然我還寫個啥...):

由此可見,這個頁面的翻頁樣式就是對應這個paginnation中的paginationType 中的 fraction。

現在來配置引數,首先在swiper上加上 :options="swiperOption"。

然後在data裡配置。先把按鈕區配置出來:

再把paginationType ‘fraction’ 分式 給配置出來

現在就有了,但在小小的地方,審查元素才可以看見

原本框架的樣式,通過審查元素找出這裡是絕對定位。

那麼我們這樣改bottom -1rem就行了?

那肯定是不行的...

這裡有個坑,當感覺程式碼沒寫錯,頁面卻沒達到預期的時候,就是再次審查元素的時候了...審查元素髮現這個外掛元件有個swiper-container裡還定義了個overflow: hidden。

所以我們在畫廊元件裡穿透作用域來改掉這個樣式就行

畫廊邏輯部分很簡單就跳過不記錄了,不過有個坑還是值得提一下。

在畫廊自身的元件gallary.vue裡測試功能的時候都好好的,但是gallary這個公有元件是要在詳情頁的Banner.vue元件中引入的。

那麼問題就來了,當我們在Banner元件對應的頁面一下子點進去gallary元件對應的頁面的時候,輪播外掛會出現一個計算寬度高度的問題。如下gif圖這樣:

要解決這個問題,需要在gallary的輪播外掛配置引數中加上這兩個配置引數

加上這兩個引數的意思是:

我這個swiper外掛,只要監聽到我這個元素,或者父級元素變化的時候(這個監聽的就是swiper和swiper的父級元素),這個外掛會自動地自動重新整理一次,重新計算寬高。

通過這次自我重新整理,就可以解決輪播外掛的這個計算寬度高度的問題。(這些配置引數在swiper官網都可以查到怎樣用的)

實現header區塊漸隱漸現的效果

看個gif。

僅提這段,當手指往下滑的時候,逐漸顯示清晰之後一直清晰的div景點詳情框邏輯。

這個逐漸顯示清晰的這塊是用個div框來fixed定位寫的。

邏輯

一開始v-show不顯示這個div框並且讓該div框的opacity為0,在activated鉤子函式中檢測全域性scroll(window.onscroll)事件(即檢測滾動條的狀態,滾動條一旦動了就觸發scroll事件),當觸發scroll事件時,執行一個方法,此方法裡面寫邏輯。寫的邏輯是:當滾動條往下滑動60px外時讓這個div框的v-show引數為true並且通過公式 let opacity = document.documentElement.scrollTop / 140 來讓該div框隨著越往下滑動清晰度越高,然後在這條語句下面限制opacity透明度值為1:opacity = opacity > 1 ? 1 : opacity

顯而易見:document.documentElement.scrollTop的意思是獲取當前頁面的滾動條縱座標位置。

這樣功能實現了,但還有個很重要的坑。對全域性事件的解綁。

對全域性事件的解綁

在header區塊邏輯中,我們在activated鉤子中定義了個全域性scroll事件。

因為這個是全域性事件,所以我們在其他元件中也可以監測到。這樣很容易引發一系列嚴重的隱藏的bug。

所以我們應該在detail下header.vue元件中對該元件解綁:

對應keep-alive引用而可以使用的鉤子還有一個deactivated鉤子。

該鉤子在頁面即將被替換成新的頁面的時候觸發。

所以這裡我們利用deactivated鉤子removeEventListener函式來解綁全域性事件。

元件中name屬性的三個作用

1、做遞迴元件的時候會用到

舉個例子,list元件的name: 'DetailList'。在list元件模板中想要使用遞迴元件呼叫自身時,就要根據name的值來用作標籤(detail-list)呼叫。如下:

2、對某個頁面取消keep-alive的快取的時候會用到

假設有個Detail.vue元件,其name: ' Detail'。當想要keep-alive全域性元件時,Detail.vue元件對應的頁面,路由重新切換到這個頁面不用去記憶體中取快取值,可以利用Detail元件的name的值如下使用:

這樣等於是除了Detail.vue元件,其他元件都可以擁有設定keep-alive後的功能。

3、vue-devtools除錯工具

如上圖紅框裡的元件名稱,這裡的名稱就取決於設定的元件的name屬性的值。

動態路由中ajax動態獲取各個路由目錄對應的值

舉專案中例子說明,注意下圖紅框中的值

此時我們應該獲取的是,動態路由中 id為0002的引數的資料。

這樣設定後,其實動態路由中,會把對應的引數存在 這個變數id裡。

每次請求,希望把這個id帶給後端,就可以這樣寫:

寫法一

現在可以在network的XHR裡看見我們傳送給後端的請求中附帶了 id

寫法二

前面只寫介面名 後面這樣子寫(我們把引數放到params去了):

其實還有問題,這地方我想一步一步來總結

設定的動態路由,只是動態加了個id引數並不能自動讓頁面也跟著動態顯示資料,動態顯示資料還得靠ajax請求資料。

而目前這個元件是在mounted鉤子中執行ajax請求的,並且該元件有keep-alive的作用影響著。這樣當路由跳轉到id為0003/0004...頁面的時候,元件也只會從記憶體中取出第一次進入該元件某個id的頁面。並不能根據id對應顯示頁面。

怎樣通過ajax請求而動態顯示資料呢?有兩種方法,兩種方法上面都提到過。

  • 第一種 在列表頁選擇某個城市,路由自動跳轉回首頁後,首頁需要顯示的是該城市對應的資料這裡記錄過。(提示一下:利用activated鉤子,判斷引數id是否等於之前的id,如果不等則重新執行ajax請求。)

  • 第二種 元件中name屬性的三個作用中的第二個作用已經說出瞭解決方案。

這兩種方式留給讀者自行思考,想不通的可以參考下我github該倉庫裡的程式碼。src/pages/detail/Detail.vue

路由滾動行為

來看個gif

這就是路由跳轉頁面會帶來的影響。會把當前頁面(Home.vue)的螢幕的顯示的寬高 帶到 我們跳轉到的頁面(Detail.vue)上去。造成如上gif所示現象。

這樣來解決。

這個在官方文件中稱為 路由的滾動行為。

我們現在是想讓每次路由切換進入到下一個頁面的時候滾動在頂部顯示。 繼續看文件。

把這段程式碼複製到路由配置項中:

這樣就實現我們預期的需求。

配置打包

前後端聯調

一般等後端資料寫好後,我們就不再使用自己前端模擬的資料,而是去使用後端給過來的資料來除錯。

如果要訪問伺服器上的資料的話,要在配置檔案config/index.js下的proxyTable裡把target改為伺服器的地址(可以寫內網的IP地址 或 外網的域名都行)。然後改pathRewrite的話,就見實際情況資料存放在伺服器的哪個資料夾下了。

真機測試

這裡的前端的專案是通過 webpack-dev-server 啟動的,預設不允許通過ip來訪問內部伺服器。所以我們需要把預設的配置項做修改。

想讓這個 webpack-dev-sever 能夠被ip訪問的話,需要這樣配置下:

(貌似漏點了... 其實也沒關係....)

然後這裡真機測試的時候,有時候就會遇到一些在PC上開發時發現不了的bug以及要考慮相容性。這個就要各人根據實際情況來改了。

打包上線

vue-cli 2.x中,就可以在專案目錄下執行指令 npm run build,此時Vue的腳手架工具會幫我們自動地對src目錄下原始碼進行打包編譯生成一個能被瀏覽器執行的程式碼,同時這個程式碼也是壓縮過後的程式碼。

打包完成後會生成一個dist資料夾,給到後端開發人員,或者直接把static資料夾裡的內容扔到後端伺服器根目錄上就OK了。這只是基本的操作,想要改變訪問路徑或怎樣的操作,就各位小夥伴自己去找了,有心自會找到~

結語

這篇文章僅是在這個專案中對於我個人而言覺得可以總結記錄下來的,更具體更詳細的知識和流程,感興趣不妨去imooc支援一下DellLee老師的這門課程~

有部分地方程式碼量太多不方便貼出來,想參考程式碼學習的可以進我Github

希望也能幫到你們~