以下是 UniApp 面试中常见的 100 道题目及解析,涵盖基础概念、生命周期、组件、路由、状态管理、跨平台适配、性能优化等核心知识点,适合面试准备和知识梳理。

一、基础概念(10 题)

  1. 什么是 UniApp?它的核心优势是什么?
    解析:UniApp 是一个使用 Vue.js 开发跨平台应用的框架,可同时构建 iOS、Android、H5、微信小程序等多个平台的应用。
    核心优势:

    • 一套代码多端运行,降低开发成本;
    • 基于 Vue.js 语法,学习成本低;
    • 内置丰富的 API 和组件,兼容各平台特性;
    • 支持原生插件扩展,满足复杂场景需求。
  2. UniApp 与传统原生开发、其他跨平台框架(如 Flutter、React Native)的区别?
    解析:

    • 与原生开发:UniApp 通过中间层转换为各平台代码,开发效率高但性能略低于原生;原生开发需为每个平台单独编码,性能优但成本高。
    • 与 Flutter:Flutter 使用 Dart 语言,自绘 UI,性能接近原生;UniApp 基于 WebView(部分平台),性能略低,但复用 Vue 生态更易上手。
    • 与 React Native:RN 基于 React,通过 JS 桥接原生组件;UniApp 更侧重多端一致性,对小程序支持更友好。
  3. UniApp 支持哪些平台?开发工具是什么?
    解析:支持平台包括:App(iOS/Android)、H5、微信 / 支付宝 / 百度 / 字节跳动 / QQ 等小程序。
    开发工具:推荐使用 HBuilderX(官方工具,内置多端编译、运行、调试功能),也可使用 VS Code 配合 UniApp 插件。

  4. UniApp 的项目结构中,主要目录和文件的作用是什么?
    解析:

    • pages:存放页面组件(每个页面对应一个文件夹,含.vue 文件);
    • static:存放静态资源(图片、字体等,打包时不编译);
    • components:存放自定义组件;
    • unpackage:打包输出目录(各平台编译后的文件);
    • manifest.json:项目配置(应用名称、权限、平台设置等);
    • pages.json:页面路由配置(路径、窗口样式、导航栏等);
    • main.js:入口文件(初始化 Vue 实例);
    • App.vue:应用入口组件(全局生命周期、样式)。
  5. UniApp 的编译原理是什么?
    解析:UniApp 通过 “编译器 + 运行时” 实现跨平台。

    • 编译时:将 Vue 代码转换为各平台的原生代码(如小程序的 wxml/wxss,H5 的 html/css);
    • 运行时:通过适配层(如小程序的逻辑层、H5 的浏览器环境)统一 API 调用。
  6. UniApp 中的manifest.jsonpages.json有什么区别?
    解析:

    • manifest.json:配置应用全局信息(如名称、图标、权限、各平台特有配置),影响应用的打包和运行环境。
    • pages.json:配置页面路由、窗口样式(导航栏、状态栏)、底部 TabBar 等,仅影响页面展示和导航逻辑。
  7. UniApp 中如何引入外部资源(如 JS、CSS、图片)?
    解析:

    • JS:通过import引入(支持相对路径或 npm 包);
    • CSS:在style标签中通过@import引入,或在App.vue中全局引入;
    • 图片:优先放在static目录,使用相对路径(如/static/img/logo.png),小程序端需注意路径是否支持网络图片。
  8. UniApp 支持 Vue 的哪些特性?不支持哪些?
    解析:支持 Vue 的核心特性(如双向绑定、组件化、生命周期、指令、Vuex 等)。
    不支持的特性:

    • 部分 Vue 高级 API(如$nextTick在部分平台有差异);
    • 自定义指令的部分钩子(如update在小程序端可能失效);
    • v-html在小程序端受限(仅支持部分平台)。
  9. UniApp 的版本更新机制是什么?
    解析:

    • App 端:支持热更新(通过uni.getUpdateManager检测,下载 wgt 包更新)和整包更新(跳转到应用商店);
    • 小程序端:依赖各平台的小程序更新机制(用户下次启动时自动更新);
    • H5 端:需手动部署新版本覆盖旧文件。
  10. 什么是 UniModule?它的作用是什么?
    解析:UniModule 是 UniApp 的扩展模块(如地图、支付、推送等),通过 HBuilderX 集成,无需手动配置原生代码,简化跨平台功能开发。例如:uni-pay模块提供统一的支付 API,适配各平台支付方式。

