【前端】Vue项目:旅游App-(8)city:标签页Tabs动态数据:网络请求axios与request、数据管理store与pinia、各种封装

news2024/11/25 10:33:59

文章目录

    • 目标
    • 过程与代码
      • 安装相关库
      • 封装网络请求相关代码
      • 网络请求数据
      • 网络请求数据操作封装
      • pinia管理数据并封装
      • tab栏改为动态数据
    • 效果
    • 本篇总结
    • 总代码
      • 修改或新建的文件
      • service
        • index
        • modules的city
        • request的config
        • request的index
      • store
        • modules的city
        • modules的loading
      • city.vue
    • 参考

目标

上一篇搭建了搜索框和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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/143939.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

录屏没有声音怎么办?录屏怎么录声音

相信部分朋友在录制视频时&#xff0c;有出现录制视频没有声音&#xff0c;导致该段视频没有声音而无法播放。录屏怎么录声音&#xff1f;可以使用支持录制声音的专业的电脑录屏软件。今天小编就在这给大家分享在录制视频同时&#xff0c;将声音也录制进去的操作步骤。一、录屏…

【Linux】主函数的三个形参

主函数的形参有三个&#xff1a;argc参数个数&#xff0c;argv参数内容&#xff0c;envp环境变量。其中argc是整型&#xff0c;argv和envp是指针数组&#xff08;存的字符串&#xff09; argv源于我们自己在使用执行命令时传的内容&#xff0c;envp源于程序的父进程&#xff08…

力扣sql入门篇(十)

力扣sql入门篇(十) 1 查找重复的电子邮箱 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT Email FROM Person GROUP BY Email HAVING count(id)>21.3 运行截图 2 合作过至少三次的演员和导演 2.1 题目内容 2.1.1 基本题目信息 2.1.2 示例…

Java并发编程(六)ExecutorService

ExecutorService invokeAny() he invokeAll() 具有阻塞特性 invokeAny invokeAny 的作用是取得第一个完成任务的结果的值。 如果线程中增加 if (!Thread.currentThread().isInterrupted()) 判断&#xff0c;则会中断这些线程。 其他线程如果抛出 InterruptedException() 异常&a…

从徘徊迷茫到行业精英,社科院与杜兰大学金融管理硕士改变你的人生轨迹

在以“内卷”为主基调的职场环境里&#xff0c;似乎不停地进阶已经成为了职场人的唯一出路。但是&#xff0c;如何在进阶路上冲破职业瓶颈&#xff0c;到达心之所往的理想位置&#xff0c;则没有一个标准的答案。有的职场人士通过考取不同的技能证书来增加自身优势&#xff0c;…

Java Agent 踩坑之 appendToSystemClassLoaderSearch 问题

作者&#xff1a;卜比 本文是《容器中的 Java》系列文章之 2/n&#xff0c;欢迎关注后续连载 &#x1f603; 。 从 Java Agent 报错开始&#xff0c;到 JVM 原理&#xff0c;到 glibc 线程安全&#xff0c;再到 pthread tls&#xff0c;逐步探究 Java Agent 诡异报错。 背景 …

数据分析,你还在单纯地看数据?

企业的数字化意识越来越强&#xff0c;工作中也开始使用各种业务系统来管理业务&#xff0c;管理数据。很多人以为上了业务系统&#xff0c;对数据进行统计了&#xff0c;就是数据分析&#xff0c;这是大错特错的观点&#xff0c;数据分析是通过数据来剖析企业经营管理和业务发…

Using chatbots to scaffold EFL students argumentative writing (论文翻译)

使用聊天机器人来指导学生的议论文写作摘要研究表明&#xff0c;英语作为外语的学生的议论文写作受益于与同龄人的互动。然而&#xff0c;在实践中找到一个理想的对象很困难&#xff0c;聊天机器人被认为是这个问题的潜在解决方案。聊天机器人是人工智能的一种形式&#xff0c;…

