☰
Uniapp全局配置详解:跨端项目开发的核心梳理
2026/10/17 6:11:18 网站建设 项目流程

做多端项目的人应该都体会过这种场景:一套代码跑小程序、App、H5,听起来很美,但真正让项目“稳”下来的,往往不是业务组件写得有多花哨,而是最基础的全局配置有没有理顺。Uniapp 全局配置这件事,说白了就是先把骨架搭对:入口加载谁、页面注册哪些、全局样式从哪来、公共组件怎么免注册、接口和状态怎么统一管,这些都不应该等项目写了几十个页面之后才回头补。这篇内容就围绕 Uniapp 的全局配置展开,按实际项目的配置顺序把关键模块拆开讲清楚,包括 pages.json、manifest.json、uni.scss、App.vue、main.js、easycom、状态管理和条件编译。适合刚开始用 Uniapp 做跨端项目的新人,也适合项目已经跑起来、但发现全局逻辑有点乱的开发者照着重新梳理一遍。

1. 先建立全局配置的整体认知

1.1 六个全局入口分别管什么

很多人第一次打开 Uniapp 项目会有点懵,根目录下同时躺着 pages.json、manifest.json、main.js、App.vue,还有一个 uni.scss,每个文件都能写配置,但职责边界很模糊。我一般会跟新同事这样解释:这几个文件就是一套房子的图纸、物业、门禁和装修标准,各管一摊,不能混着用。

  • pages.json:管“有哪些页面、页面长什么样”,包括页面注册、路由、导航栏、tabBar、窗口样式,它是整个应用的地图。
  • manifest.json:管“应用对外怎么声明”,包括应用名称、版本号、平台配置、权限声明、SDK 配置,它面向的是各平台的应用信息。
  • main.js:管“应用怎么启动”,包括创建实例、安装插件、注册全局属性,它是代码执行的入口。
  • App.vue:管“应用生命周期和全局样式”,包括 onLaunch、onShow、全局 app 级别样式,它是所有页面的根组件。
  • uni.scss:管“全局样式变量”,在编译阶段注入到每个组件的样式里,用它来统一管理颜色、字号、间距这些设计变量。
  • store:管“全局共享数据”,用户登录态、购物车、权限等跨页面状态都放这里。

理解这个分工之后,你会发现在新项目里最先动手的就是 pages.json 和 uni.scss,因为它们决定了页面的基础框架和视觉基线。main.js 和 App.vue 则是后面逐步补充的,比如接入了第三方插件、需要全局拦截器的时候再来改。

一种常见的反模式:把接口地址、appKey 这类“应用级配置”直接写进某个页面里。一旦换环境或换包名,就要全局搜索替换,非常痛苦。正确做法是放环境变量或统一配置文件,后面第 5 章会详细展开。

1.2 从 Vue2 到 Vue3 的入口差异

全局配置看起来是“写文件”,但底层逻辑跟着 Vue 版本走。Uniapp 早期主流模板是 Vue2,main.js 里用new Vue()启动,全局属性挂到Vue.prototype上。Vue3 模板则改成createSSRApp(),全局属性挂到app.config.globalProperties上。

如果你接手的是一个 Vue2 老项目,想在它里面照抄 Vue3 的app.config.globalProperties写法,那跑不起来是正常的。反过来,Vue3 项目里去new Vue()也会出错。

// Vue2 写法 import Vue from 'vue' Vue.prototype.$http = request const app = new Vue({ ...App, }) app.$mount() // Vue3 写法 import { createSSRApp } from 'vue' export function createApp() { const app = createSSRApp(App) app.config.globalProperties.$http = request return app }

实际项目里最常踩的坑是:在 Vue3 的createApp返回函数中,忘了return app,或者把config.globalProperties写在createSSRApp外面。前者会导致组件加载不出来,后者会在多端编译时报类型错误。

1.3 分割全局配置的判断标准