二、生命周期(10 题)

  1. UniApp 的应用生命周期有哪些?请说明各自的触发时机。
    解析:应用生命周期定义在App.vue中,包括:

    • onLaunch:应用初始化完成时触发(全局只触发一次);
    • onShow:应用启动或从后台进入前台时触发;
    • onHide:应用从前台进入后台时触发;
    • onError:应用发生错误时触发(如 API 调用失败);
    • onUniNViewMessage:接收 nvue 页面发送的消息时触发(仅 App 端)。
  2. UniApp 的页面生命周期有哪些?与 Vue 的生命周期有何区别?
    解析:页面生命周期定义在页面组件中,核心包括:

    • onLoad:页面加载时触发(接收路由参数);
    • onShow:页面显示 / 切入前台时触发;
    • onReady:页面初次渲染完成时触发(可操作 DOM);
    • onHide:页面隐藏 / 切入后台时触发;
    • onUnload:页面卸载时触发;
    • onPullDownRefresh:下拉刷新时触发;
    • onReachBottom:上拉触底时触发。
      区别:UniApp 在 Vue 生命周期(如createdmounted)基础上新增了页面特有生命周期(如onLoadonPullDownRefresh),更适配跨平台页面交互。
  3. onLoadcreated的触发顺序是什么?使用场景有何不同?
    解析:触发顺序为created(Vue 生命周期)→ onLoad(UniApp 页面生命周期)。

    • created:页面实例创建时触发,此时还未接收路由参数,适合初始化数据(不依赖路由参数);
    • onLoad:页面加载完成,可获取路由参数(options),适合根据参数请求数据。
  4. 页面切换时,生命周期的执行顺序是怎样的?(如 A 页面跳转到 B 页面)
    解析:A 页面onHide → B 页面onLoad → B 页面onShow → B 页面onReady
    (若 A 页面被卸载,如使用uni.redirectTo,则 A 页面会触发onUnload

  5. onReadymounted的区别是什么?
    解析:

    • mounted:Vue 生命周期,DOM 挂载完成,但可能未完成样式渲染(如小程序端);
    • onReady:UniApp 页面生命周期,页面初次渲染完成(包括样式),更适合进行 DOM 操作(如获取元素尺寸)。
  6. 如何监听页面的下拉刷新和上拉触底?
    解析:

    • 下拉刷新:在pages.json中配置页面的"enablePullDownRefresh": true,然后在页面中实现onPullDownRefresh方法,完成后调用uni.stopPullDownRefresh()停止刷新;
    • 上拉触底:在pages.json中配置"onReachBottomDistance": 50(触发距离),然后实现onReachBottom方法。
  7. 应用从前台进入后台时,会触发哪些生命周期?
    解析:首先触发当前页面的onHide,然后触发应用的onHide

  8. onErrortry/catch的区别是什么?
    解析:

    • onError:全局捕获应用级错误(如 API 调用失败、组件渲染错误),无法捕获异步错误(如setTimeout内的错误);
    • try/catch:局部捕获代码块中的错误(同步或异步),更灵活,适合处理已知可能出错的逻辑(如接口请求)。
  9. nvue 页面的生命周期与 vue 页面有何不同?
    解析:nvue(原生渲染)页面仅支持部分生命周期,如onLoadonShowonHideonUnload,不支持createdmounted等 Vue 生命周期(因 nvue 基于 weex 引擎,渲染机制不同)。

  10. 如何在页面中监听应用的生命周期(如切后台)?
    解析:通过uni.onAppShowuni.onAppHide等 API 在页面中注册监听,示例:

    javascript

    onLoad() {
      this.showListener = uni.onAppShow(() => { console.log('应用切入前台') });
      this.hideListener = uni.onAppHide(() => { console.log('应用切入后台') });
    },
    onUnload() {
      this.showListener(); // 移除监听
      this.hideListener();
    }
    

三、组件与样式(15 题)

  1. UniApp 的内置组件有哪些?请列举 5 个并说明用途。
    解析:

    • view:基础容器(类似 div),用于布局;
    • text:文本容器(支持长按复制,仅包裹文本);
    • button:按钮组件(支持默认、primary、warn 等样式,可绑定点击事件);
    • image:图片组件(支持懒加载、模式裁剪,需注意路径);
    • scroll-view:滚动容器(支持横向 / 纵向滚动,下拉刷新)。
  2. 自定义组件的注册方式有哪些?区别是什么?
    解析:

    • 局部注册:在页面的components选项中注册,仅当前页面可用;
    • 全局注册:在main.js中通过Vue.component()注册,所有页面可用;
    • easycom 组件规范:将组件放在components目录,按组件名/组件名.vue命名,无需注册可直接使用(推荐)。
  3. 如何在父组件和子组件之间传递数据?
    解析:

    • 父传子:通过props定义属性,父组件在引用子组件时传递数据;
      子组件:props: { title: String },父组件:<child :title="msg"></child>
    • 子传父:通过$emit触发事件,父组件监听事件接收数据;
      子组件:this.$emit('change', data),父组件:<child @change="handleChange"></child>
  4. viewdivtextspan的区别是什么?
    解析:

    • view vs divview是 UniApp 跨平台的容器组件,在小程序端编译为view标签,H5 端编译为div,支持各平台统一的样式和事件;div仅在 H5 端有效,小程序端不支持。
    • text vs spantext支持跨平台文本处理(如selectable属性开启长按复制),span仅 H5 端有效,小程序端不识别。
  5. image组件的mode属性有哪些值?分别代表什么?
    解析:mode用于指定图片裁剪 / 缩放模式,常用值:

    • scaleToFill:拉伸填充(可能变形);
    • aspectFit:等比缩放,长边适配(显示完整);
    • aspectFill:等比缩放,短边适配(可能裁剪);
    • widthFix:宽度固定,高度自适应;
    • heightFix:高度固定,宽度自适应。
  6. UniApp 中如何使用全局样式?
    解析:在App.vuestyle标签中编写样式(不加scoped),即可全局生效。例如:

    css

    /* App.vue */
    <style>
      .global-color { color: #f00; }
    </style>
    
  7. scoped样式的作用是什么?如何让子组件使用父组件的scoped样式?
    解析:scoped使样式仅作用于当前组件(通过添加属性选择器实现),避免样式污染。
    让子组件使用父组件样式:

    • 父组件中使用::v-deep穿透scoped(Vue2)或:deep()(Vue3);
      示例:::v-deep .child-class { color: red; }
  8. UniApp 支持哪些 CSS 预处理器?如何配置?
    解析:支持 Sass、Less、Stylus。配置方式:

    • 在 HBuilderX 中新建项目时勾选预处理器;
    • 已创建项目:在HBuilderX的 “工具→插件安装” 中安装对应预处理器插件,然后在style标签中指定lang(如<style lang="scss">)。
  9. 如何实现不同平台的样式适配?
    解析:

    • 条件编译:使用/* #ifdef 平台 *//* #endif */包裹平台特有样式;
      示例:

      css

      /* #ifdef H5 */
      .box { width: 100%; }
      /* #endif */
      /* #ifdef MP-WEIXIN */
      .box { width: 750rpx; }
      /* #endif */
      
    • 使用rpx单位(自动适配不同屏幕宽度,1rpx = 屏幕宽度 / 750)。
  10. scroll-view如何实现横向滚动?
    解析:

    1. 设置scroll-viewscroll-xtrue
    2. 子元素需设置display: inline-block(避免换行);
    3. 父容器设置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>
    
  11. 如何自定义导航栏?
    解析:

    1. pages.json中配置页面的"navigationStyle": "custom"(隐藏默认导航栏);
    2. 在页面中自定义导航栏组件(包含标题、返回按钮等);
    3. 如需适配状态栏高度,可通过uni.getSystemInfoSync().statusBarHeight获取高度。
  12. button组件的open-type属性有哪些常用值?
    解析:open-type用于调用小程序原生能力,常用值:

    • contact:打开客服会话;
    • share:触发分享;
    • getUserInfo:获取用户信息(微信小程序旧版,新版用getUserProfile);
    • launchApp:打开 APP(需配置关联)。
  13. 如何实现组件的懒加载?
    解析:在pages.json中为页面配置"lazyCodeLoading": "requiredComponents",仅加载页面所需组件,减少初始包体积。

  14. slot插槽在 UniApp 中的使用场景是什么?如何使用具名插槽?
    解析:slot用于父组件向子组件插入内容,适合组件复用(如卡片、弹窗)。
    具名插槽使用:

    • 子组件:<slot name="header"></slot>
    • 父组件:<template #header><view>标题</view></template>(Vue3 语法)或<template slot="header">(Vue2)。
  15. nvue 页面的样式与 vue 页面有何不同?
    解析:nvue 页面使用 weex 的样式规范,仅支持部分 CSS 属性:

    • 必须使用flex布局(默认不支持流式布局);
    • 不支持*选择器、scoped
    • 单位仅支持px(不支持rpx,需手动适配)。

四、路由与导航(10 题)

  1. UniApp 的路由模式有哪些?如何配置?
    解析:支持两种路由模式(在pages.jsonglobalStyle中配置):

    • hash模式(默认):URL 带#,H5 端兼容所有浏览器;
    • history模式:URL 无#,需后端配置支持(否则刷新 404),仅 H5 端有效。
  2. 路由跳转的 API 有哪些?区别是什么?
    解析:

    • uni.navigateTo:保留当前页面,跳转到新页面(栈深限制,小程序端最多 10 层);
    • uni.redirectTo:关闭当前页面,跳转到新页面;
    • uni.reLaunch:关闭所有页面,跳转到新页面;
    • uni.switchTab:跳转到 TabBar 页面(必须在pages.jsontabBar中配置);
    • uni.navigateBack:返回上一页面(可指定返回层数,delta参数)。
  3. 如何传递路由参数?接收方式是什么?
    解析:

    • 传递:在跳转 URL 后拼接参数(如/pages/detail?id=1&name=test);
    • 接收:在目标页面的onLoad生命周期中通过options参数获取:

      javascript

      onLoad(options) {
        console.log(options.id); // 1
        console.log(options.name); // test
      }
      
  4. uni.navigateTouni.switchTab的使用限制是什么?
    解析:

    • uni.navigateTo:不能跳转到 TabBar 页面(需用switchTab);
    • uni.switchTab:不能携带参数(URL 后拼接的参数会被忽略),且只能跳转到tabBar配置中的页面。
  5. 如何实现 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": "我的" }
      ]
    }
    
     

    核心属性:colorselectedColorlist(Tab 项配置,含路径、文本、图标)。

  6. 路由拦截如何实现?
    解析:UniApp 无内置路由拦截,需手动封装路由 API 实现:

    javascript

    // 封装navigateTo
    function myNavigateTo(url) {
      // 拦截逻辑(如登录判断)
      if (needLogin && !isLogin) {
        uni.navigateTo({ url: '/pages/login/login' });
        return;
      }
      uni.navigateTo({ url });
    }
    
  7. H5 端路由刷新后参数丢失怎么办?
    解析:uni.navigateTo的参数通过 URL 传递,H5 端刷新后onLoadoptions会丢失。解决方式:

    • 使用uni.setStorageSync将参数存入本地存储,刷新后读取;
    • 改用history模式,参数通过query传递(刷新后 URL 保留参数)。
  8. 如何获取当前页面的路由信息?
    解析:通过getCurrentPages()获取页面栈,栈顶元素为当前页面:

    javascript

    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    console.log(currentPage.route); // 当前页面路径(如pages/home/home)
    console.log(currentPage.options); // 当前页面参数
    
  9. 小程序端路由栈的最大深度是多少?如何处理超过限制的情况?
    解析:小程序端路由栈最大深度为 10 层(navigateTo累计调用 10 次后无法再跳转)。
    处理方式:

    • 合理使用redirectTo(关闭当前页)或reLaunch(关闭所有页);
    • 对于多级页面,跳转时关闭中间页面(如 A→B→C,从 C 返回 A 时用reLaunch)。
  10. 如何实现页面的反向传值(如 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)。

