書到用時方恨少
這個階段涉及到了vuex,本來想著不慌,用起來,使用的過程中問題還真不少
本篇涉及到的內(nèi)容:
---postman 測試數(shù)據(jù)
---封裝 ajax 請求函數(shù)
---封裝接口請求函數(shù)
---使用 vuex 管理狀態(tài)
---獲取首頁相關(guān)數(shù)據(jù)
0. 其它
vue實戰(zhàn)(1):準備與資料整理
vue實戰(zhàn)(2):初始化項目、搭建底部導航路由
vue實戰(zhàn)(3):底部導航顯示、搭建各模塊靜態(tài)頁面、添加登錄頁頁面與路由
vue實戰(zhàn)(4):postman測試數(shù)據(jù)、封裝ajax、使用vuex管理狀態(tài)
vue實戰(zhàn)(5):總結(jié)一
vue實戰(zhàn)(6):異步顯示數(shù)據(jù)、開發(fā)Star組件
vue實戰(zhàn)(7):完整開發(fā)登錄頁面(一)
vue實戰(zhàn)(8):完整開發(fā)登錄頁面(二)
vue實戰(zhàn)(9):總結(jié)二
vue實戰(zhàn)(10):開發(fā)店鋪詳情(一)
vue實戰(zhàn)(11):開發(fā)店鋪詳情(二)
vue實戰(zhàn)(12):完結(jié) + 附學習視頻
1. 安裝 MongoDB ,啟動后臺
- 這個小練習項目是一個前后臺分離的項目,后臺應用負責處理前臺應用提交的請求, 并給前臺應用返回 json 數(shù)據(jù),前臺應用負責展現(xiàn)數(shù)據(jù), 與用戶交互, 與后臺應用交互。
- 后臺應用是用
nodejs寫的,數(shù)據(jù)庫需要用到mongodb - 暫時不會
nodejs和mongodb,不過沒關(guān)系,照著文檔先用起來,問題不大。 - MongoDB 官方網(wǎng)站鏈接 和 教程與安裝鏈接
- 后臺應用是用
1.1 到MongoDB官網(wǎng),下載適合的版本,安裝好
1.2 到后臺項目文件夾下,cmd,用npm start啟動數(shù)據(jù)庫

2. 使用 postman 測試數(shù)據(jù)
- 數(shù)據(jù)庫打開以后,進一步去測試是否打開成功,是否能取到數(shù)據(jù),這里就要用到接口測試工具 postman
- postman 可以獲取數(shù)據(jù)、可以檢測API文檔中的接口是否有問題
- 項目重點也不在這里,可以去 postman 官方網(wǎng)站鏈接 下載客戶端 和 很厲害的教程鏈接
- 查看API接口文檔
1.1 根據(jù)經(jīng)緯度獲取位置詳情(例子)
--請求URL:http://localhost:3000/position/:geohash
--示例:http://localhost:3000/position/40.10038,116.36867
--請求方式:GET
--參數(shù)類型:param
|參數(shù) |是否必選 |類型 |說明
|geohash |Y |string |經(jīng)緯度
--返回示例:
{
"code": 0,
"data": {
"address": "北京市昌平區(qū)337省道",
"city": "北京市",
"geohash": "40.10038,116.36867",
"latitude": "40.10038",
"longitude": "116.36867",
"name": "昌平區(qū)北七家宏??萍紙@(337省道北)"
}
}
1.2 接口輸入postman中,查看結(jié)果
1.3 輸出與文檔相同,獲取數(shù)據(jù)成功

