vue外賣專案筆記
# gshop
> A Vue.js project
## Build Setup
``` bash
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
# build for production and view the bundle analyzer report
npm run build --report
```
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
# 專案開發準備
專案描述 前後端分離的外賣專案,spa應用,專案開發模式:模組化 元件化 工程化
技術選型 vue全家桶 前後端互動ajax使用的是axios庫 自己封裝適合自己開發的ajax庫promise 介面的測試 模擬資料 stylus庫
api介面 前後臺互動介面 url 請求方式 請求引數 返回資料格式 介面一般有介面文件 postman測試介面
# 開啟專案開發
使用腳手架建立專案
安裝依賴
開發環境執行
生產環境打包釋出
# 搭建專案整體介面結構
stylus的理解和使用
結構化 變數 函式/minxin
vue-router的理解使用
$router 路由器物件,包含操作路由的功能函式,實現頁面跳轉
$route 當前路由物件,包含當前路由資訊資料的容器 path/meta/query/params
專案路由拆分
底部導航元件
導航路由元件
# 抽取元件
頭部元件 通過slot來實現元件之間的標籤通訊
商家列表元件
# 登入路由元件
靜態元件
底部導航的顯示和隱藏:通過路由的meta
# 後臺專案
啟動後臺專案 理解前後端分離
測試後臺介面 使用postman
看介面文件是否有問題
# 前後端互動
ajax請求庫 axios
封裝適合自己的請求函式 axios+promise
封裝介面請求函式
# 跨域傳送http請求是瀏覽器做的控制 解決跨域的方法
1.伺服器告訴瀏覽器允許他跨域 伺服器端開發是加上頭部允許
2.懵逼瀏覽器 配置config資料夾中index.js檔案的proxyTable然後在url上拼接上'./api'
本質上是訪問應用所在的前臺伺服器,內部存在代理轉發,也就是配置的ProxyTable 代理執行在前臺伺服器,負責跨域轉發,與伺服器進行交換資訊
# vuex是一種設計思想,目的在於管理大型app中各個元件之間資料共享,類似於全域性,他是一個vuex外掛
應用場景:大型app多個頁面之間的資料共享和管理
安裝:npm install vuex --save
在src下新建store資料夾,並在裡面新建一個index.js檔案作為管理vuex的核心模組
# 設計vuex main.js中註冊
1.index.js 向外暴露store物件,引入vuex外掛並使用vuex外掛
2.state.js 存放和向外暴露從伺服器獲取的資料,或者需要管理的資料
3.actions.js 頁面需要的執行方法 定義非同步actions 傳送ajax請求 提交commit給mutations
4.mutations.js 處理資料的核心方法
5.getters.js 存放所有計算屬性 需要由state中資料計算得到的資料
# 讀取vuex管理的資料有兩種方法
1.this.$store.state
2.在元件的計算屬性computed中...mapState(['要讀取的資料'])但是要先引入import {mapState} from 'vuex'
3.使用第二種方法讀取資料需要將其擴充套件放入計算屬性computed中,讀取使用actions中方法需要將其擴充套件放入methods
4.頁面獲取伺服器資料步驟:
0.一進入頁面就需要執行的方法或者程式碼可以在生命週期mounted中執行
1.發ajax請求 執行actions中對應的方法 使用this.$store.dispatch('')方法名 或者 mapActions
2.讀取state中資料
3.渲染到頁面
# 元件非同步顯示資料
1.在mounted中通過$store.dispatch('actionsName')非同步獲取後臺資料到state中
2.mapState(['xxx'])讀取state中的資料到元件中
3.在模板中顯示資料
# 模板中顯示的資料來源
1.data 自身所帶的data
2.props 外部傳入
3.computed 根據data props 別的compute其他計算屬性,多個計算屬性 vuex中的state getters
# 渲染輪播圖
1.需求:每8個小分類一頁,如果是17個小分類那麼第三頁就是一個,後臺返回來的資料就是直接17扔過來,因此需要對扔過來的陣列進行處理,
2.處理思路:二維陣列,數組裡面儲存陣列,最後進行巢狀遍歷
v-for="(xxx,index) in maxArr"
v-for="(yyy,index) in xxx"
3.資料渲染完成後發現輪播圖不能正常
1.產生原因:swiper在mounted生命週期就載入了,但此時資料並沒有渲染完畢,剛開始陣列是空的,後面陣列有了資料
2.解決辦法:監視陣列資料 watch + $nextTick()
# 渲染商家列表
1.主要是v-for
# svg顯示載入中 比如網速慢,資料還沒有回來,總不能讓頁面空著
1.目的是提供使用者體驗
2.使用方法,將需要替換的標籤加上v-if="判斷是否載入完資料" 同級新增一個同樣的標籤v-else
# 註冊登入
1.前臺介面功能
1.切換登入 包括手機號+簡訊驗證碼登入 手機號+密碼+圖片驗證碼
實現方法通過動態類名和一個標識當前為何種登入方式
2.手機號合法性檢查
3.簡訊驗證碼倒計時效果
4.登入密碼的顯示或隱藏
5.前臺驗證
2.後臺資料互動
1.動態一次性圖形驗證碼
2.動態一次性簡訊驗證碼
3.簡訊登入
4.密碼登入
5.獲取使用者資訊,實現自動登入
6.退出登入
# 登入成功需要把使用者資料記錄到state中userInfo{}
1.新增一個action以及對於的mutations和mutationstype
2.在登入元件相應位置執行記錄使用者資訊的actions this.$router.dispatch('recordUser',記錄的使用者資訊data)
3.然後在相應需要讀取使用者資訊的介面讀取使用者資料,比如在profile中先使用mapState引入vuex
4.渲染到頁面上 分手機號登入和使用者名稱登入
1.手機號登入就展示手機號
2.使用者名稱登入就展示使用者名稱,暫未繫結手機號
3.實現過程
<p v-if="!userInfo.phone">{{userInfo.name||"登入/註冊"}}</p>
<p><span>{{userInfo.phone||"暫未繫結手機號"}}</span></p>
4.還得修改相應的路由,之前一進來profile就是點選"登入/註冊"進入login頁面,現在已經登入成功,點選應該是進入個人詳細資訊
5.實現過程:寫一個判斷進行3目運算userInfo._id?'/userinfo':'/login' 然後繫結到路由元件的router-link 的to屬性上
6.首頁介面左上角的登入註冊也需要根據是否登入進行相應的顯示,登入了就顯示已登入圖示,未登入就顯示 登入/註冊
7.實現過程:依然是根據userInfo進行判斷,路由也進行相應的判斷切換,通過slot進行傳遞的標籤就需要改成router-link才有to屬性,直接把相應的router-link傳給子元件的slot標籤,router-link其實就是a標籤
# 登入成功後,重新整理之後資訊就不在了,不能保持登入狀態
1.保持登入狀態實現
1.登入成功後記錄user_id
2.新增獲取使用者資訊的actions並將獲取的資訊存入state
3.在App的mounted中執行獲取使用者資訊的函式
# 退出登入
1.要求:未登入前不顯示,登入後顯示,
2.實現:v-if
# vue中使用mint-ui
1.下載npm install mint-ui --save
2.下載按需打包外掛npm install --save-dev babel-plugin-component
3.修改babel配置使外掛生效,根目錄下的.babellrc檔案,在plugin配置項加入["component",[{
"libraryName":"mint-ui",
"style":true
}]]
4.mint-ui是要在全域性中使用元件外掛,因此需要去main.js中註冊
import {Button} from 'mint-ui' //按需載入
Vue.component(Button.name,Button) //對映成全域性元件
# 一次性驗證碼 圖形驗證碼為後臺生成的SVG 返回值就是一個svg圖
1.要求:圖形驗證碼有效性只有一次,點選獲取新的圖形驗證碼
2.實現方法
1.返回直接是svg圖因此直接訪問相應的網址即可獲取
2.點選切換 新增點選事件,更改事件物件e.target.src = 'http://www.baidu.com?time='+Data.now()
3.要獲取不同的驗證碼,因此每次的src必須不同,但是url是固定的,那麼可以加上一個時間引數
# 如果多個方法函式需要使用到同一個新定義的變數,但是此變數沒有在data,props,computed中,可以直接使用this.變數名,相當於把這個變數變成全域性變數
# mock模擬資料
1.下載npm install mock --save
2.建立mock資料夾,建立相應mockServer.js 引入mock和資料,寫好攔截請求的url
3.在main.js中引入
# 非同步顯示資料 資料都是先獲取後顯示 有個前後關係 沒有資料之前就顯示就會報錯
1.一般是在於多層次,比較深的資料需要有非同步獲取和展示
2.沒有資料之前可以使用v-if進行判斷是否展示相應標籤
# vue自帶動畫標籤,用於解決比較生硬的顯示和隱藏
1.將需要顯示和隱藏的內容放入<transition name="fade"><div class="test"></div></transition>
2.給test的class下級樣式加入
&.fade-enter-active,&.fade-leave-active
transition opacity 0.5s
&.fade-enter,&.fade-leave-to
opacity 0
# 店鋪頁面 當前分類和分類下商品展示相應變化
1.展示當前分類應該有一個差別與其他分類的樣式
2.當點選左側某個分類時,右側商品應該自動滑動到相應分類
3.當滑動右側商品時,到達某個分類時左側應該自動滑到相應分類
實現過程
1.當前分類通過一個類名current樣式類來區別於其他分類
2.設計一個當前分類索引用於記錄當前所在分類的計算屬性currentIndex
此計算屬性由:右側滑動的Y軸座標scrollY,滑動實時在變化,右側分類每個分類的高度tops,tops在讀取完資料就可以確定高度
實現方法
1.滑動過程中實時收集scrollY
2.列表第一次展示後收集tops
3.實現currentIndex計算邏輯
# 滑動外掛better-scroll使用 彈動效果
1.npm install better-scroll --save
2.import BScroll from 'better-scroll'
3.const bs = new BScroll('元素選擇器',{配置物件}),只需要選中需要滑動的內容的整體標籤標識
4.但是需要資料有了之後再展現,不然會報錯,先要有列表資料,然後展現
5.以往實現通過watch+$nextTick()
6.現在使用當觸發非同步獲取商品列表時
this.$store.dispatch('getShopGoods',()=>{
this.$nextTick(()=>{
new BScroll('元素選擇器')
})
})
7.BScroll的例項上有很多方法,比如繫結事件監聽on方法等,scrollY滑動多少就可以在此處計算得到
8.解決慣性滑動,scrollY並未發生改變,可以繫結scrollEnd事件,得到滾動停止時的scrollY
9.滾動到指定位置的事件scrollTo
# better-scroll頁面滾動原理:父容器固定高度或者寬度,子容器有子元素自動撐大寬高,當子容器高度大於父容器高度,自動就可以滑動
# 計算tops
1.根據每個li的高度,選取li時的技巧,為快速定位,需要給ul加一個標識ref="foodsUl" 然後選取this.$refs.foodUl.getElementsByClassName('li的類名')或者this.$refs.foodUl.children()
2.實現程式碼
const tops = []
let top = 0
const lis = this.$refs.foodUl.getElementsByClassName('li的類名')
Array.prototype.slice.call(lis).forEach(li=>{
top += li.clientHeight
tops.push(top)
})
收集完成後更新資料
this.tops = tops
# 計算當前index 根據scrollY 和 tops進行計算得到
currentIndex(){
const {scrollY,tops} = this
const index = tops.findIndex((top,index)=>{
return scrollY>=top && scrollY<=tops[index+1]
})
return index
}
# 當拿不到變數或者元件方法時,前面加上this.將其變成全域性
# 當在某個元件要更新資料時且該資料是state裡面資料,那就應該是要觸發actions呼叫
# vue對於state物件中的物件後期新增加的資料屬性是沒有資料繫結的
解決辦法
Vue.set(state中要增加屬性的物件,要增加的屬性名,屬性值)
# 面試之學習過程中遇到問題
1.對於vue中已經有資料繫結的物件想要給他新加一個屬性,雖然可以新加但是沒有資料繫結,也就是資料變化,介面不更新
2.對於先有例項建立,但是例項中所需的資料需要從後臺獲取還未產生到位,導致所建立例項並沒有相應的功能,這個就可能導致本應該有的功能沒有甚至還會報錯,解決辦法是watch+$nextTick(()=>{})
# 解決BScroll多例建立現象 目標實現單例建立
1.問題出現:當將一件商品加入購物車時,就會建立一個BScroll例項,新增多個商品就會建立多個BScroll例項,
導致點一下加號出現一次加好幾個
2.解決辦法,先判斷是否已經建立過例項
this.$nextTick(()=>{
//先判斷是否存在該例項
if(!this.scroll){
//先儲存起來
this.scroll = new BScroll('',{
click:true
})
}else{
//例項已經建立,重新統計高度看是否需要進行滾動
this.scroll.refresh() //重新整理重新統計高度
}
})
# 遇到根據條件切換不同的樣式,需要把這些樣式類名存到一個數組裡面
# 解決BScroll水平滑動時因為ul寬度小於內部多個li的寬度,導致不能水平滑動
解決辦法
動態計算ul的寬度並且修改ul的寬度
# 先點選A頁面資料會載入到位,但是B頁面會使用A頁面中的資料,如果直接在B頁面重新整理就會報錯
解決辦法:
在B頁面資料用到處加條件判斷,如果沒有資料直接return出去
# 形成列表,列表帶路由跳轉
:to="'/shop?id='+item.id"
<router-link to="{path:'shop',query:{id:item.id}}" tag="li" v-for="item in searchFoods" :key="item.id">
</router-link>
# 路由元件之前切換都是重新載入一次元件,有時候切換又不想重新載入,想要他保持之前的狀態,
解決辦法
將該組將放到<keep-alive>放入此處就可以保持狀態不會被重新載入,原理是把之前狀態快取了起來,不會進行再次載入</keep-alive>
此辦法名稱:快取路由元件物件<keep-alive></keep-alive>
# 路由元件懶載入 元件按需載入
需求:開發環境,第一次開啟應用會把所有js檔案我們寫的,第三方的都打包到一個檔案,但是我們第一次僅僅是想顯示第一個首頁,這也為了更好的使用者體驗,按需載入
解決方案:
主要是按需載入生產版本的static/js/app.js中的程式碼
按路由元件來拆,進入router資料夾處理index.js
const MSite = ()=>import('../pages/MSite/MSite.vue')
const Search = ()=>import('../pages/Search/Search.vue')
const Order = ()=>import('../pages/Order/Order.vue')
const Profile = ()=>import('../pages/Profile/Profile.vue')
因此路由配置裡面的component中的元件就是一個函式表示式,只有執行了函式表示式才會去載入路由元件
# 圖片懶載入 使用的是vue的外掛vue-lazyload
1.npm install --save vue-lazyload
可能整個專案都會使用到圖片懶載入所以在入口main.js中註冊
2.import VueLazyload from 'vue-lazyload'
3.Vue.use(VueLazyload,{配置,有個非常好的配置項,載入中顯示一個指定圖片})
4.在需要懶載入的圖片img標籤使用v-lazy替代圖片的src屬性
# 快取路由元件和路由元件懶載入是兩碼事
1.快取路由元件:是在瀏覽器記憶體將獲取的資料進行快取,不再進行傳送資料請求ajax
2.路由元件懶載入是真正的通過函式表示式進行按需載入所需要的的元件
# 頁面後退問題,回到上一個頁面
問題產生:
店鋪頁面,展示了3個子元件路由,每次切換使用的是push方法,每點一次就是新加一個視窗,
而後退是後退一個push
問題解決辦法:給router-link標籤加一個replace屬性就可以解決了
給<router-link to="/shop" replace></router-link>
# vue專案生產版本各檔案說明 共static資料夾一個和index.html檔案一個
1.static中的js資料夾
app.js 專案中我們手寫的js程式碼
mainfest.js webpack的模板檔案
vendor.js 引入的第三方庫外掛以及各個模組
# 專案使用git進行管理
#1 傳輸到git上需要忽略的資料夾,在.gitignore中配置
#2 傳輸步驟1:將本資料夾初始化為本地git倉庫git init然後git add *然後進行一次本地提交git commit -m "提交"
#3 傳輸步驟2:建立遠端倉庫會生成關聯地址然後與本地倉庫進行關聯git remote add origin https://github.com/webprevious/gshop.git然後git push origin master提交
# vue專案打包分析工具 可以看出頁面使用過的庫 打包出來是個圖片 稱為視覺化打包
npm run build --report
圖形化看出專案所用外掛或者第三方庫大小,考慮換掉大的庫,比如moment比較大,推薦替代date-fns