五、API 与数据请求(15 题)

  1. UniApp 的 API 与小程序 API 有何关系?
    解析:UniApp 的 API(uni.xxx)是对各平台 API 的封装,如uni.request对应微信小程序的wx.request、H5 的fetch等,实现跨平台统一调用。大部分 API 参数与小程序 API 兼容,但部分平台特有 API 需用条件编译。

  2. uni.request的使用步骤是什么?如何处理请求成功 / 失败?
    解析:步骤:

    1. 调用uni.request,传入urlmethoddata等参数;
    2. 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('请求完成'); }
    });
    
  3. 如何封装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(); }
        });
      });
    }
    
  4. UniApp 中如何处理跨域问题?
    解析:

    • H5 端:在manifest.json的 H5 配置中设置"devServer": { "proxy": { "/api": { "target": "https://xxx", "changeOrigin": true } } }(开发环境代理);生产环境需后端配置CORS
    • 小程序 / App 端:无跨域限制(因小程序通过后端域名校验,App 端直接请求)。
  5. uni.setStorageSyncuni.setStorage的区别是什么?使用场景有哪些?
    解析:

    • uni.setStorageSync:同步存储(阻塞后续代码),语法简单,适合少量数据;
    • uni.setStorage:异步存储(非阻塞),通过回调处理结果,适合大量数据。
      使用场景:存储用户信息、缓存列表数据、记住密码等。
  6. 如何获取用户信息?不同平台有何差异?
    解析:

    • 小程序端:微信小程序需通过uni.getUserProfile(需用户授权)获取,返回userInfo
    • App 端:可通过uni.getProvider获取第三方登录(如微信、QQ),或调用原生 SDK;
    • H5 端:依赖浏览器或第三方登录(如 OAuth),无统一 API。
  7. uni.showToastuni.showModal的区别是什么?
    解析:

    • uni.showToast:轻提示(如成功、加载中),默认 3 秒后消失,无交互;
    • uni.showModal:模态弹窗(含标题、内容、确认 / 取消按钮),需用户操作后关闭,适合询问用户(如删除确认)。
  8. 如何实现图片上传?
    解析:使用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); }
        });
      }
    });
    
  9. uni.getSystemInfoSync能获取哪些信息?有何用途?
    解析:获取设备信息,如屏幕宽高、状态栏高度、设备型号、操作系统等。
    用途:适配不同屏幕(如动态计算元素尺寸)、判断设备类型(如 iOS/Android)、处理状态栏高度。

  10. 如何实现扫码功能?
    解析:使用uni.scanCode

    javascript

    uni.scanCode({
      success: (res) => {
        console.log('扫码结果', res.result); // 二维码/条形码内容
      }
    });
    
     

    注意:App 端需配置相机权限,H5 端仅部分浏览器支持。

  11. UniApp 中如何调用原生插件?
    解析:

    1. 在 HBuilderX 中导入原生插件(本地插件或市场插件);
    2. manifest.json中配置插件权限;
    3. 通过uni.requireNativePlugin('插件ID')获取插件实例,调用其方法。
  12. uni.navigateTouni.openURL的区别是什么?
    解析:

    • uni.navigateTo:跳转到应用内的页面(路由跳转);
    • uni.openURL:打开外部链接(如网页、其他 App 的 Scheme),需平台支持(如小程序需配置业务域名,App 端需配置白名单)。
  13. 如何监听网络状态变化?
    解析:使用uni.onNetworkStatusChange注册监听:

    javascript

    uni.onNetworkStatusChange((res) => {
      console.log('是否联网', res.isConnected);
      console.log('网络类型', res.networkType); // wifi/2g/3g/4g/5g/unknown
    });
    
  14. 小程序端uni.request的超时时间如何设置?默认是多少?
    解析:通过timeout参数设置(单位 ms),默认超时时间为 60000ms(1 分钟)。
    示例:uni.request({ url: 'xxx', timeout: 30000 })

  15. 如何实现应用内的分享功能?
    解析:

    • 小程序端:通过buttonopen-type="share"触发,在页面的onShareAppMessage中配置分享内容;
    • App 端:调用uni.shareAPI,配置分享平台(微信、QQ 等)和内容;
      示例(小程序):

    javascript

    onShareAppMessage() {
      return {
        title: '分享标题',
        path: '/pages/home/home?id=1', // 分享路径
        imageUrl: '/static/share.png'
      };
    }
    