3. 封裝 ajax 請求函數(shù)
- 這里的異步交互使用的是
axios,需要在項目中添加依賴npm install --save axios - 這里的封裝非常重要,雖然代碼不是很難懂,但是感覺是 知其然而不知其所以然 ,這也是貫徹了模塊化開發(fā)的思想,還是先用起來,會熟能生巧的。
- 在 api 文件夾下創(chuàng)建 ajax.js ,引入
axios:import axios from 'axios'
- 在 api 文件夾下創(chuàng)建 ajax.js ,引入
import axios from 'axios'
/*
ajax請求模塊
封裝ajax請求函數(shù)
*/
export default function ajax (url = '', data = {}, type = 'GET') { // type 默認傳 get
return new Promise(function (resolve, reject) { // 返回 new promise,后面會用到 async 和 await
let promise
if (type === 'GET') { // 判斷 get
let dataStr = '' // 數(shù)據(jù)拼接字符串
Object.keys(data).forEach(key => {
dataStr += key + '=' + data[key] + '&'
})
if (dataStr !== '') { // 拼接成 url 地址
dataStr = dataStr.substring(0, dataStr.lastIndexOf('&'))
url = url + '?' + dataStr
}
// 發(fā)送get請求
promise = axios.get(url)
} else {
// 發(fā)送post請求
promise = axios.post(url)
}
promise.then(response => {
resolve(response.data)
})
.catch(error => {
reject(error)
})
})
}
4. 封裝接口請求函數(shù)
-
ajax 請求封裝完成之后,就是開始封裝各個接口請求函數(shù)
- 在 api 文件夾下創(chuàng)建 index.js ,引入
ajax:import ajax from './ajax'
- 在 api 文件夾下創(chuàng)建 index.js ,引入
- 這個就好理解的多,根據(jù)項目需求的不同,需要的接口會非常的多,這樣做也是模塊化的體現(xiàn),便于管理和維護
/* 包含多個模塊ajax函數(shù)
* 封裝接口請求函數(shù)(一部分例子)
* */
import ajax from './ajax'
const BASE_URL = '/api' // 關(guān)于跨域
// 1、根據(jù)經(jīng)緯度獲取位置詳情
// 此處直接這么寫,當請求時會出錯,因為后臺代碼的端口是4000(或域名),與本地的請求端口不一致,自然無法實現(xiàn)跨域ajax請求,需要代理配置
// export const reqAddress = (geohash) => ajax(`/position/${geohash}`)
export const reqAddress = (geohash) => ajax(`${BASE_URL}/position/${geohash}`)
// 2、獲取食品分類列表
export const reqCategorys = () => ajax(`${BASE_URL}/index_category`)
// 3、根據(jù)經(jīng)緯度獲取商鋪列表
export const reqShops = (latitude, longitude) => ajax(`${BASE_URL}/shops`, { latitude, longitude })
- 此處涉及到跨域的問題,需要進行一些配置
- 因為本項目使用
vue-cli3腳手架搭建,沒有現(xiàn)成的配置文件,現(xiàn)在需要在根目錄下創(chuàng)建vue.config.js,查了一些資料,有點雜而且比較落后,其中一些參數(shù)已經(jīng)被棄用了,配置了一個簡潔的,其它配置可以看 官方文檔
- 因為本項目使用
// vue.config.js
module.exports = {
// 修改的配置
publicPath: '/',
devServer: {
proxy: {
'/api': { // 匹配所有以 '/api'開頭的請求路徑
target: 'http://localhost:4000', // 代理目標的基礎(chǔ)路徑
changeOrigin: true, // 支持跨域
// ws: true,
pathRewrite: { // 重寫路徑: 去掉路徑中開頭的'/api'
'^/api': ''
}
}
}
}
}
- 配置完成,測試一下是否能夠取到數(shù)據(jù),可以在
App.vue中引入import { reqCategorys } from './api',添加mounted方法
async mounted () { // 例子
const result = await reqCategorys()
console.log(result) // 打印輸出
}