配置拆分没有绝对标准,但我多年下来的经验总结成一句话:跟着运行环境和业务逻辑走。

  • 跟“平台声明”相关的放 manifest.json,比如应用图标、各端权限、第三方 SDK 配置。这东西不需要写代码,改完之后通常要重新编译对应端才会生效。
  • 跟“页面与路由”相关的放 pages.json,比如页面路径、导航栏标题、tabBar 图标。它描述的是用户能看到的东西。
  • 跟“启动与依赖注入”相关的放 main.js,比如插件安装、全局组件注册、全局工具方法挂载。
  • 跟“设计语言”相关的放 uni.scss 和全局样式文件,比如主色调、圆角、间距。
  • 跟“业务共享”相关的放 store 和 utils,比如 token、用户信息、请求封装。

如果拿不准,我会用下面这张表自查。配置项属于哪一类,就放对应文件,不要朝三暮四。

配置内容示例放置位置备注
页面路径与启动页pages,globalStylepages.json第一个页面就是启动页
应用图标和权限appid,图标,权限声明manifest.json改动后一般需要重新编译
全局插件第三方 SDK 初始化main.js在 createApp 之前或之后按插件要求处理
设计变量主色、字号、间距uni.scss / 全局 style编译期注入,无需 import 即可使用
业务共享数据登录状态、购物车store用状态管理,不要依赖 globalData 响应式
接口环境baseURL、appKey环境变量文件配合 process.env 使用

2. pages.json:页面与路由的全局配置

2.1 pages 数组里藏着启动页规则

pages.json 的pages数组是页面配置的第一优先级。数组第一项就是应用启动后的第一个页面,这一点很多人都会,但真正容易疏忽的是页面路径必须和文件目录完全一致,大小写、多一个斜杠都会导致编译后找不到页面。

{ "pages": [ { "path": "pages/index/index", "style": { "navigationBarTitleText": "首页", "enablePullDownRefresh": true } }, { "path": "pages/login/login", "style": { "navigationBarTitleText": "登录" } } ] }

这里有一个细节:path 不写前缀/,比如pages/index/index而不是/pages/index/index。很多从微信原生小程序转过来的人习惯性写成/pages/...,在小程序端可能没问题,但在 App 端和 H5 端可能会出奇怪的路由问题。我实测下来,Uniapp 官方对两种写法有兼容处理,但最好统一不写斜杠,减少不同版本编译器的差异判断。

还有一个经验:pages 数组的排列顺序不仅是启动顺序,在很多路由跳转场景中也会影响页面栈的表现。比如uni.navigateTo只能跳转到非 tabBar 页面,而判断一个页面是不是 tabBar 页面,取决于tabBar.list,跟 pages 顺序无关。但首页最好不要挪位置,某些端的默认回退逻辑会参考第一项。

2.2 globalStyle 的默认值到底覆盖什么

globalStyle是全局窗口风格的默认值,页面少的时候很容易被忽略,等页面多了再改就要一个页面一个页面地覆盖。我在新项目里一定会先配好这一段:

{ "globalStyle": { "navigationBarBackgroundColor": "#ffffff", "navigationBarTextStyle": "black", "navigationBarTitleText": "", "backgroundColor": "#f5f5f5", "backgroundTextStyle": "dark" } }

几个关键参数的真实效果需要区分清楚:

  • navigationBarBackgroundColor和navigationBarTextStyle:控制的是原生导航栏的背景色和文字颜色,注意navigationBarTextStyle只支持black/white两个值,写其他颜色在编译时不会报错,但真机上不会生效。
  • backgroundColor:控制的是下拉刷新和页面回弹时的背景色,不是页面主体背景色,页面主体背景色还是要靠每个页面的根节点样式来控制。
  • backgroundTextStyle:控制的是下拉刷新加载圈的颜色,同样是dark/light两种值。

实际项目里我习惯把navigationBarTitleText留空,让每个页面自己去设置导航标题,这样全局配置和页面配置的职责更清晰。否则你在 globalStyle 里写死一个“首页”,结果每个页面顶部都显示“首页”,排查起来很莫名其妙。

2.3 tabBar 配置的三处硬性约束

tabBar 是全局配置里最有“存在感”的一块,因为配置错了直接表现为页面起不来、图标不显示。我总结过三类高频问题:

第一,list里的pagePath必须在pages数组中真实存在,否则会报“tabBar 页面路径错误”。第二,tabBar 图标是静态资源,不能放网络图片,而且文件大小有限制,一般推荐不超过 40KB。第三,color和selectedColor是必填项,漏了之后选中的文字颜色可能直接跟随系统默认值,看起来像没配一样。

{ "tabBar": { "color": "#999999", "selectedColor": "#ff6600", "backgroundColor": "#ffffff", "borderStyle": "black", "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "static/tab-home.png", "selectedIconPath": "static/tab-home-active.png" }, { "pagePath": "pages/mine/mine", "text": "我的", "iconPath": "static/tab-mine.png", "selectedIconPath": "static/tab-mine-active.png" } ] } }

改动 tabBar 配置后,不要只在浏览器里看效果。很多端(尤其原生 App)对 tabBar 的改动缓存很顽固,编译一次不够,需要停止运行再重新运行。我经历过一次改图标一直显示旧图,最后把真机上的应用删掉重装才看到新图标。

2.4 条件编译:让 pages.json 同时服务多端

Uniapp 条件编译不仅仅是代码里的#ifdef,在 pages.json 里同样可以用。比如某些页面只在微信小程序端出现,某些 tab 只在 App 端保留,可以通过注释表达式控制:

// #ifdef MP-WEIXIN { "path": "pages/weixin-only/weixin-only", "style": { "navigationBarTitleText": "仅微信" } } // #endif

这里需要注意,pages.json 本质是 JSON 文件,但 Uniapp 官方编译时会预处理这些条件注释,所以它能被正确解析。问题出在一些社区编辑器或自动格式化工具上,格式化之后可能把注释排到奇怪的位置。我的经验是:运行环境相关差异尽量用条件编译,但如果差异就一两行,不如统一在代码里运行时判断,降低配置文件的复杂度。

还有一个容易被绕晕的点:MP-WEIXIN、MP-ALIPAY、APP-PLUS、H5这些平台代号是编译期常量,写错一个字符都不会生效,而且通常没有明显报错。判断当前平台用运行时 APIuni.getSystemInfoSync().platform,这两个完全是两码事,别混着用。

3. 全局样式:uni.scss 与通用样式管理

3.1 uni.scss 是变量注入器,不是样式文件

很多人以为把.page-container { padding: 20rpx; }这种公共类名写进 uni.scss 就能全局生效,然后发现页面里根本找不到这个类,这就是对 uni.scss 的定位没理解。uni.scss 的机制是把文件中的变量注入到每个组件的样式编译上下文,它的主要用途是定义 SCSS 变量,而不是写真正的全局 CSS 规则。

// uni.scss $uni-color-primary: #0079ff; $uni-color-success: #3cb371; $uni-color-warning: #ff9900; $uni-color-error: #f56c6c; $brand-color: #ff6600; $brand-radius: 12rpx; $brand-space-base: 24rpx;

定义之后,在任何组件或者页面的<style lang="scss">里,直接使用$brand-color即可,不需要@import这个文件。这个设计就是为了解决跨端项目里“设计变量不一致”的痛点,主题色换个值,全项目一起变。

需要注意,要在页面中使用这些变量,style 标签必须加上lang="scss",纯 css 一大段在编译时不会认识这些$变量。如果项目里为了省事用纯 CSS,那 uni.scss 对你就没有任何意义,这是前面几轮排错时经常发现的问题。

3.2 App.vue 的全局样式怎么写才安全

App.vue 里的<style>标签默认不带scoped,写在这里的样式会穿透到所有页面,这个特性用好了是利器,用不好就是灾难源头。我见过最典型的问题:在 App.vue 里写了.container { display: flex; },结果某个页面自己的.container样式被覆盖,页面布局直接乱掉。

安全写法主要有三条原则:

  • 给全局样式加统一的命名前缀,比如.g-btn、.g-card,或者用页面级 class 包裹。
  • 公共类名尽量只负责“基础视觉”,不轻易修改页面内组件的具体布局。
  • 跟页面结构耦合强的样式不要放全局,而是放组件内部或页面作用域。
/* App.vue 里推荐只放 reset 类和极少量全局工具类 */ page { background-color: #f5f5f6; font-size: 28rpx; color: #333333; box-sizing: border-box; } /* 避免全局晚乱七八糟的类名,如果实在需要,用 g- 前缀 */ .g-card { background: #ffffff; border-radius: 16rpx; padding: 24rpx; margin-bottom: 24rpx; }

另外一个跟全局样式配套的是 rpx 单位。Uniapp 遵循设计稿 750 宽的约定,1rpx 等于屏幕宽度除以 750,所以写750rpx就等于全屏宽度。小程序端对 rpx 有完整支持,H5 和 App 端编译后会有换算逻辑。我建议所有设计稿尺寸统一按 750 来,避免出现“在 H5 上宽度不够、在小程序上溢出”的惨剧。

3.3 深色模式与主题切换的全局处理

深色模式不是一个“页面级”的需求,它天然是全局的,所以适合放在全局样式层。Uniapp 提供了page-meta组件和theme相关能力,但在全局样式层面,比较通用的是 CSS 媒体查询:

@media (prefers-color-scheme: dark) { page { background-color: #1a1a1a; color: #e0e0e0; } }

这个方案在小程序端和 H5 端都有不错的支持。但要注意,原生 App 端对这种媒体查询的支持在不同系统版本下有差异,如果项目要稳定支持深色模式,建议结合运行时判断和全局变量切换来做,而不是只靠一条 CSS。

我做主题切换时会配合 uni.scss 里的设计变量,把颜色抽成 CSS 自定义属性:

page { --primary: #ff6600; --bg-color: #ffffff; } @media (prefers-color-scheme: dark) { page { --primary: #ffaa66; --bg-color: #1a1a1a; } }

这样每个页面引用var(--primary)而不是写死颜色。优点是想让用户手动切换主题时,只需要在更上层的节点换一套变量值就行,不需要去找几十个页面里的硬编码色值。

4. 全局组件与公共逻辑注入

4.1 easycom 让组件免注册

如果你受够了每个页面都要import一个组件、再在components里声明一遍,那 easycom 就是帮你解放双手的机制。按照约定,把组件放在components/组件名/组件名.vue,页面里直接用组件标签即可,不需要任何注册代码。

<template> <view> <my-header title="首页"></my-header> </view> </template>

默认情况下,Uniapp 会自动扫描components/目录下符合约定的组件。如果需要自定义匹配规则,可以在 pages.json 里配置:

{ "easycom": { "custom": { "^fu-(.*)": "@/components/foo-$1/foo-$1.vue" } } }

这里有一个坑提醒:easycom 自动引入的组件在 HBuilderX 项目里默认开启,但在 CLI 创建的项目里,某些版本需要在 pages.json 里显式声明"autoscan": true。另一个坑是,如果你在某个页面内手动 import 了同名组件,可能会和 easycom 的自动注册冲突,表现为“组件重复注册”或“某个版本随机取一个”,所以同一项目里别两套方式混着用同一类组件。

4.2 全局方法挂载的正确姿势

全局方法最典型的就是$http、$toast、$formatDate。Vue3 项目里可以这样挂:

// main.js import request from './utils/request' import { formatTime } from './utils/tools' export function createApp() { const app = createSSRApp(App) app.config.globalProperties.$http = request app.config.globalProperties.$formatTime = formatTime return app }

挂载之后,Options API 的组件里可以通过this.$http调用,方便是方便,但有两个问题必须提前想清楚:一是命名冲突,全局方法如果被某个组件自己的同名属性覆盖,几乎只会在运行时不经意地踩到;二是 Vue3 的<script setup>里拿this很别扭,很多新写的页面喜欢用getCurrentInstance()去取全局属性:

const { proxy } = getCurrentInstance() proxy.$http.get('/user/info')

这个写法能用,但我不太推荐全项目到处getCurrentInstance。更稳的方案是直接把request和工具函数独立导出,页面里import { request } from '@/utils/request'按需使用。全局挂载更像是给老页面留便捷入口,新页面尽量显式 import,依赖关系看得见摸得着,排查问题也会容易很多。

4.3 mixins 和逻辑复用要怎么取舍

全局 mixin 是一个充满争议的写法。在 Vue2 项目里,我曾经见过项目根目录放一个common.js,全局混入了一堆方法,结果每个组件都有好几十个“看不见来源”的属性,常常不知道这里的数据是页面自己定义的,还是 mixin 里塞进来的。这个维护成本非常高。

如果你只是在少数几个页面复用简单的逻辑,我更推荐抽成独立的工具函数或组合式 API。Uniapp 3.x 基于 Vue3,composable是比 mixin 更清爽的方案:

// composables/useLogin.js import { ref } from 'vue' export function useLogin() { const userInfo = ref(null) const isLogin = ref(false) const checkLogin = () => { // 判断本地 token 和用户信息 } return { userInfo, isLogin, checkLogin } }

页面里:

const { userInfo, isLogin, checkLogin } = useLogin()

这样数据来源清晰,每个页面只拿自己需要的东西。如果一定要用全局 mixin,务必把变量命名前缀做得足够特殊,避免和组件内属性覆盖,并且写清楚注释:这个 mixin 混入了哪些属性、为什么在这里。

4.4 globalData 到底适不适合存全局数据

App.vue里可以定义globalData,在任意页面通过getApp().globalData访问,这看起来很简单,但它有一个致命缺点:不是响应式的。页面 A 改掉了globalData.userInfo,页面 B 不一定能感知,除非在onShow里手动重新读取。

我实际项目中只在两个场景用 globalData:一是挂在应用启动时获取后就不再变化的配置(比如系统信息、版本号),二是临时缓存,跨页面传参太重了临时中转一下。真正需要跨页面“动态同步”的数据,请交给状态管理。

5. 全局接口与状态管理配置

5.1 请求拦截器的统一封装思路

不做全局请求封装的项目,我几乎每个页面都能看到重复的uni.request、重复的 header 处理、重复的 401 跳转。一旦接口返回结构变化或 token 过期逻辑要调整,就是一场大扫除。所以全局配置里,请求层是值得最先收拾的地方。

// utils/request.js const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.example.com' async function request(path, method = 'GET', data = {}) { const token = uni.getStorageSync('token') const response = await new Promise((resolve, reject) => { uni.request({ url: BASE_URL + path, method, data, header: { 'Content-Type': 'application/json', 'Authorization': token ? `Bearer ${token}` : '', }, success: (res) => { if (res.statusCode === 401) { uni.removeStorageSync('token') uni.navigateTo({ url: '/pages/login/login' }) reject(res) return } if (res.statusCode >= 200 && res.statusCode < 300) { resolve(res.data) } else { reject(res) } }, fail: reject, }) }) return response } export const get = (url, data) => request(url, 'GET', data) export const post = (url, data) => request(url, 'POST', data)

这段代码里几个全局化处理点值得说清楚。BASE_URL不写死,而是读到环境变量,这是多环境部署的关键。token 从本地存储统一读取,避免每个页面手动传。401 统一跳到登录页,这样接口层权限逻辑只需要维护一处。如果项目上线后要统计 API 耗时或埋点,也可以在这个文件里集中加逻辑,页面完全无感。

注意:uni.request的success回调里,网络层面只要收到响应就会执行,无论返回的 statusCode 是 200 还是 500。所以不要只看 success 就认为业务成功,必须再次判断状态码和业务 code。这是我调试时最常见的“坑”:接口返回 500 但页面上还把数据渲染了,因为只写了 success 没有判断状态码。

5.2 Pinia 与 Vuex 的全局状态到底怎么部署

Uniapp 的模板里有内置 Vuex,但如果你用的是 Vue3 版本,我更推荐直接上 Pinia。Pinia 的 API 更简洁,对 TypeScript 类型推导友好,而且 Vue DevTools 支持也不错。

// store/index.js import { createPinia } from 'pinia' export const store = createPinia() // store/user.js import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ token: '', userInfo: null, }), actions: { setLoginInfo(payload) { this.token = payload.token this.userInfo = payload.userInfo uni.setStorageSync('token', payload.token) }, logout() { this.token = '' this.userInfo = null uni.removeStorageSync('token') }, }, })

使用前的关键一步是在 main.js 里把 Pinia 实例注册进来,顺序写在 createApp 返回之前:

import { createSSRApp } from 'vue' import * as Pinia from 'pinia' import App from './App.vue' export function createApp() { const app = createSSRApp(App) const pinia = Pinia.createPinia() app.use(pinia) return app }

有一个容易踩的 Vue3 + Pinia 坑:在 store 里uni.getStorageSync这种运行时 API 只能在应用启动后访问,不要在 store 模块的顶层作用域去读取uni。因为模块加载时机可能早于运行时环境初始化,某些端会直接报找不到。正确做法是在App.vue的onLaunch里初始化 store 数据,或者直接读到值之后调用 store 的 action。

5.3 全局权限与导航跳转的统一处理

Uniapp 没有像 Vue Router 那样的beforeEach全局路由守卫,但这不意味着不能做全局权限控制。我习惯把跳转方法自己包一遍,所有页面都用这个公共方法代替直接调uni.navigateTo:

// utils/navigate.js export function navigateTo(url, needLogin = false) { const token = uni.getStorageSync('token') if (needLogin && !token) { uni.navigateTo({ url: '/pages/login/login' }) return } uni.navigateTo({ url }) }

这样的好处是,将来如果要增加升级弹窗、页面访问埋点、传参校验,都可以收敛到一个地方。对于 tab 页面,记得用uni.switchTab,不能走navigateTo,否则到小程序端会报错。这些细节不整理成全局工具,天天在页面里复制粘贴,早晚出问题。

6. 环境变量与多端条件编译

6.1 本地开发、测试、生产的 baseURL 自动切换

全局配置里最容易被轻视的是环境变量。很多人写死一个接口地址,等上线时再改,风险极高。小程序和 App 的接口域名还有向平台申请校验的问题,本地联调时的地址放进去,连发布环节都会被拖累。

在 Uniapp 的 CLI 工程里,我通常这样组织:

.env.development .env.test .env.production

文件内容类似:

# .env.development VITE_API_BASE_URL=https://dev-api.example.com/ VITE_APP_ENV=development # .env.production VITE_API_BASE_URL=https://api.example.com/ VITE_APP_ENV=production

代码里读取用:

const baseURL = import.meta.env.VITE_API_BASE_URL

这里必须强调一个规则:变量名以 VITE_ 开头的才会被暴露到客户端代码中。如果你写个API_BASE_URL不带前缀,代码里拿到的永远是undefined。这是 Vite 有意为之的安全设计,防止把敏感配置全部塞进前端代码。

如果是 HBuilderX 可视化创建的项目,也可以在manifest.json的可视化界面里配置环境变量,效果一样。切换环境时最保险的做法是“改完配置后停掉运行,重新启动编译”,因为环境变量在编译阶段就注入了,热更新不一定完全替换干净。

6.2 条件编译的真实边界条件

条件编译是 Uniapp 多端能力的灵魂,但它不是万能的。官方提供的注释写法可以用于 js、css、template、pages.json、manifest.json,写法统一:

// #ifdef H5 console.log('只在H5执行') // #endif // #ifndef MP-WEIXIN console.log('除了微信小程序之外都执行') // #endif

在模板里写成:

<!-- #ifdef H5 --> <view>H5 专属节点</view> <!-- #endif -->

在样式里写成:

/* #ifdef APP-PLUS */ .g-toolbar { padding-bottom: constant(safe-area-inset-bottom); } /* #endif */

这里的关键是理解条件编译是预处理阶段的操作,不是运行时的 if。编译完成后,不符合条件的代码会被直接删掉,包体里完全不存在。所以不能用条件编译判断“运行时用户设备类型”,那是uni.getSystemInfoSync()的职责。

条件编译最常见的错误是注释符号写错。在 JSON 文件中用//,在 HTML 区域用<!-- -->,二者一旦交叉,编译器不会报错但会被忽略。我建议在代码里搜索一下#ifdef的数量,确认没有写错平台代号,比如把H5写成H5-app这种臆想出来的名字,编译期毫无反应。

6.3 全局配置失效的第一现场排查顺序

全局配置改了之后没有生效,是开发者最头疼的。我经过多次踩坑,总结出一套固定排查顺序,愿意直接分享给你:

第一,确认文件名和目录结构。HBuilderX 项目里的pages.json和 CLI 项目的src/pages.json位置不一样,你改的那个文件到底是不是项目实际读取的,先确认。这个听起来像废话,但我真遇到过同事在根目录放了一个pages.json,项目根本不理它。

第二,重新编译而不是热更新。pages.json 里的tabBar、globalStyle、easycom这些配置,很多端热更新感知不到,停掉运行再启动,通常能解决 80% 的问题。

第三,检查环境变量是否暴露。如果改动 baseURL 没生效,先看代码里读的是不是import.meta.env.VITE_XXX,再看对应.env文件的变量名是否带VITE_前缀。

第四,检查条件编译注释。如果某段配置只在特定端生效,确认平台代号写法和注释位置。特别是 JSON 文件里,条件编译注释不能出现在键值对内部,否则会导致解析混乱。

第五,看编译日志里的警告。Uniapp 的编译输出虽然不算特别详细,但对 pages.json 和 manifest.json 的异常会有提示,仔细翻一遍总比盲猜强。

症状优先级排查点常见结果
导航栏颜色没变globalStyle vs 页面 style被页面级 style 覆盖了
tabBar 图标不显示图标路径 / 体积 / 命名放错目录或大小超限
全局组件不起作用easycom 路径 / 命名组件名首字母大小写不一致
接口环境没切换env 文件 / VITE_ 前缀改错 env 文件或变量未暴露
条件编译不生效平台代号 / 注释语法写了别名而不是官方代号
uni.scss 变量报错style lang页面 style 没写 lang="scss"

7. 写在最后的一点个人经验

做过的跨端项目越多,越发现全局配置本质上是在给团队立规矩。文件放哪、变量叫什么、环境怎么切、组件怎么挂,这些事在项目第一天理顺,后面几十个页面开发时会非常顺。我个人的习惯是在项目根目录放一份简短的配置说明,把 pages.json、manifest.json、uni.scss 里已经约定好的规则写清楚,新人接手不用靠猜。

最后再分享一个小的实操细节:每当你觉得“全局改一个变量应该全项目生效,怎么这里还是旧值”时,先不要急着怀疑框架有 bug,按前面说的重新编译一步,然后再检查命名空间覆盖关系。我遇到的大多数全局配置失效,最后都归结为三个原因:文件没找对、缓存没清干净、局部覆盖没意识到。把这三关一过,Uniapp 的全局配置就没有秘密可言。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询