六、状态管理与全局数据(10 题)

  1. UniApp 中如何实现全局状态管理?
    解析:常用方式:

    • Vuex(或 Pinia):适合复杂应用,跨组件共享状态;
    • 全局变量:在main.js中挂载到Vue.prototype(如Vue.prototype.$global = { user: null });
    • 本地存储:uni.setStorageSync存储数据,跨页面读取(适合持久化数据)。
  2. Vuex 的核心概念有哪些?如何在 UniApp 中使用 Vuex?
    解析:核心概念:state(状态)、mutations(同步修改状态)、actions(异步操作)、getters(计算属性)、modules(模块化)。
    使用步骤:

    1. 创建store/index.js,定义 Vuex 实例;
    2. main.js中导入并挂载到 Vue 实例;
    3. 组件中通过this.$store访问。
  3. Vuex 中mutationsactions的区别是什么?
    解析:

    • mutations:只能同步操作,是修改state的唯一途径(通过commit触发);
    • actions:可包含异步操作(如接口请求),通过dispatch触发,最终通过commit调用mutations修改state
  4. 如何在组件中监听 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); }
    }
    
  5. 全局变量和 Vuex 的使用场景有何不同?
    解析:

    • 全局变量:适合存储简单、无需响应式的数据(如配置信息、临时标识),修改后需手动刷新组件;
    • Vuex:适合存储复杂、需要响应式的数据(如用户信息、购物车),状态变化时自动更新依赖组件。
  6. 如何实现跨页面的数据共享(非 Vuex)?
    解析:

    • 方式 1:通过getCurrentPages()获取目标页面实例,直接修改数据;
    • 方式 2:使用事件总线uni.$emit/uni.$on(全局事件);
    • 方式 3:本地存储(uni.setStorageSync)+ 页面onShow时读取。
  7. Pinia 与 Vuex 相比有哪些优势?如何在 UniApp 中使用 Pinia?
    解析:Pinia 优势:

    • 简化 API(无mutations,直接在actions中修改状态);
    • 支持 TypeScript,类型推断更友好;
    • 无需嵌套modules,天然支持模块化。
      使用:通过 npm 安装pinia,创建store实例并挂载到 Vue,组件中通过useStore访问。
  8. 如何避免 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));
    });
    
  9. Vue.prototype挂载的全局方法,在 nvue 页面中能否使用?
    解析:不能。nvue 页面基于 weex 引擎,不支持Vue.prototype挂载的属性 / 方法,需通过globalData(App.vue 中定义)或本地存储共享。

  10. 如何在 App.vue 中定义全局数据,并在页面中访问?
    解析:在App.vueglobalData中定义:

    javascript

    // App.vue
    export default {
      globalData: {
        appName: 'MyApp'
      }
    }
    
     

    页面中访问:

    • Vue 页面:getApp().globalData.appName
    • nvue 页面:this.$getAppWebview().getApp().globalData.appName