5. 創(chuàng)建 vuex 整體結(jié)構(gòu),管理狀態(tài)
關(guān)于vuex的學習,起初不是怎么會用,看了官方文檔也沒怎么懂,看了幾篇博客知道了一些使用方法,視頻中對這部分的構(gòu)建還是去年的形式,我照著現(xiàn)在的形式搭建了一下,因為只知其一不知其二,這也造成一些問題,好在目前遇到的問題都解決了,問題不大,后面還需要繼續(xù)深入學習。
modules文件夾里面放模塊,更便于管理與維護
- 首先是下載依賴,并且在
main.js中配置好import store from './store/store',并且在store.js中引用import Vuex from 'vuex'和使用Vue.use(Vuex)- 如果在創(chuàng)建項目時已經(jīng)配置好 vuex ,則無需在
main.js中配置,已經(jīng)是配置好的了
- 如果在創(chuàng)建項目時已經(jīng)配置好 vuex ,則無需在
// vuex最核心的管理對象store
import Vue from 'vue'
import Vuex from 'vuex'
// 引用模塊
import msite from './modules/msite'
import getters from './getters'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
msite // modules文件夾中的msite模塊
},
getters
})
- 模塊的編寫(例子)
// 內(nèi)容比較多,這邊可以把相似或者功能相同的組成一個模塊,更方便維護
// 模塊文件在store.js中引用
import { // 引用封裝好的接口
reqAddress,
reqCategorys,
reqShops
} from '../../api/index'
// 基礎(chǔ)數(shù)據(jù)狀態(tài),現(xiàn)在在任何文件都可以引用,引用時 this.$store.xxx 即可
const state = {
latitude: 40.10038, // 緯度
longitude: 116.36867, // 經(jīng)度
address: {}, // 地址信息對象
categorys: [], // 分類數(shù)組
shops: [] // 商家數(shù)組
}
// 直接更改state的多個方法的對象,現(xiàn)在在任何文件都可以引用,引用時 this.$store.commit('xxxx')即可
const mutations = {
RECEIVE_ADDRESS: (state, { address }) => { // 接受地址
state.address = address
},
RECEIVE_REQCATEGORYS: (state, { categorys }) => { // 接受食品分類數(shù)組
state.categorys = categorys
},
RECEIVE_REQSHOPS: (state, { shops }) => { // 接受商家數(shù)組
state.shops = shops
}
}
// 與后臺交互的數(shù)據(jù),現(xiàn)在在任何文件都可以引用,引用時 this.$store.dispatch('xxxx')即可
const actions = {
// 異步獲取地址
async getAddress ({ commit, state }) {
// 發(fā)送ajax異步請求
const geohash = state.latitude + ',' + state.longitude
const result = await reqAddress(geohash)
// 提交一個mutations
if (result.code === 0) {
commit('RECEIVE_ADDRESS', { address: result.data })
}
},
// 異步獲取分類列表
async getCategorys ({ commit }) {
const result = await reqCategorys()
if (result.code === 0) {
commit('RECEIVE_REQCATEGORYS', { categorys: result.data })
}
},
// 異步獲取商家列表
async getShops ({ commit, state }) {
const { latitude, longitude } = state
const result = await reqShops({ latitude, longitude })
if (result.code === 0) {
commit('RECEIVE_REQSHOPS', { shops: result.data })
}
}
}
export default { // 把方法暴露出去
namespaced: true,
state,
mutations,
actions
}
-
vuex 構(gòu)建好,下面是使用測試,在需要的地方使用
- 這里還涉及到了 vuex 的輔助函數(shù),
mapState、mapMutations、mapAction,vuex最簡單、最詳細的入門文檔,這篇文章寫的非常好,具體的就不展開了,直接使用起來,問題不大。 - 首先在
App.vue中引入import { mapActions } from 'vuex',使用需要的方法
- 這里還涉及到了 vuex 的輔助函數(shù),
<script>
import FooterGuide from './components/FooterGuide/FooterGuide'
import { mapActions } from 'vuex'
export default {
name: 'App',
mounted () {
// this.$store.dispatch('msite/getAddress')
this.getAddress() // 這邊調(diào)用的方法,在瀏覽器的插件中會有一個非常清楚的展示
},
methods: {
...mapActions('msite', ['getAddress'])
},
components: {
FooterGuide
}
}
</script>

- 現(xiàn)在我們需要其中的 name 屬性數(shù)據(jù),在
Msite.vue中引用import { mapState } from 'vuex',添加 computed 方法:computed: { ...mapState('msite', ['address'])},然后就可以愉快的使用了
<!--首頁頭部-->
<!--此處title使用強制綁定,取出 address 中的 name-->
<HeaderTop :title = "address.name">
<router-link class="header_search" slot="left" to="">
<i class="iconfont iconfangdajing"></i>
</router-link>
<router-link class="header_login" slot="right" to="">
<span class="header_login_text">登錄|注冊</span>
</router-link>
</HeaderTop>


- 遇到一個 大坑
vuex 使用 ...mapState 獲取到 undefined,這是我遇到的一個坑,這篇文章正好解決了我的問題。
6. 結(jié)束
感覺這個部分是最難的部分了,還是不熟悉的原因,下面都是邏輯處理方面的內(nèi)容了

