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

技术栈选用 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;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW动态加载语言与VI调用 附件有程序

此LabVIEW设计通过动态加载语言资源和调用VI来实现多语言支持和模块化功能。它适用于需要灵活语言切换和动态VI管理的场景,但在开发和维护中有一些需要优化的地方。以下是详细的分析和改进建议。 优点: 灵活的语言切换: 用户可通过加载不同语…

分布式搜索引擎之elasticsearch基本使用2

分布式搜索引擎之elasticsearch基本使用2 在分布式搜索引擎之elasticsearch基本使用1中,我们已经导入了大量数据到elasticsearch中,实现了elasticsearch的数据存储功能。但elasticsearch最擅长的还是搜索和数据分析。 所以j接下来,我们研究下…

使用webrtc-streamer查看实时监控

摄像头配置(海康摄像头为例) 摄像头视频编码应改成H264格式 webrtc-streamer下载 webrtc-streamer下载地址 下载后解压出来双击运行,端口默认8000 VUE2项目引入文件 在项目静态文件“public”中需引入两个js文件“webrtcstreamer.js”与“…

鸿蒙调试打包(非正式打包)

文章目录 前言第一步:生成.p12和.csr文件第二步:申请证书的前置步骤第三步:申请证书 前言 HarmonyOS 应用打包后的文件为.app 格式, android 打包后的文件为.apk,IOS 打包后的文件为.apa HarmonyOS通过数字证书&#…

如何利用DBeaver配置连接MongoDB和人大金仓数据库

最近根据国产化要求,需要使用国产数据库,但习惯使用DBeaver连接各种成熟的商业或开源数据库。因此,就想着如何继续基于该工具,连接MongoDB和人大金仓数据库,查了半天很多地方说法不统一,所以自己就简单整理…

手机租赁系统开发指南一站式服务流程解析

内容概要 手机租赁系统的开发是一个复杂但有趣的过程,像搭建乐高一样,只要找到合适的模块,就能打造出一个宾至如归的租赁平台。在这部分,我们将对开发流程的整体结构进行简要概述,并指出每个环节的重要性。 首先&…

Linux中vi和vim的区别详解

文章目录 Linux中vi和vim的区别详解一、引言二、vi和vim的起源与发展三、功能和特性1、语法高亮2、显示行号3、编辑模式4、可视化界面5、功能扩展6、插件支持 四、使用示例1、启动编辑器2、基本操作 五、总结 Linux中vi和vim的区别详解 一、引言 在Linux系统中,vi和…

信息安全管理——应急响应、灾备与恢复

安全管理 信息安全管理 信息安全管理是指通过维护信息的机密性、完整性和可用性来管理和保护信息资产,是对信息安全保障进行指导、规范和管理的一系列活 动和过程。 信息安全管理的意义在于他是组织或者公司管理体系的一个重要环节 ,比如说一所大学就是…

数据库数据恢复—ORACLE常见故障有哪些?如何恢复数据?

Oracle数据库常见故障表现: 1、ORACLE数据库无法启动或无法正常工作。 2、ORACLE ASM存储破坏。 3、ORACLE数据文件丢失。 4、ORACLE数据文件部分损坏。 5、ORACLE DUMP文件损坏。 Oracle数据库数据恢复方案: 1、检测存放数据库的服务器/存储设备是否存…

使用 WebStorm 导入已有的 Vue 项目并运行的步骤与注意事项

目录 1. 引言2. WebStorm 环境准备 2.1 安装 WebStorm2.2 配置 Node.js 和 npm2.3 使用 nvm 管理 Node.js 和 npm 版本2.4 npm 版本与 Vue 版本对应关系 3. 导入已有的 Vue 项目 3.1 打开 Vue 项目3.2 安装项目依赖3.3 使用 nvm 控制 Node.js 和 npm 版本 4. 运行 Vue 项目 4.…

C++感受15-Hello Object 封装版 -下(上机)

一步步(分解成九段小视频)带你完成“选美大赛海选报名程序”,从需求到设计再到实现,完整体验,同时边学边用以下知识点: 转换构造、复制构造、转发构造特定成员函数默认实现成员数据初始化列表成员数据默认值…

深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

目录 深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解 一、引言:为什么要使用Array.find() 二、Array.find()的使用与技巧 1、基础语法 2、返回值 3、使用技巧 三、Array.find()的优势与实际应用案例 1、利用返回引用…

探索 LeNet-5:卷积神经网络的先驱与手写数字识别传奇

一、引言 在当今深度学习技术蓬勃发展的时代,各种复杂而强大的神经网络架构不断涌现,如 ResNet、VGG、Transformer 等,它们在图像识别、自然语言处理、语音识别等众多领域都取得了令人瞩目的成果。然而,当我们回顾深度学习的发展历…

希迪智驾持续亏损8.2亿:毛利率下滑,冲刺“自动驾驶矿卡第一股”

《港湾商业观察》黄懿 近日,希迪智驾(湖南)股份有限公司(下称“希迪智驾”)向港交所主板递交上市申请,联席保荐人为中金公司、中信建投国际、中国平安资本(香港)。 资料显示&#…

Vue 提供了Transition,可以帮助你制作基于状态变化的过渡和动画

官方文档&#xff1a;https://cn.vuejs.org/guide/built-ins/transition.html Transition​ Vue 提供了两个内置组件&#xff0c;可以帮助你制作基于状态变化的过渡和动画&#xff1a; <Transition> 会在一个元素或组件进入和离开 DOM 时应用动画。本章节会介绍如何使用…

Ansible自动化运维(三)playbook剧本详解

Ansible自动化运维这部分我将会分为五个部分来为大家讲解 &#xff08;一&#xff09;介绍、无密钥登录、安装部署、设置主机清单 &#xff08;二&#xff09;Ansible 中的 ad-hoc 模式 模块详解&#xff08;15&#xff09;个 &#xff08;三&#xff09;Playbook 模式详解 …

【汽车】-- 燃油发动机3缸和4缸

3缸和4缸燃油发动机是小轿车常见的发动机配置。以下从结构特点、性能、经济性等方面对两者进行对比&#xff0c;并分析优缺点及使用注意事项&#xff1a; 1. 结构与运行原理 3缸发动机 特点&#xff1a;少一个气缸&#xff0c;内部零部件更少&#xff0c;整体结构更紧凑。优点…

如何在x86模拟器和鸿蒙API9如何使用MQTT模块ohos_mqtt

目录 引言 安装失败的原因 如何编译so文件的x86_64版本 下载源代码 安装NDK 代码编译 安装MQTT软件包 避免MQTT软件包自动升级 设置libs 客户端程序的编写 运行测试 结语 参考文献 引言 在上周的博客&#xff08;如何在鸿蒙API9和x86模拟器中使用MQTT-CSDN博客&am…

若依集成更好用的easyexcel

背景 若依使用的是apach poi并在此基础上进行封装apach poi的原生的api是很复杂的&#xff0c;若依简化了了此操作apach poi的上传速率和下载速率都是没有优化的&#xff0c;依赖于文件大小的限制在此前提下&#xff0c;如果没法满足客户的需求&#xff08;超大型文件的上传&am…

我们来学mysql -- 探讨win安装方式(安装篇)

题记 书接上回&#xff0c;在我们来学mysql – 闲聊(安装篇)中&#xff0c;拿到安装包&#xff0c;当宝贝一样揣在怀里 然而&#xff0c;还没捂热乎&#xff0c;得粉丝秘报&#xff0c;U哥&#xff0c;上篇文章用了滞后的官方文档&#xff0c;哈哈哈…内心的小倔强&#xff0c…