前端H5移动端基础框架模板 :Vue3 + Vite5 + Pinia + Vant4 + Sass + 附源码

news2024/12/15 7:27:21

技术栈选用 Vue3 + Vite5 + Pinia + Vant4 + Sass

源码地址:

git clone https://gitee.com/gaiya001/h5-APP.git

在这里插入图片描述
在这里插入图片描述

1. 1.vite.config.js文件配置

**

import { defineConfig } from 'vite' // 导入 Vite 的配置函数
import vue from '@vitejs/plugin-vue' // 导入 Vue 插件
import path from 'path' // 导入 Node.js 的 path 模块
import Components from 'unplugin-vue-components/vite' // 导入 Vue 组件自动注册插件
import { VantResolver } from 'unplugin-vue-components/resolvers' // 导入 Vant 组件解析器
import { visualizer } from 'rollup-plugin-visualizer' // 导入 Rollup 打包分析插件
import { execSync } from 'child_process' // 导入 Node.js 的 child_process 模块

export default defineConfig({
  base: '/', // 设置应用的基础路径
  server: {
    port: 3000, // 设置开发服务器端口
    open: true, // 启动开发服务器时自动打开浏览器
    proxy: {
      '/api': {
        target: 'https://baidu', // 设置代理的目标地址
        changeOrigin: true, // 改变请求的源头
        rewrite: (path) => path.replace(/^\/api/, ''), // 重写路径
      },
    },
  },
  plugins: [
    vue(), // 使用 Vue 插件
    Components({
      resolvers: [VantResolver()], // 使用 Vant 组件解析器自动注册 Vant 组件
    }),
    visualizer({ open: true }), // 使用打包分析工具并在打包后自动打开分析报告
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'), // 设置路径别名,@ 指向 src 目录
    },
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['vue', 'axios', 'vant'], // 手动分割 vendor 包,包含 vue, axios, vant
        },
      },
    },
    chunkSizeWarningLimit: 500, // 设置警告阈值,单位 KB
    brotliSize: false, // 关闭 Brotli 压缩大小报告
  },
  optimizeDeps: {
    include: ['vue', 'axios', 'vant'], // 预构建依赖,提高构建速度
  },
  // 添加打包完成后清除 log 文件的钩子
  buildEnd: () => {
    try {
      execSync('rimraf logs'); // 使用 rimraf 清除 logs 目录
      // console.log('日志文件已清除');
    } catch (error) {
      // console.error('清除日志文件失败:', error);
    }
  },
})

2.main.js文件配置详解

// 导入 Vue 的 createApp 函数,用于创建 Vue 应用实例
import { createApp } from 'vue';

// 导入根组件 App.vue
import App from './App.vue';

// 引入路由配置
import router from './router/index.js';

// 引入路由权限配置
import '@/router/permission.js';

// 引入 Vant 的样式文件
import 'vant/lib/index.css';

// 引入全局样式文件(使用 SCSS)
import './assets/index.sass';

// 引入 Pinia 实例
import pinia from './store/index.js';

// 创建 Vue 应用实例
const app = createApp(App);

// 使用路由插件
app.use(router);

// 使用 Pinia 插件
app.use(pinia);

// 将 Pinia 实例注册为全局属性(可选)
// app.config.globalProperties.$store = pinia;

// 挂载应用到 DOM 中的 #app 元素
app.mount('#app');

## ```3.axios-req.js文件详解

