前端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/allhttp://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:点击跳转至带参数的动态路由

前端Vue项目:旅游App-(21)detail:房屋详情页及其数据返回导航栏轮播图

vue项目使用elementUI中Tabs标签页点击切换tab-click发起网络请求数据