寫著寫著發現會寫不少內容... 全部寫在一篇文章裡感覺太多了不方便看,所以分為上下篇吧...
下篇寫完啦,感興趣的朋友可以繼續關注~ => 用Vue開發仿旅遊站webapp專案總結 (下)
溫馨提示
此文章,僅是做完專案後的個人覺得可以總結下來的操作/思路,接觸vue不久的朋友應該會有收穫。此專案也才是萌新做的第二個Vue專案,使用了腳手架工具( vue-cli 2.x 非 3 ),前輩老手們有時間看的話,有寫得不好的地方還請多多指導!~
成果預覽
僅實現專案首頁、專案詳情頁、城市列表頁元件的頁面/邏輯。
專案初始化
先用腳手架生成專案框架。
因為做的是一個移動端網頁,所以我們可以有一些配置:
第一步 配置meta標籤
index.html里加個 meta
標籤:
<meta name="viewport"content="width=device-width,initial-scale=1.0,
minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
複製程式碼
在網頁的<head>
標籤中增加以上程式碼,可以讓網頁的寬度自動適應手機螢幕的寬度。
其中:
width=device-width : 表示寬度是裝置螢幕的寬度
initial-scale=1.0 : 表示初始的縮放比例
minimum-scale=1.0 : 表示最小的縮放比例
maximum-scale=1.0 : 表示最大的縮放比例
user-scalable=no : 表示使用者是否可以調整縮放比例
以上我設定的引數的目的是:想要一開啟網頁,就自動以原始比例顯示,並且不允許使用者修改,不允許使用者縮放。
第二步 初始化預設樣式
在不同的手機瀏覽器上,預設的一些樣式是不同統一的。我們需要把這些不同手機的初始化樣式做一個統一。
所以可以引入個 reset.css
這是一個初始化的程式碼,其中一些初始化配置可以自行根據需求修改。
想看/拿程式碼的可以到我Github上拿:src/assets/styles/reset.css
第三步 解決1畫素邊框方案
在移動端頁面開發,常常有個 1畫素邊框 的問題。
也就是有的手機螢幕解析度比較高,如果我們在頁面上寫border-bottom啥的樣式,會導致這些手機螢幕解析度高的當中,1px邊框顯示成2px邊框或3px邊框等顯示成多畫素。
為了解決這個1畫素邊框問題,我們就引入了 border.css(貌似這是哪個團隊提出的解決方案?忘記啦,只知道怎麼用...但仍然要表示感謝。還有其他解決方案,這個就自行搜尋了。)
兩百多行不貼出來了,想看/拿完整程式碼的可以到我Github上:src/assets/styles/border.css
具體這個解決方案的用法,看過border.css程式碼的同志就會發現很簡單:在元素上根據想要的需求加以下這些類名。
按照字面意思理解就行。
比如要給一個元素加上一畫素的下邊框,就直接加個類名:<div class="border-bottom>"
就行了。
要給一個元素加上一畫素的上邊框和下邊框,就直接加類名:<div class="border-topbottom">
就行了。
邊框也可以改顏色的,舉個專案中的例子,按照這種格式去改顏色(本文例子有css程式碼的話基本都是stylus的寫法):
對應頁面:
第四步 引入fastclick庫
在移動端開發中,某些機型、某些瀏覽器上,click點選事件要延遲300ms執行。
要解決這個問題,我們引入個fastclick庫
npm install fastclick --save
--save的意思是:不管在開發環境測試,還是線上跑程式碼,安裝了的庫都可以使用。並且下載好後,自動存到package.json的dependencies屬性中,比如這裡install的fastclick:
然後在入口函式main.js中引入和使用:
import fastClick from 'fastclick'
、
fastClick.attach(document.body)
第五步 配置使用iconfont
先在阿里巴巴向量圖示庫建立一個專案
然後在iconfont上選購,新增到購物車,選好後新增到自己的專案,然後下載到本地。
下載的東西中只要用到這幾個:
然後把iconfont.css放到一個資料夾中並且在入口函式main.js處引入後就可以全域性使用了。
舉個使用的例子:
注意類名要加iconfont,然後這裡在span裡輸入的程式碼就是你選中的圖示的程式碼:
第六步 自定義目錄
這步其實應該穿插在做專案過程中進行的,這裡先列出來。
在build資料夾下的webpack.base.conf.js中配置,如下圖,圈起來的是我在專案中配置的。
這樣有配置後就可以使用自定義目錄了。比如按照我上面的配置的話
import src/assets/styles/border.css
就可以寫成
import styles/border.css
了。
首頁開發中想記錄下來的
輪播外掛
安裝與使用
這裡使用的是 vue-awesome-swiper。
先安裝: npm install vue-awesome-swiper --save
然後用法一些的其實都可以在其文件中查閱到:
然後使用:
比如要使用按鈕區的話,就需要配置引數。根據個人在專案中的需求,可以查閱其github文件按需使用。
這裡值得一提的是:假如在輪播圖的下面有東西
比如這個test。在網速慢慢載入的時候,可能test會先在上面顯示,然後等圖片撐開區域的時候再跑回下面。
為了防止這種抖動,最好這樣子做:
給輪播swiper外面套一層類為wrapper的div,然後給div固定大小。比如在專案中這裡的輪播圖片的寬高比是 364:97 約等於 3.75,高度是寬度的百分之 26.6。
所以響應式開發可以這樣給div框樣式:
現在vw單位的相容性其實可以了。有種相容性很好的方案:
overflow: hidden
width: 100%
height: 0
padding-bottom: 26.6%
複製程式碼
這種方式也是高度是寬度的 26.6%。
其實吧。。這個vue-aowsome-swiper元件目前為止已經不存在這種抖動問題了。。
還有個改變外掛預設顏色的問題
比如外掛按鈕區配置後,預設按鈕顏色是藍色小圓點。
審查元素可以看出:
那我們如下這樣子加樣式去改變行嗎?
一般這樣子問都是不行滴...
因為有scoped作用域的原因,這個類的屬性的設定是在原本的 swiper元件下,而不是在我們這裡設定的swiper元件下。
應該這樣設定:
意思是在.wrapper下的所有類中,找.swiper-pagination-bullet-active類。
>>>
是具有穿透作用域的意思,穿透其他元件的作用域。
如果文字在一行中多了,實現省略號效果
比如,這裡是個p標籤。
P標籤裡的資料太多的話 希望顯示一個 ... 省略號。
可以這樣利用text-overflow屬性:
要實現溢位時產生省略號的效果,應該在定義兩個樣式:強制文字在一行內顯示(white-space:nowrap)和溢位內容為隱藏(overflow:hidden),只有這樣才能實現溢位文字顯示為省略號效果。
傳送ajax請求
一般情況下在mounted鉤子裡傳送ajax請求資料。想詳細瞭解生命週期 => 我有寫過一篇文章
請求方式,看自己,這個專案中axios、fetch兩個方式我都寫過。
配置
首先,用vue腳手架工具生成的工程裡面,只有static目錄(靜態檔案目錄)下,才能被外界訪問到。
我們就把本地的一些模擬資料放在這個static目錄下,自己建個資料夾儲存資料。這個專案中是static/mock/index.json:
這資料是本地的模擬資料,我們不希望到時候一起把它push到線上,可以在.gitignore裡這樣配置:
現在這個資料夾下的所有東西都不會被傳到線上了。
當然,也不會提交到本地的git倉庫裡面。
這樣配置還不夠,目前在區域性根元件中寫的請求的路徑是這樣的,拿專案中舉例:
當我們上線這程式碼的時候,我們請求的網址,最好前面加上個‘api’,如下面的紅框中:/api/index.json 這樣子最好了。
很好的是,恰好Vue腳手架裡面有這樣一個轉發的代理功能。通過這個功能,就可以實現以上構想。
config配置檔案下,有個 index.js 指令碼,官方給我們提供了一個 proxyTable{} 的配置項,我們可以這樣配置:
這意思是:當我們請求api的時候,依然對映到本地8080埠,然後訪問任何以api為開頭的url的時候,做一個路徑替換,代理訪問到 /static/mock 處。
實際這功能 是webpack-dev-sever提供的。
改過配置檔案,需要重啟下伺服器,重啟後就可以如下請求資料了:
這裡實際上訪問的就是static/mock/index.json裡的內容了。
優化
如果可以的話,最好能在區域性根元件裡請求一次ajax資料,然後從區域性根元件裡把接收到的資料分別傳給各個區域性的子元件,而不是每個區域性的子元件都傳送一次ajax請求。
城市列表頁開發中想記錄下來的
記box-sizing:border-box的一個應用場景
這裡是這樣寫的css
現在在輸入框裡面輸入文字字元超過輸入框大小時:
這兩部會貼著,不那麼好看。想要給這個輸入框加個padding,留點間隙會更好。
但直接在input下面加行嗎?
頁面:
因為包裹input框的div沒設定width,也就是width是auto。input框的width設定的是100%。
如果直接給input加padding左右一點的話是會撐開input框的寬度的。所以會溢位。
那怎樣解決這個問題呢?
我們只是想設定一個左右padding值,沒想讓input框長寬變化。所以,我們在 Input 下面加個:box-sizing: border-box
這樣的話,我們直接給input設定的寬高就包括了padding、border在內的寬高了。
此時我們要修改padding的值的話,就只會在這個框內變化 不會撐開框寬高了。
在列表欄用第三方外掛 better-scroll
初始開發頁面時,到這步,因為加了比較多字母對應的區域,頁面出現了滾動條的時候:
為了使用better-scroll庫,我們僅讓列表區域顯示到剛進頁面時能顯示到的區域就行了,不需要出現滾動條。所以可以給最外層的包裹整個列表區域的框div.list 加個overflow: hidden
就行了。(整個列表頁指下圖中的從當前城市開始到最後,城市選擇和輸入框是其他子元件寫的了)
接下來具體better-scroll的用法,github上其文件有說明,各人可根據具體情況查閱使用。
字母表的邏輯實現思路
點選事件中,我們需要檢視點選的內容時,可以利用點選事件的事件物件
在Vue的一個點選事件裡,在methods定義點選方法時這個方法可以接收一個引數e,e就是我們點選到的那個事件物件。
要拿到我們點選到的事件物件的內容 可以這樣來:e.target.innerText
舉個專案中的例子驗證一下:
比如此時頁面上點選了 D F J
需求1
當點選到相應的字母的時候顯示list元件的對應城市的區域。
better-scroll這個第三方外掛有個方法可以實現這個需求,思路是:
監聽所點選的字母表裡字母的值letter的變化,一旦letter變了,就利用better-scroll的提供的一個介面,如下圖劃線的部分
它會讓better-scroll的滾動區域,自動滾動到某一個元素上。需要給這個方法傳遞我們滾動到該元素的該元素DOM。利用這個思路就可以實現需求1了。
需求2
手指拖動字母表,字母對應的列表跟著聯動展示。
思路:
利用touchstart、touchmove、touchend事件,並給個限制(touchStatus) 只當手指在螢幕移動的時候才執行一些操作。然後用個陣列letters來存放字母表的所有字母,這裡的letters大概是['A','B','C'...],並讓頁面v-for這個letters來顯示相應的內容。用陣列存放這些字母的原因也是為了實現這需求的主要思想:根據下標,找到對應的字母。
接下來,先用offsetTop找到字母表中字母A距離包裹它的頂部的高度。下圖紅框。
這裡的74 代表的是紅色方框的高度。
然後獲取移動時手指所在的高度,此高度時針對於客戶端的高度,用clientY。 touchmove事件有個事件物件,事件物件裡有個touches陣列,touches[0]裡面就有當前手指的資訊,包括clientY屬性。
實時獲取我們手指的位置。
我們要獲取距離包裹塊的高度 => 也就是clientY的高度要減去headers區和serach區的高度,這兩個區高度是 79px。
然後算我們手指移到的字母在陣列中的下標 邏輯是 (touchY - startY)/每個字母的高度,再把結果向下取個整。
最後,把這個下標在letters陣列中對應的字母傳給需求1所在的元件利用需求1的思路就行了。(這裡的傳值涉及到了兄弟元件之間的傳值,此時該頁面比較簡單不建議用vuex,可以用event bus/找同一父元件做媒介傳值,具體方法百度。)
在我專案中最終邏輯程式碼是這樣寫的:
最後做個最佳實踐,用個if,確保 index的值。
效能優化
第一處
handleTouchMove是手指滑動的時候就會執行,而我們框起來的也就是A字母距離包裹框的高度是固定的,不用每次滑動的都執行這段程式碼。所以此處需要優化,這樣子來:
在data裡初始化startY為0
然後用生命週期鉤子 updated 去執行給startY賦值的語句
這裡為什麼用updated這個鉤子呢?在專案中初次渲染字母表元件alphabet.vue的時候,從它父元件City.vue傳過來的值是一個空物件。當City.vue裡ajax動態獲取資料後,從City再傳到alphabet的值讓資料從初次的空物件發生改變。在資料更新完畢後,就觸發了updated鉤子,此時給startY賦值就是值都有,而且只會賦一次。
第二處:函式節流
通過函式節流 減少handleTouchMove()的執行頻率 (因為我們手指在滑動的時候 該函式執行頻率很高的)。
怎樣使得函式節流呢?
通過定時器和清除定時器來實現。
先在data中初始化timer為 null,然後這樣來用
這樣子用定時器進行函式節流的話 :
如果已經正在做這件事情的時候,我呢,讓它延遲16ms之後再去執行。假設在這16ms之間你又去做了手指的滾動,那麼它會把上一次你要做的操作給清除掉(clearTimeout),然後重新執行你這次要做的事情 (等於以最終的手指滑動的位置為準 )。
通過這種函式節流方式,會大大減少該函式的執行次數,從而提高網頁效能。
函式節流的方式,當一個函式執行次數很多想要減少而且減少也沒影響的時候,是很有必要採用的一種方式。
localStorage
可能使用者會有不小的概率關閉了本地自動儲存的功能,一般我們使用localStorage的時候 都要使用 try catch 程式碼塊,這樣就算使用者關閉本地自動儲存功能,也不會讓整個程式碼都不能執行,只是沒了這個localStorage的功能而已。
舉個專案中的例子: