uniapp 面试题目整理100道加解析
以下是 UniApp 面试中常见的 100 道题目及解析,涵盖基础概念、生命周期、组件、路由、状态管理、跨平台适配、性能优化等核心知识点,适合面试准备和知识梳理。
一、基础概念(10 题)
-
什么是 UniApp?它的核心优势是什么?
解析:UniApp 是一个使用 Vue.js 开发跨平台应用的框架,可同时构建 iOS、Android、H5、微信小程序等多个平台的应用。
核心优势:- 一套代码多端运行,降低开发成本;
- 基于 Vue.js 语法,学习成本低;
- 内置丰富的 API 和组件,兼容各平台特性;
- 支持原生插件扩展,满足复杂场景需求。
-
UniApp 与传统原生开发、其他跨平台框架(如 Flutter、React Native)的区别?
解析:- 与原生开发:UniApp 通过中间层转换为各平台代码,开发效率高但性能略低于原生;原生开发需为每个平台单独编码,性能优但成本高。
- 与 Flutter:Flutter 使用 Dart 语言,自绘 UI,性能接近原生;UniApp 基于 WebView(部分平台),性能略低,但复用 Vue 生态更易上手。
- 与 React Native:RN 基于 React,通过 JS 桥接原生组件;UniApp 更侧重多端一致性,对小程序支持更友好。
-
UniApp 支持哪些平台?开发工具是什么?
解析:支持平台包括:App(iOS/Android)、H5、微信 / 支付宝 / 百度 / 字节跳动 / QQ 等小程序。
开发工具:推荐使用 HBuilderX(官方工具,内置多端编译、运行、调试功能),也可使用 VS Code 配合 UniApp 插件。 -
UniApp 的项目结构中,主要目录和文件的作用是什么?
解析:pages:存放页面组件(每个页面对应一个文件夹,含.vue 文件);static:存放静态资源(图片、字体等,打包时不编译);components:存放自定义组件;unpackage:打包输出目录(各平台编译后的文件);manifest.json:项目配置(应用名称、权限、平台设置等);pages.json:页面路由配置(路径、窗口样式、导航栏等);main.js:入口文件(初始化 Vue 实例);App.vue:应用入口组件(全局生命周期、样式)。
-
UniApp 的编译原理是什么?
解析:UniApp 通过 “编译器 + 运行时” 实现跨平台。- 编译时:将 Vue 代码转换为各平台的原生代码(如小程序的 wxml/wxss,H5 的 html/css);
- 运行时:通过适配层(如小程序的逻辑层、H5 的浏览器环境)统一 API 调用。
-
UniApp 中的
manifest.json和pages.json有什么区别?
解析:manifest.json:配置应用全局信息(如名称、图标、权限、各平台特有配置),影响应用的打包和运行环境。pages.json:配置页面路由、窗口样式(导航栏、状态栏)、底部 TabBar 等,仅影响页面展示和导航逻辑。
-
UniApp 中如何引入外部资源(如 JS、CSS、图片)?
解析:- JS:通过
import引入(支持相对路径或 npm 包); - CSS:在
style标签中通过@import引入,或在App.vue中全局引入; - 图片:优先放在
static目录,使用相对路径(如/static/img/logo.png),小程序端需注意路径是否支持网络图片。
- JS:通过
-
UniApp 支持 Vue 的哪些特性?不支持哪些?
解析:支持 Vue 的核心特性(如双向绑定、组件化、生命周期、指令、Vuex 等)。
不支持的特性:- 部分 Vue 高级 API(如
$nextTick在部分平台有差异); - 自定义指令的部分钩子(如
update在小程序端可能失效); v-html在小程序端受限(仅支持部分平台)。
- 部分 Vue 高级 API(如
-
UniApp 的版本更新机制是什么?
解析:- App 端:支持热更新(通过
uni.getUpdateManager检测,下载 wgt 包更新)和整包更新(跳转到应用商店); - 小程序端:依赖各平台的小程序更新机制(用户下次启动时自动更新);
- H5 端:需手动部署新版本覆盖旧文件。
- App 端:支持热更新(通过
-
什么是 UniModule?它的作用是什么?
解析:UniModule 是 UniApp 的扩展模块(如地图、支付、推送等),通过 HBuilderX 集成,无需手动配置原生代码,简化跨平台功能开发。例如:uni-pay模块提供统一的支付 API,适配各平台支付方式。
二、生命周期(10 题)
-
UniApp 的应用生命周期有哪些?请说明各自的触发时机。
解析:应用生命周期定义在App.vue中,包括:onLaunch:应用初始化完成时触发(全局只触发一次);onShow:应用启动或从后台进入前台时触发;onHide:应用从前台进入后台时触发;onError:应用发生错误时触发(如 API 调用失败);onUniNViewMessage:接收 nvue 页面发送的消息时触发(仅 App 端)。
-
UniApp 的页面生命周期有哪些?与 Vue 的生命周期有何区别?
解析:页面生命周期定义在页面组件中,核心包括:onLoad:页面加载时触发(接收路由参数);onShow:页面显示 / 切入前台时触发;onReady:页面初次渲染完成时触发(可操作 DOM);onHide:页面隐藏 / 切入后台时触发;onUnload:页面卸载时触发;onPullDownRefresh:下拉刷新时触发;onReachBottom:上拉触底时触发。
区别:UniApp 在 Vue 生命周期(如created、mounted)基础上新增了页面特有生命周期(如onLoad、onPullDownRefresh),更适配跨平台页面交互。
-
onLoad和created的触发顺序是什么?使用场景有何不同?
解析:触发顺序为created(Vue 生命周期)→onLoad(UniApp 页面生命周期)。created:页面实例创建时触发,此时还未接收路由参数,适合初始化数据(不依赖路由参数);onLoad:页面加载完成,可获取路由参数(options),适合根据参数请求数据。
-
页面切换时,生命周期的执行顺序是怎样的?(如 A 页面跳转到 B 页面)
解析:A 页面onHide→ B 页面onLoad→ B 页面onShow→ B 页面onReady。
(若 A 页面被卸载,如使用uni.redirectTo,则 A 页面会触发onUnload) -
onReady和mounted的区别是什么?
解析:mounted:Vue 生命周期,DOM 挂载完成,但可能未完成样式渲染(如小程序端);onReady:UniApp 页面生命周期,页面初次渲染完成(包括样式),更适合进行 DOM 操作(如获取元素尺寸)。
-
如何监听页面的下拉刷新和上拉触底?
解析:- 下拉刷新:在
pages.json中配置页面的"enablePullDownRefresh": true,然后在页面中实现onPullDownRefresh方法,完成后调用uni.stopPullDownRefresh()停止刷新; - 上拉触底:在
pages.json中配置"onReachBottomDistance": 50(触发距离),然后实现onReachBottom方法。
- 下拉刷新:在
-
应用从前台进入后台时,会触发哪些生命周期?
解析:首先触发当前页面的onHide,然后触发应用的onHide。 -
onError和try/catch的区别是什么?
解析:onError:全局捕获应用级错误(如 API 调用失败、组件渲染错误),无法捕获异步错误(如setTimeout内的错误);try/catch:局部捕获代码块中的错误(同步或异步),更灵活,适合处理已知可能出错的逻辑(如接口请求)。
-
nvue 页面的生命周期与 vue 页面有何不同?
解析:nvue(原生渲染)页面仅支持部分生命周期,如onLoad、onShow、onHide、onUnload,不支持created、mounted等 Vue 生命周期(因 nvue 基于 weex 引擎,渲染机制不同)。 -
如何在页面中监听应用的生命周期(如切后台)?
解析:通过uni.onAppShow、uni.onAppHide等 API 在页面中注册监听,示例:javascript
onLoad() { this.showListener = uni.onAppShow(() => { console.log('应用切入前台') }); this.hideListener = uni.onAppHide(() => { console.log('应用切入后台') }); }, onUnload() { this.showListener(); // 移除监听 this.hideListener(); }
三、组件与样式(15 题)
-
UniApp 的内置组件有哪些?请列举 5 个并说明用途。
解析:view:基础容器(类似 div),用于布局;text:文本容器(支持长按复制,仅包裹文本);button:按钮组件(支持默认、primary、warn 等样式,可绑定点击事件);image:图片组件(支持懒加载、模式裁剪,需注意路径);scroll-view:滚动容器(支持横向 / 纵向滚动,下拉刷新)。
-
自定义组件的注册方式有哪些?区别是什么?
解析:- 局部注册:在页面的
components选项中注册,仅当前页面可用; - 全局注册:在
main.js中通过Vue.component()注册,所有页面可用; - easycom 组件规范:将组件放在
components目录,按组件名/组件名.vue命名,无需注册可直接使用(推荐)。
- 局部注册:在页面的
-
如何在父组件和子组件之间传递数据?
解析:- 父传子:通过
props定义属性,父组件在引用子组件时传递数据;
子组件:props: { title: String },父组件:<child :title="msg"></child>; - 子传父:通过
$emit触发事件,父组件监听事件接收数据;
子组件:this.$emit('change', data),父组件:<child @change="handleChange"></child>。
- 父传子:通过
-
view和div、text和span的区别是什么?
解析:viewvsdiv:view是 UniApp 跨平台的容器组件,在小程序端编译为view标签,H5 端编译为div,支持各平台统一的样式和事件;div仅在 H5 端有效,小程序端不支持。textvsspan:text支持跨平台文本处理(如selectable属性开启长按复制),span仅 H5 端有效,小程序端不识别。
-
image组件的mode属性有哪些值?分别代表什么?
解析:mode用于指定图片裁剪 / 缩放模式,常用值:scaleToFill:拉伸填充(可能变形);aspectFit:等比缩放,长边适配(显示完整);aspectFill:等比缩放,短边适配(可能裁剪);widthFix:宽度固定,高度自适应;heightFix:高度固定,宽度自适应。
-
UniApp 中如何使用全局样式?
解析:在App.vue的style标签中编写样式(不加scoped),即可全局生效。例如:css
/* App.vue */ <style> .global-color { color: #f00; } </style> -
scoped样式的作用是什么?如何让子组件使用父组件的scoped样式?
解析:scoped使样式仅作用于当前组件(通过添加属性选择器实现),避免样式污染。
让子组件使用父组件样式:- 父组件中使用
::v-deep穿透scoped(Vue2)或:deep()(Vue3);
示例:::v-deep .child-class { color: red; }。
- 父组件中使用
-
UniApp 支持哪些 CSS 预处理器?如何配置?
解析:支持 Sass、Less、Stylus。配置方式:- 在 HBuilderX 中新建项目时勾选预处理器;
- 已创建项目:在
HBuilderX的 “工具→插件安装” 中安装对应预处理器插件,然后在style标签中指定lang(如<style lang="scss">)。
-
如何实现不同平台的样式适配?
解析:- 条件编译:使用
/* #ifdef 平台 */和/* #endif */包裹平台特有样式;
示例:css
/* #ifdef H5 */ .box { width: 100%; } /* #endif */ /* #ifdef MP-WEIXIN */ .box { width: 750rpx; } /* #endif */ - 使用
rpx单位(自动适配不同屏幕宽度,1rpx = 屏幕宽度 / 750)。
- 条件编译:使用
-
scroll-view如何实现横向滚动?
解析:- 设置
scroll-view的scroll-x为true; - 子元素需设置
display: inline-block(避免换行); - 父容器设置
white-space: nowrap(禁止文本换行)。
示例:
html
<scroll-view scroll-x="true" class="scroll-x"> <view class="item" v-for="i in 10" :key="i">{{i}}</view> </scroll-view> <style> .scroll-x { white-space: nowrap; } .item { display: inline-block; width: 200rpx; } </style> - 设置
-
如何自定义导航栏?
解析:- 在
pages.json中配置页面的"navigationStyle": "custom"(隐藏默认导航栏); - 在页面中自定义导航栏组件(包含标题、返回按钮等);
- 如需适配状态栏高度,可通过
uni.getSystemInfoSync().statusBarHeight获取高度。
- 在
-
button组件的open-type属性有哪些常用值?
解析:open-type用于调用小程序原生能力,常用值:contact:打开客服会话;share:触发分享;getUserInfo:获取用户信息(微信小程序旧版,新版用getUserProfile);launchApp:打开 APP(需配置关联)。
-
如何实现组件的懒加载?
解析:在pages.json中为页面配置"lazyCodeLoading": "requiredComponents",仅加载页面所需组件,减少初始包体积。 -
slot插槽在 UniApp 中的使用场景是什么?如何使用具名插槽?
解析:slot用于父组件向子组件插入内容,适合组件复用(如卡片、弹窗)。
具名插槽使用:- 子组件:
<slot name="header"></slot>; - 父组件:
<template #header><view>标题</view></template>(Vue3 语法)或<template slot="header">(Vue2)。
- 子组件:
-
nvue 页面的样式与 vue 页面有何不同?
解析:nvue 页面使用 weex 的样式规范,仅支持部分 CSS 属性:- 必须使用
flex布局(默认不支持流式布局); - 不支持
*选择器、scoped; - 单位仅支持
px(不支持rpx,需手动适配)。
- 必须使用
四、路由与导航(10 题)
-
UniApp 的路由模式有哪些?如何配置?
解析:支持两种路由模式(在pages.json的globalStyle中配置):hash模式(默认):URL 带#,H5 端兼容所有浏览器;history模式:URL 无#,需后端配置支持(否则刷新 404),仅 H5 端有效。
-
路由跳转的 API 有哪些?区别是什么?
解析:uni.navigateTo:保留当前页面,跳转到新页面(栈深限制,小程序端最多 10 层);uni.redirectTo:关闭当前页面,跳转到新页面;uni.reLaunch:关闭所有页面,跳转到新页面;uni.switchTab:跳转到 TabBar 页面(必须在pages.json的tabBar中配置);uni.navigateBack:返回上一页面(可指定返回层数,delta参数)。
-
如何传递路由参数?接收方式是什么?
解析:- 传递:在跳转 URL 后拼接参数(如
/pages/detail?id=1&name=test); - 接收:在目标页面的
onLoad生命周期中通过options参数获取:javascript
onLoad(options) { console.log(options.id); // 1 console.log(options.name); // test }
- 传递:在跳转 URL 后拼接参数(如
-
uni.navigateTo和uni.switchTab的使用限制是什么?
解析:uni.navigateTo:不能跳转到 TabBar 页面(需用switchTab);uni.switchTab:不能携带参数(URL 后拼接的参数会被忽略),且只能跳转到tabBar配置中的页面。
-
如何实现 TabBar 的配置?包含哪些属性?
解析:在pages.json中配置tabBar:json
"tabBar": { "color": "#666", // 未选中颜色 "selectedColor": "#f00", // 选中颜色 "list": [ { "pagePath": "pages/home/home", "text": "首页", "iconPath": "static/tab/home.png", "selectedIconPath": "static/tab/home-selected.png" }, { "pagePath": "pages/mine/mine", "text": "我的" } ] }核心属性:
color、selectedColor、list(Tab 项配置,含路径、文本、图标)。 -
路由拦截如何实现?
解析:UniApp 无内置路由拦截,需手动封装路由 API 实现:javascript
// 封装navigateTo function myNavigateTo(url) { // 拦截逻辑(如登录判断) if (needLogin && !isLogin) { uni.navigateTo({ url: '/pages/login/login' }); return; } uni.navigateTo({ url }); } -
H5 端路由刷新后参数丢失怎么办?
解析:uni.navigateTo的参数通过 URL 传递,H5 端刷新后onLoad的options会丢失。解决方式:- 使用
uni.setStorageSync将参数存入本地存储,刷新后读取; - 改用
history模式,参数通过query传递(刷新后 URL 保留参数)。
- 使用
-
如何获取当前页面的路由信息?
解析:通过getCurrentPages()获取页面栈,栈顶元素为当前页面:javascript
const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; console.log(currentPage.route); // 当前页面路径(如pages/home/home) console.log(currentPage.options); // 当前页面参数 -
小程序端路由栈的最大深度是多少?如何处理超过限制的情况?
解析:小程序端路由栈最大深度为 10 层(navigateTo累计调用 10 次后无法再跳转)。
处理方式:- 合理使用
redirectTo(关闭当前页)或reLaunch(关闭所有页); - 对于多级页面,跳转时关闭中间页面(如 A→B→C,从 C 返回 A 时用
reLaunch)。
- 合理使用
-
如何实现页面的反向传值(如 B 页面向 A 页面传递数据)?
解析:- 方式 1:通过
getCurrentPages()获取上一页面实例,直接修改数据;javascript
// B页面 const pages = getCurrentPages(); const prevPage = pages[pages.length - 2]; prevPage.setData({ name: '新数据' }); // 小程序端 // 或Vue式:prevPage.name = '新数据'; prevPage.$forceUpdate(); - 方式 2:使用 Vuex/Pinia 存储数据,A 页面监听数据变化;
- 方式 3:通过事件总线(如
uni.$emit/uni.$on)。
- 方式 1:通过
五、API 与数据请求(15 题)
-
UniApp 的 API 与小程序 API 有何关系?
解析:UniApp 的 API(uni.xxx)是对各平台 API 的封装,如uni.request对应微信小程序的wx.request、H5 的fetch等,实现跨平台统一调用。大部分 API 参数与小程序 API 兼容,但部分平台特有 API 需用条件编译。 -
uni.request的使用步骤是什么?如何处理请求成功 / 失败?
解析:步骤:- 调用
uni.request,传入url、method、data等参数; - 在
success回调中处理返回数据,fail中处理错误;
示例:
javascript
uni.request({ url: 'https://api.example.com/data', method: 'GET', data: { id: 1 }, success: (res) => { console.log(res.data); }, fail: (err) => { console.error('请求失败', err); }, complete: () => { console.log('请求完成'); } }); - 调用
-
如何封装
uni.request?为什么要封装?
解析:封装目的:统一处理请求头、错误、 loading 状态等,简化代码。
封装示例:javascript
// utils/request.js export default function request(options) { // 显示loading uni.showLoading({ title: '加载中' }); return new Promise((resolve, reject) => { uni.request({ url: 'https://api.example.com' + options.url, // 基础路径 method: options.method || 'GET', header: { 'Content-Type': 'application/json' }, data: options.data, success: (res) => { if (res.statusCode === 200) { resolve(res.data); } else { reject(new Error('请求错误')); } }, fail: reject, complete: () => { uni.hideLoading(); } }); }); } -
UniApp 中如何处理跨域问题?
解析:- H5 端:在
manifest.json的 H5 配置中设置"devServer": { "proxy": { "/api": { "target": "https://xxx", "changeOrigin": true } } }(开发环境代理);生产环境需后端配置CORS。 - 小程序 / App 端:无跨域限制(因小程序通过后端域名校验,App 端直接请求)。
- H5 端:在
-
uni.setStorageSync和uni.setStorage的区别是什么?使用场景有哪些?
解析:uni.setStorageSync:同步存储(阻塞后续代码),语法简单,适合少量数据;uni.setStorage:异步存储(非阻塞),通过回调处理结果,适合大量数据。
使用场景:存储用户信息、缓存列表数据、记住密码等。
-
如何获取用户信息?不同平台有何差异?
解析:- 小程序端:微信小程序需通过
uni.getUserProfile(需用户授权)获取,返回userInfo; - App 端:可通过
uni.getProvider获取第三方登录(如微信、QQ),或调用原生 SDK; - H5 端:依赖浏览器或第三方登录(如 OAuth),无统一 API。
- 小程序端:微信小程序需通过
-
uni.showToast和uni.showModal的区别是什么?
解析:uni.showToast:轻提示(如成功、加载中),默认 3 秒后消失,无交互;uni.showModal:模态弹窗(含标题、内容、确认 / 取消按钮),需用户操作后关闭,适合询问用户(如删除确认)。
-
如何实现图片上传?
解析:使用uni.chooseImage选择图片,再用uni.uploadFile上传:javascript
uni.chooseImage({ count: 1, success: (res) => { const tempFilePath = res.tempFilePaths[0]; uni.uploadFile({ url: 'https://api.example.com/upload', filePath: tempFilePath, name: 'file', // 后端接收的字段名 formData: { type: 'image' }, success: (uploadRes) => { console.log('上传成功', uploadRes.data); } }); } }); -
uni.getSystemInfoSync能获取哪些信息?有何用途?
解析:获取设备信息,如屏幕宽高、状态栏高度、设备型号、操作系统等。
用途:适配不同屏幕(如动态计算元素尺寸)、判断设备类型(如 iOS/Android)、处理状态栏高度。 -
如何实现扫码功能?
解析:使用uni.scanCode:javascript
uni.scanCode({ success: (res) => { console.log('扫码结果', res.result); // 二维码/条形码内容 } });注意:App 端需配置相机权限,H5 端仅部分浏览器支持。
-
UniApp 中如何调用原生插件?
解析:- 在 HBuilderX 中导入原生插件(本地插件或市场插件);
- 在
manifest.json中配置插件权限; - 通过
uni.requireNativePlugin('插件ID')获取插件实例,调用其方法。
-
uni.navigateTo和uni.openURL的区别是什么?
解析:uni.navigateTo:跳转到应用内的页面(路由跳转);uni.openURL:打开外部链接(如网页、其他 App 的 Scheme),需平台支持(如小程序需配置业务域名,App 端需配置白名单)。
-
如何监听网络状态变化?
解析:使用uni.onNetworkStatusChange注册监听:javascript
uni.onNetworkStatusChange((res) => { console.log('是否联网', res.isConnected); console.log('网络类型', res.networkType); // wifi/2g/3g/4g/5g/unknown }); -
小程序端
uni.request的超时时间如何设置?默认是多少?
解析:通过timeout参数设置(单位 ms),默认超时时间为 60000ms(1 分钟)。
示例:uni.request({ url: 'xxx', timeout: 30000 })。 -
如何实现应用内的分享功能?
解析:- 小程序端:通过
button的open-type="share"触发,在页面的onShareAppMessage中配置分享内容; - App 端:调用
uni.shareAPI,配置分享平台(微信、QQ 等)和内容;
示例(小程序):
javascript
onShareAppMessage() { return { title: '分享标题', path: '/pages/home/home?id=1', // 分享路径 imageUrl: '/static/share.png' }; } - 小程序端:通过
六、状态管理与全局数据(10 题)
-
UniApp 中如何实现全局状态管理?
解析:常用方式:- Vuex(或 Pinia):适合复杂应用,跨组件共享状态;
- 全局变量:在
main.js中挂载到Vue.prototype(如Vue.prototype.$global = { user: null }); - 本地存储:
uni.setStorageSync存储数据,跨页面读取(适合持久化数据)。
-
Vuex 的核心概念有哪些?如何在 UniApp 中使用 Vuex?
解析:核心概念:state(状态)、mutations(同步修改状态)、actions(异步操作)、getters(计算属性)、modules(模块化)。
使用步骤:- 创建
store/index.js,定义 Vuex 实例; - 在
main.js中导入并挂载到 Vue 实例; - 组件中通过
this.$store访问。
- 创建
-
Vuex 中
mutations和actions的区别是什么?
解析:mutations:只能同步操作,是修改state的唯一途径(通过commit触发);actions:可包含异步操作(如接口请求),通过dispatch触发,最终通过commit调用mutations修改state。
-
如何在组件中监听 Vuex 状态的变化?
解析:- 方式 1:通过
computed计算属性映射state(配合mapState辅助函数); - 方式 2:使用
watch监听$store.state中的属性;
示例:
javascript
computed: { ...mapState(['user']), userName() { return this.$store.state.user.name; } }, watch: { userName(newVal) { console.log('用户名变化', newVal); } } - 方式 1:通过
-
全局变量和 Vuex 的使用场景有何不同?
解析:- 全局变量:适合存储简单、无需响应式的数据(如配置信息、临时标识),修改后需手动刷新组件;
- Vuex:适合存储复杂、需要响应式的数据(如用户信息、购物车),状态变化时自动更新依赖组件。
-
如何实现跨页面的数据共享(非 Vuex)?
解析:- 方式 1:通过
getCurrentPages()获取目标页面实例,直接修改数据; - 方式 2:使用事件总线
uni.$emit/uni.$on(全局事件); - 方式 3:本地存储(
uni.setStorageSync)+ 页面onShow时读取。
- 方式 1:通过
-
Pinia 与 Vuex 相比有哪些优势?如何在 UniApp 中使用 Pinia?
解析:Pinia 优势:- 简化 API(无
mutations,直接在actions中修改状态); - 支持 TypeScript,类型推断更友好;
- 无需嵌套
modules,天然支持模块化。
使用:通过 npm 安装pinia,创建store实例并挂载到 Vue,组件中通过useStore访问。
- 简化 API(无
-
如何避免 Vuex 状态在页面刷新后丢失?
解析:- 监听
beforeunload事件,将state存入本地存储; - 初始化 Vuex 时,从本地存储读取数据恢复
state;
示例:
javascript
// store/index.js const store = new Vuex.Store({ state: JSON.parse(uni.getStorageSync('store') || '{}'), // ... }); // 监听刷新,保存state window.addEventListener('beforeunload', () => { uni.setStorageSync('store', JSON.stringify(store.state)); }); - 监听
-
Vue.prototype挂载的全局方法,在 nvue 页面中能否使用?
解析:不能。nvue 页面基于 weex 引擎,不支持Vue.prototype挂载的属性 / 方法,需通过globalData(App.vue 中定义)或本地存储共享。 -
如何在 App.vue 中定义全局数据,并在页面中访问?
解析:在App.vue的globalData中定义:javascript
// App.vue export default { globalData: { appName: 'MyApp' } }页面中访问:
- Vue 页面:
getApp().globalData.appName; - nvue 页面:
this.$getAppWebview().getApp().globalData.appName。
- Vue 页面:
七、跨平台适配与条件编译(10 题)
-
什么是条件编译?UniApp 的条件编译标识有哪些?
解析:条件编译是指根据不同平台编译不同代码,实现平台特有逻辑。
常用标识:#ifdef MP-WEIXIN:微信小程序;#ifdef H5:H5;#ifdef APP-PLUS:App;#ifdef MP-ALIPAY:支付宝小程序;#ifndef 平台:排除指定平台(如#ifndef H5表示非 H5 平台)。
-
条件编译的使用场景有哪些?请举例说明。
解析:场景:- 平台特有 API(如微信小程序的
wx.getWeRunData); - 样式差异(如 H5 需滚动条,小程序不需要);
- 功能差异(如 App 支持推送,H5 不支持)。
示例(JS 条件编译):
javascript
// #ifdef MP-WEIXIN console.log('微信小程序'); // #endif // #ifdef H5 console.log('H5'); // #endif - 平台特有 API(如微信小程序的
-
如何处理不同平台的 API 差异?
解析:- 优先使用
uni.xxx统一 API; - 平台特有 API 用条件编译包裹;
- 封装适配层(如将不同平台的支付 API 封装为统一方法)。
- 优先使用
-
H5 端与小程序端的样式差异主要有哪些?
解析:- 单位:H5 支持
px/rem/rpx,小程序推荐rpx; - 布局:H5 支持
float/position,小程序更依赖flex; - 选择器:H5 支持复杂选择器(如
div > p),小程序限制较多; - 滚动:H5 可通过
overflow: auto滚动,小程序需用scroll-view。
- 单位:H5 支持
-
App 端如何适配 iOS 和 Android 的差异?
解析:- 条件编译:
#ifdef IOS和#ifdef ANDROID; - 原生插件:使用平台特有插件(如 iOS 的内购、Android 的应用内支付);
- 样式:iOS 导航栏高度与 Android 不同,需动态计算(通过
uni.getSystemInfoSync())。
- 条件编译:
-
小程序端的分包加载是什么?如何配置?
解析:分包加载是将小程序代码拆分为主包和分包,用户进入对应页面时才下载分包,减少初始加载时间。
配置(pages.json):json
"subPackages": [ { "root": "pages/sub", // 分包根目录 "pages": [ { "path": "list/list" } ] // 分包页面 } ] -
H5 端如何适配不同屏幕尺寸?
解析:- 使用
rpx或%单位; - 媒体查询(
@media)适配不同宽度设备; - 弹性布局(
flex)和网格布局(grid); - 禁止页面缩放(
meta标签:<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">)。
- 使用
-
UniApp 中如何处理小程序端的域名校验?
解析:小程序端请求的域名需在对应平台的开发者后台配置(如微信小程序需在 “开发→开发设置→服务器域名” 中添加),否则会报 “域名不在许可列表中” 错误。开发环境可勾选 “不校验合法域名”(仅调试用)。 -
nvue 页面和 vue 页面如何混合使用?
解析:- App 端支持 nvue 和 vue 页面共存,通过路由跳转互通;
- 注意:nvue 页面不能引用 vue 组件,反之亦然;
- 数据传递通过路由参数或全局状态管理。
-
如何在 UniApp 中判断当前运行的平台?
解析:通过uni.getSystemInfoSync().platform判断:javascript
const platform = uni.getSystemInfoSync().platform; if (platform === 'android') { console.log('Android'); } else if (platform === 'ios') { console.log('iOS'); } else if (platform === 'devtools') { console.log('小程序开发者工具'); }
八、性能优化(10 题)
-
UniApp 的性能优化有哪些常用方法?
解析:- 减少渲染层级:避免嵌套过深(建议不超过 5 层);
- 图片优化:使用合适尺寸、懒加载(
image组件的lazy-load)、WebP 格式; - 合理使用组件:复用组件,避免频繁创建 / 销毁;
- 数据处理:减少
data中的冗余数据,避免频繁修改data; - 分包加载:小程序端拆分主包,减少初始下载体积;
- 避免不必要的渲染:使用
v-show替代v-if(频繁切换场景)。
-
为什么要避免在
onShow中请求数据?如何优化?
解析:onShow在页面每次显示时触发(如返回页面),频繁请求会浪费资源。
优化:在onLoad中请求(仅加载一次),或通过状态管理缓存数据,onShow中判断是否需要重新请求。 -
如何优化长列表性能?
解析:- 使用
recycle-view组件(UniApp 内置,实现虚拟列表,只渲染可视区域项); - 分页加载:每次加载部分数据,滚动到底部再加载更多;
- 减少列表项复杂度:避免嵌套过多组件或复杂样式。
- 使用
-
v-if和v-show的使用场景有何不同?如何影响性能?
解析:v-if:条件不满足时销毁组件(移除 DOM),适合切换频率低的场景(如权限控制);v-show:条件不满足时隐藏组件(display: none),适合切换频繁的场景(如标签页)。
性能影响:v-if切换时有更高的初始渲染成本,v-show有更高的初始渲染成本但切换成本低。
-
如何减少小程序端的
setData次数?
解析:小程序端通过setData更新数据,频繁调用会导致性能问题。
优化:- 合并数据更新(如将多次
setData合并为一次); - 避免更新整个对象(只更新变化的属性);
- 使用
this.data临时存储数据,批量更新。
- 合并数据更新(如将多次
-
图片懒加载如何实现?有何作用?
解析:实现:为image组件添加lazy-load="true",仅当图片进入可视区域时加载。
作用:减少初始加载的图片数量,降低带宽消耗,提高页面加载速度。 -
如何优化 App 端的启动速度?
解析:- 减少启动页初始化逻辑(如
onLaunch中避免复杂操作); - 启用预编译(HBuilderX 中勾选 “运行→运行到手机或模拟器→预编译模式”);
- 减小安装包体积(删除无用资源、使用分包);
- 启动页使用原生渲染(nvue 页面)。
- 减少启动页初始化逻辑(如
-
H5 端如何优化首屏加载速度?
解析:- 路由懒加载(
() => import('页面路径')); - 压缩资源(JS/CSS 压缩,图片压缩);
- 使用 CDN 加速静态资源;
- 服务端渲染(SSR)或预渲染(适合静态页面)。
- 路由懒加载(
-
如何避免组件的重复渲染?
解析:- 使用
v-memo(Vue3)缓存组件(仅在依赖数据变化时重新渲染); - 合理设计
key值(列表渲染时,key唯一且稳定); - 拆分组件:将频繁变化的部分拆分为独立组件,减少父组件渲染范围。
- 使用
-
UniApp 中如何使用
keep-alive缓存页面?
解析:在pages.json中为页面配置"style": { "keepAlive": true },缓存页面实例,避免重复创建。
注意:缓存的页面onLoad仅触发一次,onShow每次显示都触发,适合表单页、列表页等需要保留状态的场景。
九、实战与问题排查(10 题)
-
如何调试 UniApp 在不同平台的问题?
解析:- 小程序端:使用对应平台的开发者工具(如微信开发者工具),通过 Console、Sources 面板调试;
- App 端:HBuilderX 连接真机,通过 “运行→显示控制台” 查看日志,或使用
vconsole; - H5 端:浏览器开发者工具(F12)调试。
-
UniApp 项目打包成 App 时,如何配置权限?
解析:在manifest.json的 “App 权限配置” 中勾选所需权限(如相机、定位、存储),或手动编辑permissions字段:json
"app-plus": { "permissions": { "Camera": { "description": "用于拍照上传" }, "Location": { "description": "用于获取位置信息" } } } -
小程序端报 “包体积过大” 如何解决?
解析:- 启用分包加载(拆分代码到分包);
- 压缩图片(使用工具压缩,或改用网络图片);
- 删除无用资源(代码、图片、组件);
- 减少第三方库体积(只引入必要模块)。
-
如何处理接口请求的 token 过期问题?
解析:在请求拦截器中统一处理:javascript
// 请求拦截器 request.interceptors.response.use( (res) => { if (res.data.code === 401) { // token过期 // 清除本地token,跳转到登录页 uni.removeStorageSync('token'); uni.navigateTo({ url: '/pages/login/login' }); return Promise.reject('token过期'); } return res; } ); -
页面跳转后,数据没有及时更新怎么办?
解析:- 检查数据是否通过
this.$set修改(对象 / 数组新增属性需用this.$set触发响应式); - 若使用 Vuex,确认
mutations正确修改state; - 在
onShow中重新获取数据(适合返回页面时刷新)。
- 检查数据是否通过
-
image组件加载失败如何处理?
解析:监听error事件,显示默认图片:html
<image src="/static/img/xxx.png" @error="onImageError" :src="imageUrl" ></image>javascript
data() { return { imageUrl: '/static/img/xxx.png' }; }, methods: { onImageError() { this.imageUrl = '/static/img/default.png'; // 替换为默认图 } } -
如何集成第三方登录(如微信登录)?
解析:- 小程序端:调用
uni.login获取code,传给后端换取用户信息; - App 端:使用
uni.getProvider获取微信登录提供商,调用uni.login:javascript
uni.getProvider({ service: 'oauth', success: (res) => { if (res.provider.includes('weixin')) { uni.login({ provider: 'weixin', success: (loginRes) => { /* 发送code到后端 */ } }); } } });
- 小程序端:调用
-
页面滚动时,导航栏如何实现动态样式(如透明变实色)?
解析:监听页面滚动,根据滚动距离修改导航栏样式:javascript
onPageScroll(e) { const scrollTop = e.scrollTop; this.navBarOpacity = scrollTop > 100 ? 1 : scrollTop / 100; // 透明度从0到1 }在导航栏样式中绑定
opacity:<view :style="{ opacity: navBarOpacity }">导航栏</view>。 -
如何解决小程序端
this指向丢失的问题?
解析:- 使用箭头函数(
() => {})绑定上下文; - 在回调外保存
this(如const that = this;);
示例:
javascript
// 错误:this指向回调函数本身 setTimeout(function() { this.name = 'test'; }, 1000); // 正确:箭头函数 setTimeout(() => { this.name = 'test'; }, 1000); - 使用箭头函数(
-
UniApp 项目上线前需要做哪些检查?
解析:
- 功能测试:验证各平台核心功能(登录、支付、分享等);
- 兼容性测试:不同设备、系统版本、浏览器的适配;
- 性能测试:页面加载速度、操作流畅度;
- 安全检查:接口加密、敏感数据处理(如 token 存储);
- 配置检查:图标、名称、权限、域名白名单等;
- 打包检查:各平台包体积、版本号是否正确。
总结
以上题目覆盖了 UniApp 开发的核心知识点,从基础到进阶,结合了理论和实战场景。面试时不仅要记住答案,更要理解原理和应用场景,尤其是跨平台适配、性能优化等高频考点。实际开发中需多实践,积累调试和问题解决经验,才能更好地应对面试挑战。
更多推荐
所有评论(0)