七、跨平台适配与条件编译(10 题)

  1. 什么是条件编译?UniApp 的条件编译标识有哪些?
    解析:条件编译是指根据不同平台编译不同代码,实现平台特有逻辑。
    常用标识:

    • #ifdef MP-WEIXIN:微信小程序;
    • #ifdef H5:H5;
    • #ifdef APP-PLUS:App;
    • #ifdef MP-ALIPAY:支付宝小程序;
    • #ifndef 平台:排除指定平台(如#ifndef H5表示非 H5 平台)。
  2. 条件编译的使用场景有哪些?请举例说明。
    解析:场景:

    • 平台特有 API(如微信小程序的wx.getWeRunData);
    • 样式差异(如 H5 需滚动条,小程序不需要);
    • 功能差异(如 App 支持推送,H5 不支持)。
      示例(JS 条件编译):

    javascript

    // #ifdef MP-WEIXIN
    console.log('微信小程序');
    // #endif
    // #ifdef H5
    console.log('H5');
    // #endif
    
  3. 如何处理不同平台的 API 差异?
    解析:

    • 优先使用uni.xxx统一 API;
    • 平台特有 API 用条件编译包裹;
    • 封装适配层(如将不同平台的支付 API 封装为统一方法)。
  4. H5 端与小程序端的样式差异主要有哪些?
    解析:

    • 单位:H5 支持px/rem/rpx,小程序推荐rpx
    • 布局:H5 支持float/position,小程序更依赖flex
    • 选择器:H5 支持复杂选择器(如div > p),小程序限制较多;
    • 滚动:H5 可通过overflow: auto滚动,小程序需用scroll-view
  5. App 端如何适配 iOS 和 Android 的差异?
    解析:

    • 条件编译:#ifdef IOS#ifdef ANDROID
    • 原生插件:使用平台特有插件(如 iOS 的内购、Android 的应用内支付);
    • 样式:iOS 导航栏高度与 Android 不同,需动态计算(通过uni.getSystemInfoSync())。
  6. 小程序端的分包加载是什么?如何配置?
    解析:分包加载是将小程序代码拆分为主包和分包,用户进入对应页面时才下载分包,减少初始加载时间。
    配置(pages.json):

    json

    "subPackages": [
      {
        "root": "pages/sub", // 分包根目录
        "pages": [ { "path": "list/list" } ] // 分包页面
      }
    ]
    
  7. H5 端如何适配不同屏幕尺寸?
    解析:

    • 使用rpx%单位;
    • 媒体查询(@media)适配不同宽度设备;
    • 弹性布局(flex)和网格布局(grid);
    • 禁止页面缩放(meta标签:<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">)。
  8. UniApp 中如何处理小程序端的域名校验?
    解析:小程序端请求的域名需在对应平台的开发者后台配置(如微信小程序需在 “开发→开发设置→服务器域名” 中添加),否则会报 “域名不在许可列表中” 错误。开发环境可勾选 “不校验合法域名”(仅调试用)。

  9. nvue 页面和 vue 页面如何混合使用?
    解析:

    • App 端支持 nvue 和 vue 页面共存,通过路由跳转互通;
    • 注意:nvue 页面不能引用 vue 组件,反之亦然;
    • 数据传递通过路由参数或全局状态管理。
  10. 如何在 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 题)

  1. UniApp 的性能优化有哪些常用方法?
    解析:

    • 减少渲染层级:避免嵌套过深(建议不超过 5 层);
    • 图片优化:使用合适尺寸、懒加载(image组件的lazy-load)、WebP 格式;
    • 合理使用组件:复用组件,避免频繁创建 / 销毁;
    • 数据处理:减少data中的冗余数据,避免频繁修改data
    • 分包加载:小程序端拆分主包,减少初始下载体积;
    • 避免不必要的渲染:使用v-show替代v-if(频繁切换场景)。
  2. 为什么要避免在onShow中请求数据?如何优化?
    解析:onShow在页面每次显示时触发(如返回页面),频繁请求会浪费资源。
    优化:在onLoad中请求(仅加载一次),或通过状态管理缓存数据,onShow中判断是否需要重新请求。

  3. 如何优化长列表性能?
    解析:

    • 使用recycle-view组件(UniApp 内置,实现虚拟列表,只渲染可视区域项);
    • 分页加载:每次加载部分数据,滚动到底部再加载更多;
    • 减少列表项复杂度:避免嵌套过多组件或复杂样式。
  4. v-ifv-show的使用场景有何不同?如何影响性能?
    解析:

    • v-if:条件不满足时销毁组件(移除 DOM),适合切换频率低的场景(如权限控制);
    • v-show:条件不满足时隐藏组件(display: none),适合切换频繁的场景(如标签页)。
      性能影响:v-if切换时有更高的初始渲染成本,v-show有更高的初始渲染成本但切换成本低。
  5. 如何减少小程序端的setData次数?
    解析:小程序端通过setData更新数据,频繁调用会导致性能问题。
    优化:

    • 合并数据更新(如将多次setData合并为一次);
    • 避免更新整个对象(只更新变化的属性);
    • 使用this.data临时存储数据,批量更新。
  6. 图片懒加载如何实现?有何作用?
    解析:实现:为image组件添加lazy-load="true",仅当图片进入可视区域时加载。
    作用:减少初始加载的图片数量,降低带宽消耗,提高页面加载速度。

  7. 如何优化 App 端的启动速度?
    解析:

    • 减少启动页初始化逻辑(如onLaunch中避免复杂操作);
    • 启用预编译(HBuilderX 中勾选 “运行→运行到手机或模拟器→预编译模式”);
    • 减小安装包体积(删除无用资源、使用分包);
    • 启动页使用原生渲染(nvue 页面)。
  8. H5 端如何优化首屏加载速度?
    解析:

    • 路由懒加载(() => import('页面路径'));
    • 压缩资源(JS/CSS 压缩,图片压缩);
    • 使用 CDN 加速静态资源;
    • 服务端渲染(SSR)或预渲染(适合静态页面)。
  9. 如何避免组件的重复渲染?
    解析:

    • 使用v-memo(Vue3)缓存组件(仅在依赖数据变化时重新渲染);
    • 合理设计key值(列表渲染时,key唯一且稳定);
    • 拆分组件:将频繁变化的部分拆分为独立组件,减少父组件渲染范围。
  10. UniApp 中如何使用keep-alive缓存页面?
    解析:在pages.json中为页面配置"style": { "keepAlive": true },缓存页面实例,避免重复创建。
    注意:缓存的页面onLoad仅触发一次,onShow每次显示都触发,适合表单页、列表页等需要保留状态的场景。

