前端Vue项目:旅游App-city:标签页Tabs动态数据:网络请求axios与request数据管理store与pinia各种封装
Posted karshey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端Vue项目:旅游App-city:标签页Tabs动态数据:网络请求axios与request数据管理store与pinia各种封装相关的知识,希望对你有一定的参考价值。
文章目录
目标
上一篇搭建了搜索框和Tab栏:【前端】Vue项目:旅游App-(7)city:搜索框search和标签页Tabs
本篇目标:
样式不变:
数据改为动态的:
数据从服务器获取:
http://123.207.32.32:1888/api/city/all或http://www.codercba.com:1888/api/city/all
注意将网络请求request和数据管理pinia 封装。
过程与代码
安装相关库
本篇要将网络请求到的数据进行处理,要用到pinia
:
npm install pinia
本篇使用的网络请求库:axios
:
npm install axios
封装网络请求相关代码
相关参考:coderwhy ts封装axios库 除去冗余代码 可直接使用 - 掘金 (juejin.cn)
service文件夹用来提供封装好的各种服务。我们在其中建立一个文件夹request,表示用来提供网络请求服务。
其中的index.js文件:封装好的axios网络请求。
import axios from "axios";
import useLoadingStore from "@/store/modules/loading";
import baseURL, TIMEOUT from "./config";
const loadingStore = useLoadingStore();
class HYRequest
constructor(baseURL)
this.instance = axios.create(
baseURL,
timeout: TIMEOUT,
);
request(config)
loadingStore.changeLoading(true);
return new Promise((resolve, reject) =>
this.instance
.request(config)
.then((res) =>
resolve(res.data);
)
.catch((err) =>
console.log("request err:", err);
reject(err);
)
.finally(() =>
loadingStore.changeLoading(false);
);
);
get(config)
return this.request( ...config, method: "get" );
post(config)
return this.request( ...config, method: "post" );
export default new HYRequest(baseURL);
其中的config.js用来封装网络请求相关的配置:
const baseURL = "http://123.207.32.32:1888/api";
const TIMEOUT = 5000;
export baseURL, TIMEOUT ;
注意,index.js代码中还有一个useLoadingStore的导入。
store中新建modules文件夹,里面的loading.js文件:
import defineStore from "pinia";
export const useLoadingStore = defineStore("loadingStore",
state: () =>
return
showLoading: false,
;
,
getters:
isLoading: (state) => state.showLoading,
,
actions:
changeLoading(isLoading)
this.showLoading = !!isLoading;
,
toggleLoading()
this.showLoading = isLoading;
,
,
);
网络请求数据
我们用封装好的网络请求库来请求数据。
注意:
- request中的index导出的是一个对象(
new HYRequest()
) - HYRequest.get的参数是对象(
...config
)
代码:
import HYRequest from '@/service/request'
function getAllCity()
// request的index导出的是一个对象
return HYRequest.get(
// 参数也是一个对象
url:'/city/all'
).then(res =>
console.log(res)
)
getAllCity()
效果:
得到了数据。观察一下数据,可知:获取到的数据是一个对象,里面的data属性是我们页面需要的数据。
data中有两个属性,分别对应两个tab的数据。
网络请求数据操作封装
请求到数据之后,我们要进行一些思考。
city.vue写的是显示和选择城市的页面,我们在这个页面里写“网络请求数据”的逻辑是否合适?是否利于维护?答案是否定的。
实际上,我们可以将city页面的所有网络请求的操作都写到一个文件里,city.vue只需要在需要数据时调用即可。简而言之,我们需要对city页面的所有网络请求操作进行封装。
我们在service文件夹中建立modules文件夹,所有页面的网络请求操作都放在这里。modules中建立city.js,所有city相关的网络请求操作都放在这里。
代码:
// 此文件保存所有city页面的网络请求
import HYRequest from '@/service/request'
export default function getAllCity()
// request的index导出的是一个对象
return HYRequest.get(
// 参数也是一个对象
url: '/city/all'
)
city.vue:
import getAllCity from '@/service/modules/city'
getAllCity()
接下来我们再进行一些思考。
我们在city中只需要导入就可以得到数据了。但是,显然city不会只有一次网络请求数据。也就是说,每次网络请求都需要import一次,这样也会让city.vue代码变得复杂。更重要的是,这些import是相似的,我们可以把它们也封装起来。
我们在service文件夹下新建index.js,里面保存所有会被使用的service:导出所有导入的模块。
// 此文件导入并导出所有要使用的service
export * from '@/service/modules/city'
在city.vue中调用:
import getAllCity from "@/service";
getAllCity()
效果:
pinia管理数据并封装
接下来我们再进行一些思考。
我们已经把所有的网络请求都封装了,在vue页面只需要调用网络请求获取数据使用就行了。但是,我们获取到的数据是一个对象,对象中的data才是我们需要的数据。
思考:在vue的页面中进行处理数据的逻辑是否合适?是否利于维护?
答案是否定的。显然,我们既然已经完成了网络请求的封装,自然也会想到要完成数据处理和存储的封装。
预想:我们把请求到的数据和对数据的处理封装到一个文件里,把处理好的数据导出。在vue的页面中只需要直接使用处理好的数据即可。
这里就要用到pinia。
在store的modules中新建city.js,city.vue页面所有的进行网络请求和数据都封装到这里。
// city.vue页面所有的进行网络请求和数据都封装到这里
import getAllCity from "@/service";
import defineStore from "pinia";
const useCityStore = defineStore('city',
state: () =>
return
allCity:
,
actions:
// 调用网络请求
async fetchAllCity()
const res = await getAllCity()
this.allCity = res.data
)
export default useCityStore
在vue中:
const cityStore=useCityStore()
cityStore.fetchAllCity()
// cityStore是响应式的
const allCity = storeToRefs(cityStore)
console.log(allCity)
效果:
tab栏改为动态数据
tab栏改为动态数据后,若服务器那边的数据发生了改变(如data有了三个属性),我们这里的代码是不用改的。
<van-tabs v-model:active="TabActive">
<template v-for="(value, key, index) in allCity">
<van-tab :title="value.title"></van-tab>
</template>
</van-tabs>
效果
不变。
本篇总结
本篇写了很多的封装,这里对它们之间的关系进行总结。
city.vue需要的数据都存在store中。
store会进行网络请求得到数据,网络请求的代码在service。
本项目views文件夹中所有页面需要的数据都在store的modules中,store的modules所有存储的数据来源都是网络请求得到的。所有的views页面的网络请求都存在service的modules中,store只需调用就可以得到数据。
service中的request是封装axios库。
总代码
修改或新建的文件
service
存放各种网络请求。
index
把要用的所有service导入并导出。
// 此文件导入并导出所有要使用的service
export * from '@/service/modules/city'
modules的city
封装city页面的所有网络请求。
// 此文件保存所有city页面的网络请求
import HYRequest from '@/service/request'
export function getAllCity()
// request的index导出的是一个对象
return HYRequest.get(
// 参数也是一个对象
url: '/city/all'
)
request的config
封装网络请求相关配置。
const baseURL = "http://123.207.32.32:1888/api";
const TIMEOUT = 5000;
export baseURL, TIMEOUT ;
request的index
封装axios。
import axios from "axios";
import useLoadingStore from "@/store/modules/loading";
import baseURL, TIMEOUT from "./config";
const loadingStore = useLoadingStore();
class HYRequest
constructor(baseURL)
this.instance = axios.create(
baseURL,
timeout: TIMEOUT,
);
request(config)
loadingStore.changeLoading(true);
return new Promise((resolve, reject) =>
this.instance
.request(config)
.then((res) =>
resolve(res.data);
)
.catch((err) =>
console.log("request err:", err);
reject(err);
)
.finally(() =>
loadingStore.changeLoading(false);
);
);
get(config)
return this.request( ...config, method: "get" );
post(config)
return this.request( ...config, method: "post" );
export default new HYRequest(baseURL);
store
封装pinia。
modules的city
city页面的所有数据。
// city.vue页面所有的进行网络请求和数据都封装到这里
import getAllCity from "@/service";
import defineStore from "pinia";
const useCityStore = defineStore('city',
state: () =>
return
allCity:
,
actions:
// 调用网络请求
async fetchAllCity()
const res = await getAllCity()
this.allCity = res.data
)
export default useCityStore
modules的loading
封装网络请求需要的模块。
import defineStore from "pinia";
export const useLoadingStore = defineStore("loadingStore",
state: () =>
return
showLoading: false,
;
,
getters:
isLoading: (state) => state.showLoading,
,
actions:
changeLoading(isLoading)
this.showLoading = !!isLoading;
,
toggleLoading()
this.showLoading = isLoading;
,
,
);
city.vue
将tab的数据改为动态的。
<template>
<div class="city top-page">
<!-- show-action:显示 “取消” -->
<van-search shape="round" v-model="value" show-action placeholder="城市/区域/位置" @search="onSearch"
@cancel="onCancel" />
<van-tabs v-model:active="TabActive">
<template v-for="(value, key, index) in allCity">
<van-tab :title="value.title"></van-tab>
</template>
</van-tabs>
</div>
</template>
<script setup>
import ref from 'vue';
import showToast from 'vant';
import useCityStore from '@/store/modules/city'
import storeToRefs from 'pinia';
const value = ref('');
const TabActive = ref(0);
const onSearch = (val) => showToast(val);
const onCancel = () =>
showToast('取消');
// tabs的数据
const cityStore = useCityStore()
cityStore.fetchAllCity()
// cityStore是响应式的
const allCity = storeToRefs(cityStore)
</script>
<style lang="less" scoped>
</style>
参考
Cannot read properties ofundefined(reading‘data‘)
coderwhy ts封装axios库 除去冗余代码 可直接使用 - 掘金 (juejin.cn)
以上是关于前端Vue项目:旅游App-city:标签页Tabs动态数据:网络请求axios与request数据管理store与pinia各种封装的主要内容,如果未能解决你的问题,请参考以下文章
前端Vue项目:旅游App-city:搜索框search和标签页Tabs
前端Vue项目:旅游App-city:隐藏TabBar的2种方法
前端Vue项目:旅游App-(10)city:以indexBar的形式显示数据
前端Vue项目:旅游App-(20)home:点击跳转至带参数的动态路由