```javascript
// 导入 axios 库,用于发送 HTTP 请求
import axios from 'axios';

// 从 Vant 库中导入 Toast 和 Dialog 组件,用于显示提示信息和对话框
import { Toast, Dialog } from 'vant';

// 从 Pinia 存储中导入 basic store,用于管理全局状态
import { useBasicStore } from '@/store/basic';

// 创建 axios 请求实例
const service = axios.create({
    baseURL: import.meta.env.VITE_APP_BASE_URL, // 设置基础 URL,从环境变量中获取
    timeout: 12000 // 设置请求超时时间为 12000 毫秒
});

let loadingInstance = null; // 用于存储 loading 提示实例
let tempReqUrlSave = ''; // 临时保存请求 URL
let authorTipDoor = true; // 控制授权提示的开关

// 定义一个函数,用于处理未授权的情况
const noAuthDill = () => {
    authorTipDoor = false; // 关闭授权提示开关
    Dialog.confirm({
        message: '请重新登录', // 提示信息
        confirmButtonText: '重新登录', // 确认按钮文本
        closeOnClickOverlay: false, // 点击遮罩层不关闭对话框
        showCancelButton: false, // 不显示取消按钮
        showClose: false, // 不显示关闭按钮
        theme: 'round-button' // 对话框主题
    }).then(() => {
        useBasicStore().resetStateAndToLogin(); // 重置状态并跳转到登录页面
        authorTipDoor = true; // 重新打开授权提示开关
    });
};

// 请求前拦截器
service.interceptors.request.use(
    (req) => {
        const { token, axiosPromiseArr } = useBasicStore();
        // 收集请求地址,用于取消请求
        req.cancelToken = new axios.CancelToken((cancel) => {
            tempReqUrlSave = req.url;
            axiosPromiseArr.push({
                url: req.url,
                cancel
            });
        });

        // 设置 token 到请求头
        if (token) req.headers['X-Auth-Token'] = token;

        // 如果请求方法是 GET 并且没有 params,使用 data 作为 params
        if (req.method?.toLowerCase() === 'get' && !req.params) req.params = req.data;

        // 请求加载提示
        if (req.reqLoading ?? true) {
            loadingInstance = Toast.loading({
                forbidClick: true, // 禁止点击
                duration: 0, // 持续时间,0 表示持续显示
                message: '数据载入中...' // 提示信息
            });
        }

        console.log('Request:', req); // 添加请求日志

        return req;
    },
    (err) => {
        console.error('Request Error:', err); // 添加请求错误日志
        return Promise.reject(err);
    }
);

// 请求后拦截器
service.interceptors.response.use(
    (res) => {
        // 取消请求
        useBasicStore().remotePromiseArrByReqUrl(tempReqUrlSave);
        if (loadingInstance) {
            Toast.clear(); // 清除 loading 提示
        }

        // 处理文件下载
        if (res.data?.type?.includes("sheet")) {
            return res;
        }

        const { code, msg } = res.data;
        const successCode = [0, 200, 20000]; // 成功状态码
        const noAuthCode = [401, 403]; // 未授权状态码

        if (successCode.includes(code)) {
            console.log('Response:', res); // 添加响应日志
            return res.data;
        } else {
            // authorTipDoor 防止多个请求多次提示
            if (authorTipDoor) {
                if (noAuthCode.includes(code)) {
                    noAuthDill(); // 处理未授权情况
                } else {
                    if (!res.config?.isNotTipErrorMsg) {
                        Toast.fail({
                            message: msg || '请求失败', // 提示信息
                            duration: 2 * 1000 // 持续时间 2 秒
                        });
                    } else {
                        return res;
                    }
                    return Promise.reject(msg || '请求失败');
                }
            }
        }
    },
    (err) => {
        // 取消请求
        useBasicStore().remotePromiseArrByReqUrl(tempReqUrlSave);
        if (loadingInstance) {
            Toast.clear(); // 清除 loading 提示
        }

        console.error('Response Error:', err); // 添加响应错误日志

        Toast.fail({
            message: err.message || '网络请求失败', // 提示信息
            duration: 2 * 1000 // 持续时间 2 秒
        });

        return Promise.reject(err);
    }
);

// 手动取消请求
export function cancelRequest(url) {
    const { axiosPromiseArr } = useBasicStore();
    const index = axiosPromiseArr.findIndex(item => item.url === url);
    if (index !== -1) {
        axiosPromiseArr[index].cancel(); // 取消请求
        axiosPromiseArr.splice(index, 1); // 从数组中移除已取消的请求
    }
}

// 导出 service 实例给页面调用,config -> 页面的配置
export default function axiosReq(config) {
    return service(config);
}

4.路由permission.js文件配置

import router from './index'; // 引入主路由模块
import { useUserStore } from '@/store/modules/user'; // pinia持久化的信息

const whiteList = ['/login']; // 不需要鉴权的路由白名单

router.beforeEach(async (to, from, next) => {
    console.log(to,"路由前置守望");

    const userStore = useUserStore();

    // 设置页面标题
    document.title = to.meta?.title;

    // 获取用户信息
    const { token } = userStore.userInfo;
    console.log(token,'token')
    // 如果用户已经登录,则直接放行
    if (token) {
        next();
        return;
    }

    // 如果用户未登录并且目标路由不在白名单中
    if (!token && !whiteList.includes(to.path)) {
        // 重定向到登录页,并携带当前路由路径作为查询参数
        next(`/login?redirect=${to.path}`);
    } else {
        // 目标路由在白名单中,直接放行
        next();
    }
});
// 路由后置守卫
router.afterEach((to, from) => {
    // console.log('路由后置守望', to, from);
});

export default router;

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

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

相关文章

继电器控制与C++编程:实现安全开关控制的技术分享

在现代生活中,继电器作为一种重要的电气控制元件,在电气设备的安全控制中起到了至关重要的作用。通过低电流控制高电流,继电器能够有效地隔离控制电路与被控设备,从而保障使用者的安全。本项目将介绍如何通过树莓派Pico与继电器模块结合,使用C++编程实现继电器的控制。 一…

Stable Diffusion Controlnet常用控制类型解析与实战课程 5

本节内容,是stable diffusion controlnet常用控制类型与实战的第5节课程。在前面几期课程中,我们已经陆续学习了controlnet的多种控制类型,本节课程,我们将继续讲解revision,instructp2p,ip-adapter&#x…

spark如何自定义函数

UDF:一对一的函数【User Defined Functions】 substr、split、concat、instr、length、from_unixtime UDAF:多对一的函数【User Defined Aggregation Functions】 聚合函数 count、sum、max、min、avg、collect_set/list UDTF:一对多的函…

linux网络编程 | c | select实现多路IO转接服务器

poll实现多路IO转接服务器 基于该视频完成 04-poll函数实现服务器_哔哩哔哩_bilibili 通过响应式–多路IO转接实现 要求:能看懂看,看不懂也没啥大事,现在基本都用epoll代替了 大家看视频思路吧,代码就是从讲义里面copy了一份…

数据结构(顺序表)JAVA方法的介绍

前言 在 Java 中,集合类(Collections)是构建高效程序的核心组件之一,而 List 接口作为集合框架中的重要一员,是一个有序、可重复的元素集合。与 Set 接口不同,List 保证了元素的顺序性,并允许存…

HTML+CSS+Vue3的静态网页,免费开源,可当作作业使用

拿走请吱一声&#xff0c;点个关注吧&#xff0c;代码如下&#xff0c;网页有移动端适配 HTML <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width…

内网穿透讲解

什么是内网穿透 内网穿透是一种网络技术&#xff0c;它允许外网或者其他局域网的用户来访问这个局域网的服务器资源&#xff0c;让资源的利用率更高&#xff0c;更加灵活&#xff0c;但是也要确保网络安全。 工作原理 如果你在公司&#xff0c;但是你需要使用到你家里的那台电…

Harmonyos之深浅模式适配

Harmonyos之换肤功能 概述实现原理颜色适配颜色资源配置工具类编写界面代码编写适配效果 概述 深色模式&#xff08;Dark Mode&#xff09;又称之为暗色模式&#xff0c;是与日常应用使用过程中的浅色模式&#xff08;Light Mode&#xff09;相对应的一种UI主题。 换肤功能应…

蓝桥杯刷题——day4

蓝桥杯刷题——day4 题目一题干题目解析代码 题目二题干题目解析代码 题目一 题干 小蓝和朋友们在玩一个报数游戏。由于今年是2024 年&#xff0c;他们决定要从小到大轮流报出是20或24倍数的正整数。前10个被报出的数是&#xff1a;20,24,40,48,60,72,80,96,100,120。请问第2…

Git:常用命令

一、查看当前分支 git branch 二、查看所有分支 git branch -a 三、切换到远程分支 git checkout origin/分支名 示例&#xff1a;git checkout origin/dev 四、拉取远程分支代码 git pull origin 分支名 示例&#xff1a;git pull origin dev 五、常用指令 查看暂存区…

算法题(4):报数游戏

审题&#xff1a;首先这题本质上是数学题中的找规律问题&#xff0c;我们需要用到编程的地方也只是辅助计算 思路&#xff1a;首先先用枚举法多算几个数出来&#xff0c;然后观察规律 枚举之后我们发现从第一个位置开始每过十个数就会增加120&#xff0c;所以每十个数可以算一个…

短视频矩阵源码开发部署全流程解析

在当今的数字化时代&#xff0c;短视频已成为人们娱乐、学习和社交的重要方式。短视频矩阵系统的开发与部署&#xff0c;对于希望在这一领域脱颖而出的企业和个人而言&#xff0c;至关重要。本文将详细阐述短视频矩阵源码的开发与部署流程&#xff0c;并附上部分源代码示例&…

【FLASH、SRAM和DRAM、CISC和RISC、冯诺依曼和哈佛】单片机内存结构的了解

【FLASH、SRAM和DRAM、CISC和RISC、冯诺依曼和哈佛】单片机内存结构的了解 一、单片机概念 单片机&#xff1a;Single-Chip Microcomputer&#xff0c;单片微型计算机&#xff0c;是一种集成电路芯片 1.1RAM里的SRAM和DRAM SRAM&#xff08;Static Random Access Memory&…

STM32仿真——01创建工程

目录 1.需要用到的软件工具​编辑 2.第一步Proteus软件新建工程​编辑 3.第二步——stm32cubumx 4、MDK代码编写 #注意安装的过程或者使用过程使用英文&#xff0c;以防报错&#xff1b; 1.需要用到的软件工具 2.第一步Proteus软件新建工程 选中&#xff0c;默认 先布局&…

Spark3.2.0集群部署ON YARN

环境说明 准备三台服务器&#xff0c;分别为&#xff1a;bigdata141&#xff08;hadoop 主节点&#xff09;、bigdata142、bigdata143确保 hadoop 集群先启动好&#xff0c;我这边的 hadoop 版本为 3.2.0另准备一台服务器&#xff0c;bigdata144&#xff0c;作为 hadoop 客户端…

GLM-4-Plus初体验

引言&#xff1a;为什么高效的内容创作如此重要&#xff1f; 在当前竞争激烈的市场环境中&#xff0c;内容创作已成为品牌成功的重要支柱。无论是撰写营销文案、博客文章、社交媒体帖子&#xff0c;还是制作广告&#xff0c;优质的内容不仅能够帮助品牌吸引目标受众的注意力&a…

C++获取时间戳/计算运行时长

一、便于使用&#xff0c;使用chrono封装一个简单的类 #pragma once#include <chrono>using CTime_point std::chrono::high_resolution_clock::time_point;class CElapsedTime final { public:static CTime_point now() {return std::chrono::high_resolution_clock::…

IDEA方法注释模板设置

目录 创建模板 新建模板&#xff1a;命名为* 设置模板内容-IDEA格式模板 设置模板应用场景 设置参数 创建模板 /**Enter这里我们也按照这种习惯来设置IDEA的方法注释&#xff1a;File-->Settings-->Editor-->Live Templates 先新建模板组&#xff0c;然后在模板组中…

Xcode

info.plist Appearance Light 关闭黑暗模式 Bundle display name 设置app名称&#xff0c;默认为工程名 Location When In Use Usage Description 定位权限一共有3个key 1.Privacy - Location When In Use Usage Description 2.Privacy - Location Always and When In U…

探索 Cesium 的未来:3D Tiles Next 标准解析

探索 Cesium 的未来&#xff1a;3D Tiles Next 标准解析 随着地理信息系统&#xff08;GIS&#xff09;和 3D 空间数据的快速发展&#xff0c;Cesium 作为领先的开源 3D 地球可视化平台&#xff0c;已成为展示大规模三维数据和进行实时渲染的强大工具。近年来&#xff0c;随着…