九、实战与问题排查(10 题)

  1. 如何调试 UniApp 在不同平台的问题?
    解析:

    • 小程序端:使用对应平台的开发者工具(如微信开发者工具),通过 Console、Sources 面板调试;
    • App 端:HBuilderX 连接真机,通过 “运行→显示控制台” 查看日志,或使用vconsole
    • H5 端:浏览器开发者工具(F12)调试。
  2. UniApp 项目打包成 App 时,如何配置权限?
    解析:在manifest.json的 “App 权限配置” 中勾选所需权限(如相机、定位、存储),或手动编辑permissions字段:

    json

    "app-plus": {
      "permissions": {
        "Camera": { "description": "用于拍照上传" },
        "Location": { "description": "用于获取位置信息" }
      }
    }
    
  3. 小程序端报 “包体积过大” 如何解决?
    解析:

    • 启用分包加载(拆分代码到分包);
    • 压缩图片(使用工具压缩,或改用网络图片);
    • 删除无用资源(代码、图片、组件);
    • 减少第三方库体积(只引入必要模块)。
  4. 如何处理接口请求的 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;
      }
    );
    
  5. 页面跳转后,数据没有及时更新怎么办?
    解析:

    • 检查数据是否通过this.$set修改(对象 / 数组新增属性需用this.$set触发响应式);
    • 若使用 Vuex,确认mutations正确修改state
    • onShow中重新获取数据(适合返回页面时刷新)。
  6. 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'; // 替换为默认图
      }
    }
    
  7. 如何集成第三方登录(如微信登录)?
    解析:

    • 小程序端:调用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到后端 */ }
            });
          }
        }
      });
      
  8. 页面滚动时,导航栏如何实现动态样式(如透明变实色)?
    解析:监听页面滚动,根据滚动距离修改导航栏样式:

    javascript

    onPageScroll(e) {
      const scrollTop = e.scrollTop;
      this.navBarOpacity = scrollTop > 100 ? 1 : scrollTop / 100; // 透明度从0到1
    }
    
     

    在导航栏样式中绑定opacity<view :style="{ opacity: navBarOpacity }">导航栏</view>

  9. 如何解决小程序端this指向丢失的问题?
    解析:

    • 使用箭头函数(() => {})绑定上下文;
    • 在回调外保存this(如const that = this;);
      示例:

    javascript

    // 错误:this指向回调函数本身
    setTimeout(function() { this.name = 'test'; }, 1000);
    // 正确:箭头函数
    setTimeout(() => { this.name = 'test'; }, 1000);
    
  10. UniApp 项目上线前需要做哪些检查?
    解析:

  • 功能测试:验证各平台核心功能(登录、支付、分享等);
  • 兼容性测试:不同设备、系统版本、浏览器的适配;
  • 性能测试:页面加载速度、操作流畅度;
  • 安全检查:接口加密、敏感数据处理(如 token 存储);
  • 配置检查:图标、名称、权限、域名白名单等;
  • 打包检查:各平台包体积、版本号是否正确。

总结

以上题目覆盖了 UniApp 开发的核心知识点,从基础到进阶,结合了理论和实战场景。面试时不仅要记住答案,更要理解原理和应用场景,尤其是跨平台适配、性能优化等高频考点。实际开发中需多实践,积累调试和问题解决经验,才能更好地应对面试挑战。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