Studio One6最新更新教程及安装包下载

Studio One6拥有多达50款原生效果插件&#xff0c;例如Analog Delay延迟插件&#xff0c;除能制作延迟效果外&#xff0c;还提供了制作复古的镶边与和声效果。Rotor插件制作的经典旋转扬声器效果也是非常不错的。这些插件&#xff0c;无论是在用户界面&#xff0c;还是使用体验…

http-serve开启一个服务器

前言在写前端页面中&#xff0c;经常会在浏览器运行HTML页面&#xff0c;从本地文件夹中直接打开的一般都是file协议&#xff0c;当代码中存在http或https的链接时&#xff0c;HTML页面就无法正常打开&#xff0c;为了解决这种情况&#xff0c;需要在在本地开启一个本地的服务器…

70. 爬楼梯

70. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1 阶 1 阶2 阶 示例 2&am…

如何将python脚本打包成可执行exe文件

如何将python脚本打包成可执行exe文件 前提条件 1. 新建一个python项目&#xff0c;并且配置虚拟环境 2. 安装pyinstaller 打包EXE文件 写一个支持入参的python脚本&#xff0c;打包成exe文件 找一张图片作为exe文件的图标 百度搜索” 在线jpg转cio”,将图片转换成cio格式 …

MySQL基础篇第11章(数据处理之增删改)

1.插入数据 1.1 实际问题 1.2 方式1&#xff1a;VALUES的方式添加 使用这种语法一次只能向表中插入一条数据。 情况1&#xff1a;为表的所有字段按默认顺序插入数据 INSERT INTO 表名 VALUES (value1,value2,....);值列表中需要为表的每一个字段指定值&#xff0c;并且值的…

MTIC工业大脑,海量接入网关!

MTIC3.0工业大脑是高性能&#xff0c;高可靠性的低代码开发数据核心平台&#xff0c;支持上万级别的网关设备同时在线&#xff0c;提供标准版本业务系统&#xff0c;可实现多业主工程项目并行管理&#xff0c;吸取大型物联网数据监测工程专家建议&#xff0c;实现项目精细化管理…

什么是DPU

什么是DPU 什么是 DPU&#xff1f; 在数据中心、DPU 或数据处理单元中移动数据的专家是一种新型的可编程处理器&#xff0c;将与 CPU 和 GPU 一起成为计算的三大支柱之一。 当然&#xff0c;您可能已经熟悉中央处理器。 多年来&#xff0c;CPU 是大多数计算机中唯一的可编程元…

如何避免成为背锅侠?

你被同事甩过锅吗&#xff1f; 打工人在职场中犯错都是不可避免的。 但明明不是自己的问题&#xff0c;还要背个黑锅&#xff0c;就非常闹心了&#xff01; 大家好&#xff0c;我是大D。 前几天&#xff0c;大D开发完了一个项目&#xff0c;在交付验收中发现业务逻辑存在漏洞&a…

java swing人机对战五子棋(含背景音乐)

一、项目简介 本项目是一套基于java swing的人机对战五子棋系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xf…

java BigDecimal保留两位小数

对于一些精准的数字&#xff0c;如涉及到金额时我们一般会使用BigDecimal类型来保存和处理。在处理保留小数位数时&#xff0c;如果通过DecimalFormat表达式需要注意下。 1、通过DecimalFormat保留两位小数 通过上图可以看到&#xff0c;#在补位时&#xff0c;如果该位没有数…

C/C++入门005-C语言数组

文章目录C语言数组数组的基本概念及定义数组定义数组中的几个名词数组长度计算方法二维数组的含义二维数组的定义字符数组字符函数1. strlen 计算字符串长度2. strcpy 字符串拷贝3. strcat 字符串追加4. strcmp 字符串比较1. strncpy 字符串拷贝3. strncmp 字符串比较4. strstr…

【web安全】——web渗透的前缀知识

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门 创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座…