目录
Vue,小程序、uniapp常用的组件有哪些,配套的组件库有哪些?
[一、Vue 相关面试题](#一、Vue 相关面试题)
[1、Vue 的核心特性是什么?](#1、Vue 的核心特性是什么?)
[2、Vue 2 和 Vue 3 的主要区别有哪些?](#2、Vue 2 和 Vue 3 的主要区别有哪些?)
[3、什么是 MVVM 模式?Vue 是如何实现它的?](#3、什么是 MVVM 模式?Vue 是如何实现它的?)
[4、解释 Vue 的生命周期钩子函数及其执行顺序?](#4、解释 Vue 的生命周期钩子函数及其执行顺序?)
[5、v-if 和 v-show 的区别是什么?](#5、v-if 和 v-show 的区别是什么?)
[v-if 和 v-show 对比表](#v-if 和 v-show 对比表)
[1、Vue 组件间通信的方式有哪些?](#1、Vue 组件间通信的方式有哪些?)
[4、Vuex |Pinia的核心概念是什么?](#4、Vuex |Pinia的核心概念是什么?)
[5、什么时候应该使用 Vuex|PInia?](#5、什么时候应该使用 Vuex|PInia?)
[4、小程序的 WXSS 和 CSS 有什么区别?](#4、小程序的 WXSS 和 CSS 有什么区别?)
[5、小程序的双向绑定和 Vue 有什么不同?](#5、小程序的双向绑定和 Vue 有什么不同?)
[1. 数据流控制逻辑](#1. 数据流控制逻辑)
[2. 语法设计差异](#2. 语法设计差异)
[3. 底层实现原理](#3. 底层实现原理)
[4、小程序如何调用微信原生 API?](#4、小程序如何调用微信原生 API?)
[三、Uniapp 面试题](#三、Uniapp 面试题)
[1、Uniapp 是什么?它有什么优势?](#1、Uniapp 是什么?它有什么优势?)
[2、Uniapp 如何实现多端兼容?](#2、Uniapp 如何实现多端兼容?)
[3、Uniapp 的生命周期有哪些?](#3、Uniapp 的生命周期有哪些?)
[4、Uniapp 如何调用原生功能?](#4、Uniapp 如何调用原生功能?)
[5、Uniapp 的页面路由与微信小程序有什么不同?](#5、Uniapp 的页面路由与微信小程序有什么不同?)
[1、Uniapp 如何实现条件编译?](#1、Uniapp 如何实现条件编译?)
[2、Uniapp 如何优化多端应用的性能?](#2、Uniapp 如何优化多端应用的性能?)
[3、Uniapp 如何实现原生插件开发?](#3、Uniapp 如何实现原生插件开发?)
[4、Uniapp 如何处理多端样式兼容问题?](#4、Uniapp 如何处理多端样式兼容问题?)
[5、Uniapp 如何实现热更新?](#5、Uniapp 如何实现热更新?)
[1、Uniapp 如何实现微信登录?](#1、Uniapp 如何实现微信登录?)
[2、Uniapp 如何实现支付功能?](#2、Uniapp 如何实现支付功能?)
[3、Uniapp 如何实现消息推送?](#3、Uniapp 如何实现消息推送?)
[4、Uniapp 如何适配不同屏幕尺寸?](#4、Uniapp 如何适配不同屏幕尺寸?)
[5、Uniapp 如何打包发布到不同平台?](#5、Uniapp 如何打包发布到不同平台?)
[1、Vue、微信小程序和 Uniapp 在数据绑定方面的异同](#1、Vue、微信小程序和 Uniapp 在数据绑定方面的异同)
[2、如何将 Vue 项目迁移到 Uniapp?](#2、如何将 Vue 项目迁移到 Uniapp?)
[3、Vue 组件和小程序/Uniapp 组件的区别](#3、Vue 组件和小程序/Uniapp 组件的区别)
[7、H5、小程序和 App 开发的主要区别是什么?](#7、H5、小程序和 App 开发的主要区别是什么?)
[9、你如何处理不同平台的 API 差异?](#9、你如何处理不同平台的 API 差异?)
[1、你做过的最复杂的 Vue/小程序/Uniapp 项目是什么?遇到了什么挑战?](#1、你做过的最复杂的 Vue/小程序/Uniapp 项目是什么?遇到了什么挑战?)
Vue,小程序、uniapp常用的组件有哪些,配套的组件库有哪些?
Vue
- 常用组件:表单组件、表格组件、弹窗组件、导航菜单、分页组件
- 组件库:Element UI、Ant Design Vue、Vant、iView
微信小程序
- 常用组件:视图容器、基础内容、表单组件、导航、媒体组件
- 组件库:WeUI、Vant Weapp、MinUI、Wux Weapp
Uniapp
- 常用组件:基础组件(view/text/button)、表单组件、媒体组件、地图
- 组件库:uni-ui、uView、ColorUI
框架/平台 | 常用内置组件 | 常用第三方组件库 | 说明 |
---|---|---|---|
Vue | - <router-view> - <transition> - <keep-alive> - <slot> |
1. Element UI (桌面端) 2. Ant Design Vue (桌面端) 3. Vant (移动端) 4. Naive UI (现代 UI) 5. Quasar (全平台) | Vue 的组件库生态丰富,根据项目类型(桌面/移动)选择不同的库。 |
微信小程序 | - <view> - <text> - <button> - <scroll-view> - <swiper> |
1. WeUI (官方风格) 2. Vant Weapp (移动端) 3. Lin UI 4. Wux Weapp 5. MinUI | 小程序原生组件以基础功能为主,第三方库增强交互和样式。 |
Uniapp | - <view> - <uni-list> - <uni-swiper> - <uni-icons> |
1. Uni UI (官方扩展组件) 2. uView UI (高集成度) 3. ColorUI (视觉风格) 4. FirstUI 5. Vant Uni (适配版) | Uniapp 兼容 Vue 和小程序语法,组件库需支持多端(H5/小程序/App)。 |
Vue,小程序、uniapp如何进行路由跳转?
Vue
// 声明式导航
<router-link to="/path"></router-link>
// 编程式导航
this.$router.push('/path')
this.$router.replace('/path')
微信小程序
// 保留当前页面跳转
wx.navigateTo({url: '/page/path'})
// 关闭当前页面跳转
wx.redirectTo({url: '/page/path'})
// 返回
wx.navigateBack()
Uniapp
// 类似小程序API
uni.navigateTo({url: '/pages/path'})
uni.redirectTo({url: '/pages/path'})
// 类似Vue方式
<navigator url="/pages/path"></navigator>
面试回答
在 Vue 中,我们使用 vue-router
插件提供的 this.$router.push()
或 <router-link>
标签来进行路由跳转;而在微信小程序中,则是通过 wx.navigateTo()
等 API 实现页面间的导航;UniApp 结合了两者的优势,既可以通过类似 Vue 的 $router.push()
方法,也可以使用 uni.navigateTo()
等跨平台 API 来完成路由跳转,同时还支持条件编译来处理平台特定的跳转需求。
一、Vue 中的路由跳转
- 使用 Vue Router
-
安装 Vue Router :首先需要安装
vue-router
,并通过Vue.use(VueRouter)
来注册插件。 -
定义路由:在路由配置文件中定义路径与组件的映射关系。
-
编程式导航
-
使用
this.$router.push(location)
方法进行跳转,其中location
可以是一个字符串路径或一个描述目标位置的对象。 -
示例(文字描述):
调用
this.$router.push('/about')
进行跳转到/about
页面;或者使用对象形式this.$router.push({ path: '/about', query: { id: 123 }})
,携带参数跳转。 -
this.$router.replace(location)
类似于push
,但它不会留下历史记录。 -
this.$router.go(n)
按照当前历史记录前进或后退 n 步。
-
-
声明式导航
-
在模板中使用
<router-link>
标签来进行导航。 -
示例(文字描述):
使用
<router-link to="/about">About</router-link>
创建一个链接,点击时会跳转到/about
页面。
-
二、微信小程序中的路由跳转
- 使用 wx API
-
页面跳转
-
使用
wx.navigateTo()
方法跳转至应用内某个页面,并保留当前页面。 -
示例(文字描述):
调用
wx.navigateTo({ url: '/pages/detail/detail?id=1' })
跳转到detail
页面并传递参数id=1
。 -
使用
wx.redirectTo()
方法关闭当前页面,跳转到应用内的某个页面。 -
使用
wx.switchTab()
方法跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。 -
使用
wx.navigateBack()
方法返回上一页或多页。
-
- 页面栈管理
-
微信小程序维护了一个页面栈,
wx.navigateTo()
会将新页面压入栈顶,而wx.navigateBack()
则是从栈顶弹出页面。 -
可以通过
getCurrentPages()
获取当前页面栈的信息,了解当前处于哪个页面。
三、UniApp 中的路由跳转
- 兼容 Vue 和小程序的路由
-
基于 Vue Router 的方式
-
UniApp 支持 Vue Router 的大部分特性,可以像在 Vue 项目中一样使用
this.$router.push()
等方法进行路由跳转。 -
示例(文字描述):
调用
this.$router.push({ path: '/pages/detail/detail', query: { id: 123 }})
实现带参数的页面跳转。
-
-
基于 uni API 的方式
-
UniApp 提供了
uni.navigateTo()
、uni.redirectTo()
、uni.switchTab()
、uni.navigateBack()
等 API 来进行跨平台的页面跳转,这些 API 兼容微信小程序和其他平台。 -
示例(文字描述):
使用
uni.navigateTo({ url: '/pages/detail/detail?id=123' })
进行页面跳转,适用于多平台场景。
-
-
条件编译支持
-
对于某些特定平台独有的跳转逻辑,可以使用条件编译来处理。
-
示例(文字描述):
#ifdef MP-WEIXIN // 微信小程序特有的跳转逻辑 wx.navigateTo({ url: '/pages/wechatDetail/wechatDetail' }); #endif
-
Vue,小程序、uniapp如何发起网络请求?
Vue
方法 | 幂等性 | 安全性 | 请求体 | 缓存 | 主要用途 |
---|---|---|---|---|---|
GET | 是 | 是 | 无 | 可 | 获取数据 |
POST | 否 | 否 | 有 | 不可 | 创建数据 |
PUT | 是 | 否 | 有 | 不可 | 更新全部 |
DELETE | 是 | 否 | 通常无 | 不可 | 删除资源 |
// 使用axios
axios.get('/api/data').then(response => {})
axios.post('/api/data', params).then(response => {})
// 或使用fetch
fetch('/api/data').then(response => response.json())
微信小程序
wx.request({
url: 'https://example.com/api',
method: 'GET',
success(res) {},
fail(err) {}
})
Uniapp
uni.request({
url: 'https://example.com/api',
method: 'GET',
success(res) {},
fail(err) {}
})
面试回答
在 Vue 中通常使用 axios
或 fetch
发起网络请求,在组件的生命周期中调用,并封装统一的请求工具;在微信小程序中主要使用 wx.request
方法,并需配置域名白名单;而在 UniApp 中,使用 uni.request
方法,它在不同平台下自动适配,适合跨平台开发。三者都可以通过封装统一请求工具来处理错误、加载状态、拦截器等功能,提升开发效率和维护性。
平台 | 请求方法 | 是否支持拦截器 | 是否跨平台 | 常用封装方式 |
---|---|---|---|---|
Vue | axios / fetch |
✅ 是 | ❌ 否 | 封装 http.js |
小程序 | wx.request |
❌ 否 | ❌ 否 | 封装 utils.js |
UniApp | uni.request |
✅ 可封装实现 | ✅ 是 | 封装 api.js 或 request.js |
一、Vue 相关面试题
基础部分
1、Vue 的核心特性是什么?
- 数据驱动(响应式系统):Vue 的核心机制,通过数据变化自动更新视图,无需直接操作 DOM
- 组件化开发:将UI拆分为独立可复用的组件,形成树状结构
- 指令系统:特殊的HTML属性,带有
v-
前缀,用于响应式地操作DOM - 虚拟DOM:用JavaScript对象模拟真实DOM结构,通过diff算法高效更新视图
- 模板语法:基于HTML的声明式模板,可以插入数据绑定和指令
Vue.js 提供了一系列的 v-
前缀指令,用于实现DOM操作、事件处理、条件渲染、列表渲染等功能。以下是一些常用的 Vue.js 指令及其简要说明:
-
v-text
-
用于更新元素内的文本内容。
-
示例:
<span v-text="message"></span>
等价于{``{ message }}
。
-
-
v-html
-
更新元素的 innerHTML。注意使用时应确保内容安全,避免XSS攻击。
-
示例:
<div v-html="rawHtml"></div>
。
-
-
v-show
-
根据表达式的真假值来切换元素的显示状态(通过CSS的
display
属性)。 -
示例:
<p v-show="isVisible">现在你看到我了</p>
。
-
-
v-if / v-else-if / v-else
-
条件性地渲染一块内容。如果条件为真,则渲染元素;否则不渲染。
-
示例:
<p v-if="type === 'A'">优秀</p> <p v-else-if="type === 'B'">良好</p> <p v-else>继续努力</p>
-
-
v-for
-
渲染列表。基于一个数组来迭代渲染元素。
-
示例:
<li v-for="(item, index) in items" :key="index">{``{ item }}</li>
。
-
-
v-on
-
绑定事件监听器。可以缩写为
@
。 -
示例:
<button @click="doSomething">点击我</button>
。
-
-
v-bind
-
动态绑定属性。可以缩写为
:
。 -
示例:
<img :src="imageSrc">
。
-
-
v-model
-
在表单控件或者组件上创建双向数据绑定。
-
示例:
<input v-model="message">
。
-
核心特性 | 描述 | 示例/说明 |
---|---|---|
响应式数据绑定 | 数据变化时视图自动更新,基于 Proxy (Vue 3)或 Object.defineProperty (Vue 2)。 |
v-model 实现表单双向绑定。 |
组件化开发 | 将 UI 拆分为独立、可复用的组件(.vue 文件)。 |
单文件组件包含 <template> 、<script> 、<style> 。 |
声明式模板语法 | 通过指令(如 v-if 、v-for )声明式描述视图逻辑。 |
<div v-if="show">Hello</div> 。 |
虚拟 DOM | 用 JS 对象模拟真实 DOM,通过 Diff 算法高效更新视图。 | 减少直接操作 DOM,提升性能。 |
指令系统 | v- 前缀的特殊属性,用于绑定数据或操作 DOM。 |
v-bind:href="url" 、v-on:click="handleClick" 。 |
生命周期钩子 | 在组件不同阶段(如创建、挂载、更新)触发逻辑。 | created() 、mounted() 用于初始化数据或访问 DOM。 |
状态管理(Vuex/Pinia) | 集中管理跨组件共享状态,提供可预测的数据流。 | Vuex 的 state 、mutations ;Pinia 的 stores 。 |
路由管理(Vue Router) | 实现 SPA 的无刷新页面切换和嵌套路由。 | router-link 导航,router-view 占位。 |
组合式 API(Vue 3) | 通过 setup() 和响应式 API(ref 、reactive )组织逻辑,提升复用性。 |
const count = ref(0) ;watch(count, () => {...}) 。 |
渐进式框架 | 可逐步集成功能,从核心库扩展到路由、状态管理等。 | 仅引入 vue.js 处理简单交互,或搭配全家桶构建复杂应用。 |
2、Vue 2 和 Vue 3 的主要区别有哪些?
- 响应式原理不同(Object.defineProperty vs Proxy):
- Composition API 替代 Options API
- 性能优化(Tree-shaking支持更好)
- 生命周期变化
- 更好的TypeScript支持
(1)响应式系统的实现
特性 | Vue 2 | Vue 3 |
---|---|---|
响应式原理 | 使用 Object.defineProperty 实现数据劫持 |
使用 Proxy (ES6)实现,更强大、性能更好 |
数组响应式 | 特殊处理(重写数组方法) | 原生支持数组的响应式更新 |
响应式对象创建 | Vue.set() 或 this.$set() |
不再需要,Proxy 自动追踪 |
(2) 性能优化
特性 | Vue 2 | Vue 3 |
---|---|---|
渲染性能 | 相对较慢 | 更快,通过重写虚拟 DOM 和编译优化提升 |
包体积 | 较大 | 更小,通过 Tree-shaking 优化,减少冗余代码 |
编译优化 | 运行时编译较多 | 编译器增强,静态提升、Patch 标记等优化 |
(3)Composition API(组合式 API)
特性 | Vue 2 | Vue 3 |
---|---|---|
API 风格 | Options API(选项式)为主 | 支持 Composition API(组合式),更灵活组织逻辑 |
逻辑复用 | 依赖 Mixins,存在命名冲突问题 | 使用 setup() 和自定义 Hook 函数,逻辑更清晰 |
(4)TypeScript 支持
特性 | Vue 2 | Vue 3 |
---|---|---|
TypeScript 支持 | 支持但不够原生 | 完全支持 TypeScript,代码结构更清晰、类型更安全 |
(5)生命周期钩子
特性 | Vue 2 | Vue 3 |
---|---|---|
生命周期名称 | beforeCreate , created , beforeMount , mounted 等 |
保持兼容,但在 Composition API 中使用 onBeforeMount , onMounted 等函数形式 |
(6)模板语法与组件
特性 | Vue 2 | Vue 3 |
---|---|---|
多根组件 | 不支持(必须包裹在一个根元素内)<value> | 支持 Fragment(可有多个根节点) |
自定义指令 | 指令钩子函数较少 | 指令钩子更丰富,与组件生命周期更一致 |
Teleport | 不支持 | 新增 <Teleport> 组件,实现元素渲染到任意位置 |
Suspense | 不支持 | 新增 <Suspense> 组件,支持异步加载组件 |
3、什么是 MVVM 模式?Vue 是如何实现它的?
MVVM(Model-View-ViewModel)是一种软件架构设计模式,主要用于简化用户界面的开发。它将应用程序分为三个部分:
- Model:代表应用的数据和业务逻辑,负责处理数据的获取、存储等操作。
- View:定义了用户界面的结构和布局,显示数据并接收用户的交互。
- ViewModel:作为桥梁连接 Model 和 View,负责处理视图的逻辑,同时提供数据绑定到视图的方法,并能响应视图中的用户输入。
MVVM 的工作原理
在 MVVM 模式中,ViewModel 监听 Model 中的数据变化,并更新到 View;同时,它也监听 View 中发生的事件(如用户输入),并将这些更改反映回 Model。这种双向数据绑定机制使得开发者不需要手动编写代码来同步 View 和 Model 之间的状态,从而提高了开发效率。
Vue 如何实现 MVVM
Vue.js 是一个实现了 MVVM 设计模式的前端框架,其核心就是通过声明式的语法来实现数据与视图之间的双向绑定。以下是 Vue 实现 MVVM 的几个关键点:
-
数据绑定 :Vue 使用声明式的数据绑定机制,允许你轻松地将数据模型绑定到 DOM(文档对象模型)上。当数据模型发生变化时,Vue 自动更新相应的视图,反之亦然。
-
模板引擎:Vue 使用基于HTML的模板语法,允许开发者声明式地将DOM绑定到底层Vue实例的数据。
-
计算属性与侦听器:Vue 提供了计算属性(computed properties)和侦听器(watchers)来处理复杂的逻辑或依赖关系。计算属性可以基于其他数据进行计算,并且只有在其依赖的数据发生改变时才会重新计算。侦听器则用于执行异步操作或开销较大的操作。
-
组件系统:Vue 的组件系统允许你构建大型应用程序,并将其拆分成可复用的独立组件。每个组件都有自己的视图和数据逻辑,这与 MVVM 中 ViewModel 的概念相吻合。
-
虚拟DOM:Vue 使用虚拟DOM技术来提高性能,通过比较前后两次虚拟DOM树的差异,仅将变化的部分应用到实际DOM上,减少了不必要的DOM操作。
4、解释 Vue 的生命周期钩子函数及其执行顺序?
beforeCreate → created → beforeMount → mounted → beforeUpdate → updated →
beforeDestroy → destroyed
阶段 | 钩子函数 | 触发时机 | 用途 | 注意事项 |
---|---|---|---|---|
创建阶段 | beforeCreate |
实例初始化后,数据观测(data )和事件配置(events )之前。 |
初始化非响应式变量(如插件配置)。 | 无法访问 data 和 methods 。 |
created |
实例创建完成,数据观测和事件配置已完成,但 DOM 未挂载。 | 发起异步请求、初始化数据。 | 可访问 data ,但 $el 为 undefined 。 |
|
挂载阶段 | beforeMount |
模板编译完成,但尚未将虚拟 DOM 渲染为真实 DOM。 | 极少使用,通常用于服务端渲染(SSR)。 | $el 存在但内容为空。 |
mounted |
实例挂载到 DOM 后,真实 DOM 已生成。 | 操作 DOM、集成第三方库(如地图、图表)。 | 子组件的 mounted 先于父组件执行。 |
|
更新阶段 | beforeUpdate |
数据变化后,虚拟 DOM 重新渲染和打补丁之前。 | 获取更新前的 DOM 状态(如保存滚动位置)。 | 避免在此修改数据,可能循环触发更新。 |
updated |
虚拟 DOM 重新渲染并应用补丁后。 | 数据变化后操作 DOM(如调整样式)。 | 避免直接修改数据,可能导致无限循环。 | |
销毁阶段 | beforeDestroy |
实例销毁前,此时实例仍完全可用。 | 清理定时器、解绑事件、取消未完成的异步任务。 | Vue 3 中更名为 beforeUnmount 。 |
destroyed |
实例销毁后,所有绑定和监听被移除,子实例也被销毁。 | 善后工作(如释放非 Vue 管理的资源)。 | Vue 3 中更名为 unmounted 。 |
父子组件生命周期执行顺序对比
场景 | 执行顺序 |
---|---|
加载时 | 父 beforeCreate → 父 created → 父 beforeMount → 子 beforeCreate → 子 created → 子 beforeMount → 子 mounted → 父 mounted |
更新时 | 父 beforeUpdate → 子 beforeUpdate → 子 updated → 父 updated |
销毁时 | 父 beforeDestroy → 子 beforeDestroy → 子 destroyed → 父 destroye |
5、v-if 和 v-show 的区别是什么?
- v-if:条件渲染,不满足时元素不存在于DOM
- v-show:条件显示,通过CSS控制,元素始终在DOM中
v-if
和 v-show
对比表
对比项 | v-if |
v-show |
---|---|---|
渲染机制 | 条件性渲染:动态添加/移除 DOM 节点 | 显示切换 :通过 CSS display: none 控制显示/隐藏 |
初始渲染 | 初始为 false 时,不渲染 DOM |
无论条件如何,始终渲染 DOM,仅切换显示状态 |
切换开销 | 高(涉及 DOM 增删和子组件生命周期) | 低(仅修改 CSS 属性) |
适用场景 | 运行时条件很少改变(如权限控制) | 需要频繁切换显示状态(如选项卡) |
生命周期 | 切换时会触发组件的 created /destroyed 钩子 |
组件始终保持挂载,仅触发 mounted 一次 |
性能影响 | 减少初始渲染负载,但频繁切换性能差 | 初始渲染负载高,但切换性能优 |
组件通信
1、Vue 组件间通信的方式有哪些?
组件通信方式:
父子:props/$emit
子父:emit/on
任意组件:Vuex/Pinia
1. 父子通信:props
/ $emit
这是最基础、最常用的组件通信方式。
-
props
(父传子):- 作用:父组件向子组件传递数据。
- 原理 :父组件在使用子组件时,通过属性(attribute)的方式将数据传递给子组件。子组件通过
props
选项显式地声明它期望接收的数据。 - 特点 :单向数据流 。数据从父组件流向子组件。子组件不应该直接修改
props
的值(Vue 会警告),如果需要修改,应该通过事件通知父组件。
-
$emit
(子传父): -
- 作用 :子组件向父组件发送事件,通常用于通知父组件状态变化或请求操作。
- 原理 :子组件通过调用
this.$emit('事件名', 数据)
触发一个自定义事件,并可以携带数据。父组件在使用子组件的标签上,通过v-on
(或@
) 监听这个事件,并定义处理函数。 - 特点 :这是子组件通知 父组件的主要方式。父组件在事件处理函数中可以修改自己的数据,这些数据再通过
props
传递回子组件(形成闭环)。
2、 任意组件通信:Vuex / Pinia
当组件层级较深或多个不相关的组件需要共享状态时,使用状态管理库。
-
Vuex:
- Vue 2 官方的状态管理库,Vue 3 也兼容,但现在更推荐 Pinia。
- 核心概念:
State
(单一状态树),Getters
(计算属性),Mutations
(同步修改状态),Actions
(异步操作,提交 Mutations)。 - 所有组件都可以通过
mapState
,mapGetters
辅助函数或直接访问$store.state
来读取状态;通过mapMutations
,mapActions
或this.$store.commit/dispatch
来修改状态。
-
Pinia:
- Vue 3 的官方推荐状态管理库,也是 Vue 2 的官方推荐(通过插件)。
- 优势 :更简洁的 API(基于
store
模块,无 Mutations,Actions 可同步可异步)、更好的 TypeScript 支持、模块化设计(天然分模块)、支持组合式 API (setup
)。 - 核心 :定义
store
(使用defineStore
),包含state
,getters
,actions
。组件中通过useXXXStore()
获取 store 实例来访问和修改状态。
-
工作流程:
- 创建一个全局的 Store (Vuex Store 或 Pinia Store)。
- 需要共享的数据放在 Store 的
state
中。 - 任何组件都可以读取 这个
state
。 - 当组件需要修改 共享状态时,必须通过调用 Store 提供的
actions
(或 Vuex 的mutations
) 来进行,保证状态变更的可追踪性。 - 状态变更后,所有依赖该状态的组件会自动更新。
-
适用场景:用户登录状态、购物车信息、全局配置、多级嵌套组件间复杂的数据流等。
2、父子组件如何传递数据?
(1)父组件向子组件传递数据
父→子:props
父组件通过 props
向子组件传递数据。
子组件在定义时声明它需要接收哪些外部数据(即 props),包括数据的名称、类型、默认值等。
父组件在使用子组件时,通过绑定属性的方式,将数据传入子组件内部。
这种方式适用于传递静态数据、动态数据、函数、对象、数组等。
(2)子组件向父组件传递数据
子→父:$emit事件
子组件通过 触发自定义事件($emit
) 向父组件传递信息。
当子组件内部发生某些行为(如点击、输入、状态变化)时,可以使用 $emit
方法触发一个事件,并携带数据。
父组件监听该事件,并在其模板中通过事件绑定语法指定处理函数,从而接收到子组件传来的数据。
3、非父子组件如何通信?
Vuex / Pinia 状态管理库
-
使用 Vuex (Vue 2 和 Vue 3 都支持)或 Pinia(Vue 3 推荐的状态管理库),将共享数据集中存放在一个全局的"store"中。
-
所有组件都可以从 store 中读取数据或提交更改,从而实现跨组件通信。
-
适用于中大型项目,提供统一的状态管理机制,便于维护和调试。
4、Vuex |Pinia的核心概念是什么?(了解)
Vuex 和 Pinia 是 Vue.js 应用中用于状态管理的库,它们帮助开发者集中管理和维护应用的状态。以下是它们的核心概念说明:
Vuex 核心概念
-
State(状态):代表存储在 store 中的数据,是驱动你的应用的数据源。
-
Getter:类似于 Vue 组件中的计算属性,用于从 state 中派生出一些状态,这些状态可以根据其他状态计算得出。
-
Mutation(变更):唯一可以改变 store 中状态的方法,必须是同步函数。通过提交 mutation 来修改状态。
-
Action:类似 Mutation,但主要用于处理异步操作,并且可以包含任意异步操作。Action 提交的是 Mutations 而不是直接变更状态。
-
Module(模块):为了便于管理大型项目中的状态,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter。
Pinia 核心概念
Pinia 是一个更现代的状态管理库,旨在解决 Vuex 中的一些限制和痛点,其核心概念如下:
-
Store(存储):Pinia 的核心概念之一,是一个包含了状态、getters 和 actions 的容器。与 Vuex 不同,Pinia 没有强制性的层级结构,所有 Store 都是平等的。
-
State:同样代表了应用的状态,但定义更加灵活,可以直接在 Store 内部定义为响应式对象。
-
Getters:用于从 State 中派生出一些值,功能上类似于 Vuex 的 Getters,但是使用起来更加直观和灵活。
-
Actions:用于执行业务逻辑或异步操作,可以访问并修改 State,也可以调用其他的 Actions 或 Getters。
-
插件支持:Pinia 支持插件扩展,可以通过插件来增强 Store 的功能,如添加全局状态、集成第三方服务等。
-
无模块嵌套限制:Pinia 采用扁平化的 Store 结构,避免了 Vuex 中的模块嵌套问题,使得跨 Store 的状态共享变得简单。
5、什么时候应该使用 Vuex|PInia?(了解)
使用 Vuex 或 Pinia 的场景
-
全局状态管理:当你的应用需要在多个组件间共享状态(如用户登录状态、购物车信息等),而这些状态不仅限于父子组件关系时,使用 Vuex 或 Pinia 可以帮助你集中管理和维护这些状态。
-
复杂的状态逻辑:如果你的应用包含复杂的业务逻辑或状态变化,比如需要处理异步操作(如 API 调用)、条件性地更新状态或基于其他状态计算出新的状态,那么 Vuex 和 Pinia 提供的结构化方式可以帮助你更好地组织代码。
-
大型项目或团队协作:对于较大的项目或者多人协作的团队,使用 Vuex 或 Pinia 可以提供一个明确的状态管理方案,有助于保持代码的一致性和可维护性。这可以减少因状态管理不当导致的错误和冲突。
-
状态持久化需求:如果你的应用需要将某些状态持久化(例如保存用户的偏好设置),Vuex 和 Pinia 都可以通过插件或其他方法支持这一需求。
选择 Vuex 还是 Pinia?
-
Vuex:
- 如果是从 Vue 2 过渡到 Vue 3,且对 Vuex 模式非常熟悉,可以选择继续使用 Vuex。
- Vuex 有更严格的架构约束(如 Mutations 必须是同步的),这对于一些开发者来说可能是优势,因为它强制了更好的状态管理实践。
-
Pinia:
- 更加灵活和直观,减少了样板代码,使得开发体验更加流畅。
- 对 TypeScript 支持更好,提供了类型推断和更好的类型安全。
- 适合新项目或是想要简化状态管理流程的团队,尤其是在 Vue 3 环境下。
总结
- 小型应用:如果只是一个简单的单页应用(SPA),可能不需要引入 Vuex 或 Pinia,直接通过组件间的 Props 和 Events 即可满足需求。
- 中大型应用:随着应用的增长,尤其是当你发现状态管理变得越来越复杂时,考虑引入 Vuex 或 Pinia 来管理全局状态会是一个不错的选择。
- Vue 3 项目:推荐使用 Pinia,因其设计更加现代化,API 更加友好,尤其适合新的 Vue 3 项目。
二、微信小程序面试题
基础部分
1、微信小程序的文件结构是怎样的?
文件/目录 | 作用 | 关键特性 | 示例/备注 |
---|---|---|---|
app.json |
全局配置 | 定义页面路径、窗口样式、tabBar 、网络超时等 |
必须配置 pages 字段,第一项为启动页。 |
app.js |
入口逻辑文件 | 监听小程序生命周期、定义全局数据(globalData ) |
通过 getApp() 获取实例。 |
app.wxss |
全局样式 | 所有页面共享样式(可被页面样式覆盖) | 使用 rpx 单位适配屏幕。 |
pages/ |
存放所有页面 | 每个页面包含 .js (逻辑)、.json (配置)、.wxml (结构)、.wxss (样式) |
页面配置(.json )会覆盖 app.json 中的 window 设置。 |
utils/ |
公共工具函数 | 封装复用逻辑(如请求、工具类函数) | 需手动引入到页面或组件中使用。 |
2、小程序的生命周期函数有哪些?
- App生命周期:onLaunch, onShow, onHide
- Page生命周期:onLoad, onShow, onReady, onHide, onUnload
应用生命周期函数
这些函数定义在 app.js
文件中,用于监听整个小程序的生命周期。
-
onLaunch:当小程序初始化完成时触发(全局只触发一次)。
-
onShow:当小程序启动,或从后台进入前台显示时触发。
-
onHide:当小程序从前台进入后台时触发。
-
onError:当小程序发生脚本错误或者 API 调用失败时触发,参数为错误信息。
页面生命周期函数
这些函数定义在每个页面的 .js
文件中,用于监听页面的生命周期。
-
onLoad:监听页面加载,其参数为页面跳转过来的参数。
-
onShow:监听页面显示。每次页面出现时都会触发,包括从后台切到前台。
-
onReady:监听页面初次渲染完成。注意,此事件仅在页面首次显示时触发一次。
-
onHide:监听页面隐藏。当用户导航到其他页面或小程序退到后台时触发。
-
onUnload:监听页面卸载。当页面被关闭或替换时触发,比如通过返回键回到前一个页面时当前页面会被卸载。
-
onPullDownRefresh :监听用户下拉动作。需要在
app.json
或对应的页面json
配置"enablePullDownRefresh": true
来启用。 -
onReachBottom:页面上拉触底事件的处理函数。可以用来加载更多数据。
-
onShareAppMessage:用户点击右上角菜单的"转发"按钮时触发。可以通过此函数自定义转发内容。
-
onPageScroll:监听页面滚动。参数为页面滚动的距离信息。
-
onResize:监听窗口尺寸变化。可用于响应屏幕旋转等导致的布局调整。
-
onTabItemTap:点击 tab 时触发。参数包含被点击的 tab 信息。
3、小程序页面间如何传递数据?
// 跳转时传参
wx.navigateTo({url: '/page?id=1'})
// 接收参数
Page({
onLoad(options) {
const id = options.id
}
})
- 通过页面跳转时传递参数
在页面跳转时,可以通过 wx.navigateTo
、wx.redirectTo
或 wx.reLaunch
等方法携带参数,将数据传递给目标页面。这些参数会作为目标页面 onLoad
生命周期函数的参数传入。这种方式适用于简单数据(如字符串、数字)的传递。
- 通过全局变量(App 全局对象)
可以在 app.js
中定义全局变量,用于存储需要跨页面共享的数据。各个页面都可以访问和修改这些变量,从而实现页面间的数据共享。这种方式适合少量共享数据的场景,但需要注意数据同步和管理,避免混乱。
4、小程序的 WXSS 和 CSS 有什么区别?(了解)
特性/对比项 | WXSS(微信小程序样式) | CSS(网页样式) |
---|---|---|
全称 | WeiXin Style Sheets | Cascading Style Sheets |
运行环境 | 微信小程序环境(小程序框架内) | 浏览器环境(HTML 页面) |
尺寸单位 | 支持 rpx (响应式像素),适配不同设备屏幕宽度 |
使用 px 、em 、rem 、vw 、vh 等标准单位 |
样式导入 | 支持 @import 导入其他 .wxss 文件,路径为相对路径 |
支持 @import 导入其他 CSS 文件 |
选择器支持 | 支持部分 CSS 选择器,部分高级选择器不支持(如 > , + , ~ 等) |
支持完整的 CSS 选择器(包括伪类、伪元素等) |
全局与局部样式 | app.wxss 为全局样式,各页面 .wxss 为局部样式,优先级更高 |
通常通过外部 CSS 文件引入,可通过类名或 ID 控制样式作用域 |
动态样式绑定 | 支持通过 {``{ }} 数据绑定动态设置 style 或 class |
一般通过 JavaScript 操作 DOM 来动态修改样式 |
伪类和伪元素支持 | 支持有限,如 ::after 、::before 可能不完全支持 |
完整支持伪类(如 :hover , :nth-child )和伪元素(如 ::before , ::after )等 |
兼容性处理 | 不需要考虑浏览器兼容性问题,统一在微信小程序环境下运行 | 需要考虑浏览器兼容性(如不同浏览器对 CSS 的支持差异) |
样式作用域 | 天然模块化,页面样式默认只作用于当前页面 | 需要通过命名空间或 CSS Modules 等方式避免样式冲突 |
开发体验 | 更适合小程序开发,与 WXML、JS 配合紧密,开发效率高 | 更灵活,但需配合 HTML 和 JS,适合网页开发 |
5、小程序的双向绑定和 Vue 有什么不同?
- Vue:v-model直接双向绑定
- 小程序:需要绑定事件手动setData
1. 数据流控制逻辑
维度 | 微信小程序 | Vue |
---|---|---|
默认机制 | 单向数据流(父→子通过属性,子→父通过事件) | 双向绑定 (v-model 语法糖) |
双向实现方式 | 需手动绑定事件(如 bindinput + setData ) |
直接通过 v-model 自动同步 |
数据更新 | 必须显式调用 this.setData() 更新 |
自动响应数据变化 |
本质区别 :
小程序通过 事件系统 + API 调用 模拟双向绑定,而 Vue 通过 数据劫持/代理 实现自动响应式。
2. 语法设计差异
维度 | 微信小程序 | Vue |
---|---|---|
表单控件绑定 | 使用 value + bindinput 组合 |
直接使用 v-model |
自定义组件 | 需手动实现 properties + 事件触发 |
通过 model 选项或 v-model 参数化 |
指令系统 | 无指令概念,依赖事件绑定 | 提供 v-model 、v-bind 等指令 |
设计哲学 :
小程序强调 显式数据流 (更接近 React 模式),Vue 追求 声明式简化(隐式自动化)。
3. 底层实现原理
维度 | 微信小程序 | Vue |
---|---|---|
响应式原理 | 依赖 setData 的差量更新机制 |
基于 Object.defineProperty (Vue 2)或 Proxy (Vue 3) |
性能优化 | 需手动合并 setData 调用 |
自动批量异步更新 |
更新粒度 | 组件级别重渲染 | 精准到虚拟 DOM 节点 |
性能影响 :
小程序的 setData
需要开发者手动优化调用频率,而 Vue 的响应式系统自动处理依赖追踪和批量更新。
进阶部分
1、小程序的运行机制是怎样的?(了解)
- 框架结构
微信小程序采用了双线程模型,分别是逻辑层(App Service)和视图层(View)。这两个层次分别运行在不同的线程中,通过微信客户端提供的原生 API 进行通信。
-
逻辑层:负责处理业务逻辑、数据请求、页面路由等。使用 JavaScript 编写,运行在一个单独的线程中。
-
视图层:负责 UI 的渲染,使用 WXML 和 WXSS 来描述界面结构和样式。同样运行在一个独立的线程中,利用 WebView 渲染页面。
- 加载流程
当用户打开一个微信小程序时,其加载过程大致如下:
-
小程序包被下载到本地设备(首次打开时)或从缓存中读取(后续打开)。
-
微信客户端启动逻辑层和视图层,并将
app.js
中的代码注入逻辑层线程执行,完成小程序的初始化工作。 -
根据初始页面路径,在逻辑层加载并执行相应的页面 JS 文件,同时在视图层加载对应的 WXML 和 WXSS 文件进行页面渲染。
- 渲染机制
-
WXML 解析与渲染:视图层接收到逻辑层传递的数据后,会解析 WXML 文件,并根据数据动态生成页面结构。
-
WXSS 应用:同时应用 WXSS 样式规则对页面元素进行样式设置。
-
组件化开发:支持自定义组件,允许开发者封装可复用的 UI 组件,提高开发效率。
- 数据更新与交互
-
当页面中的数据发生变化时,逻辑层会通知视图层进行重新渲染,确保界面与数据保持同步。
-
视图层可以通过事件绑定的方式向逻辑层发送用户交互信息(如点击按钮),从而触发相应的业务逻辑处理。
2、如何优化小程序的性能?
- 减少setData调用频率和数据量
- 使用分包加载
- 图片压缩
- 合理使用onPageScroll
优化方向 | 具体措施 | 原理/效果 | 注意事项 |
---|---|---|---|
代码体积控制 | 1. 使用分包加载(主包≤2MB,总包≤20MB) 2. 删除未使用的代码和资源 3. 压缩图片/代码(如TinyPNG、uglify) | 减少首次下载时间,提升启动速度 | 分包需在app.json 中配置路径 |
数据通信优化 | 1. 合并setData 调用 2. 使用路径更新(如setData({'a.b': value}) ) 3. 避免传输大对象(≤256KB) |
减少逻辑层与渲染层通信次数和传输量,降低延迟 | 高频操作(如滚动)避免频繁调用setData |
渲染性能 | 1. 列表渲染用wx:for +唯一key 2. 长列表用recycle-view 虚拟列表 3. 隐藏节点用hidden 替代wx:if |
减少DOM节点数量,复用已有节点,避免重复渲染 | wx:if 会销毁组件,适合低频切换场景 |
启动加载 | 1. 启用预加载(preloadRule ) 2. 骨架屏(Skeleton Screen) 3. 异步初始化(延迟非必要逻辑) |
提前加载资源,提升页面切换速度;减少用户等待感知 | 预加载需平衡流量消耗与体验 |
图片/资源优化 | 1. 使用WebP格式图片 2. 懒加载图片(lazy-load 属性) 3. CDN加速静态资源 |
减少资源体积和请求数,提升加载速度 | WebP需兼容iOS 14以下机型 |
事件处理 | 1. 防抖/节流(如lodash.throttle ) 2. 避免在onPageScroll 中频繁操作 |
减少不必要的事件触发和逻辑层压力 | 滚动监听尽量轻量化 |
缓存策略 | 1. 数据缓存(wx.setStorage ) 2. 接口数据本地化(合理设置缓存时间) |
减少网络请求,加快二次访问速度 | 敏感数据避免缓存 |
原生组件优化 | 1. 避免过多原生组件(如video 、map ) 2. 动态加载原生组件(按需渲染) |
原生组件层级最高,过多会导致渲染性能下降 | 需处理遮盖问题(cover-view ) |
内存管理 | 1. 及时销毁定时器、事件监听 2. 使用onUnload 清理全局变量 |
防止内存泄漏,提升长时间运行稳定性 | 尤其注意页面跳转时的资源释放 |
工具监控 | 1. 使用性能面板 2. 真机性能分析 | 定位瓶颈( |
3、小程序如何实现自定义组件?
- 创建组件目录
- 配置component: true
- 使用properties定义属性
- 父组件通过属性传递数据
面试回答模板(简洁版)
在微信小程序中实现自定义组件,首先需要创建一个组件文件夹,包含 WXML、WXSS、JS 和 JSON 文件。在 JSON 中声明 component: true
,在 JS 中定义 properties、data 和方法。然后在页面的 JSON 中通过 usingComponents
引入组件,就可以在 WXML 中使用。支持通过属性传值、事件通信和插槽分发内容,非常适合构建可复用的 UI 模块
步骤 | 操作说明 | 详细描述 |
---|---|---|
1. 创建组件文件夹 | 新建一个专门用于存放自定义组件的文件夹 | 在项目中创建一个目录(如 components/my-button ),用于存放组件的 WXML、WXSS、JS 和 JSON 文件。 |
2. 编写组件结构(WXML) | 定义组件的页面结构 | 使用 WXML 编写组件的模板内容,例如按钮、图标、文本等布局结构,支持数据绑定和事件绑定。 |
3. 编写组件样式(WXSS) | 定义组件的外观样式 | 使用 WXSS 为组件设置样式,样式默认具有局部作用域,不会影响其他页面或组件(除非使用全局样式)。 |
4. 编写组件逻辑(JS) | 定义组件的行为和数据 | 在 JS 文件中调用 Component({}) 方法定义组件,包含组件的属性(properties)、内部数据(data)、方法(methods)以及生命周期函数。 |
5. 配置组件(JSON) | 声明这是一个自定义组件 | 在组件的 JSON 文件中设置 "component": true ,告诉小程序这是一个自定义组件而非页面。 |
6. 在页面中引用组件 | 将组件注册到需要使用的页面 | 在页面的 JSON 配置文件中,通过 "usingComponents" 字段引入该组件,并指定组件标签名(如 my-button )。 |
7. 传递数据给组件 | 父组件向子组件传参 | 使用属性绑定语法(如 title="{``{title}}" )将数据从页面传递给组件,组件通过 properties 接收并使用。 |
8. 组件向页面通信 | 子组件触发事件通知父组件 | 组件内部通过 this.triggerEvent() 触发自定义事件,页面通过事件绑定(如 bind:click )监听并处理。 |
9. 使用插槽(Slot) | 实现内容分发(类似 Vue 的 slot) | 如果希望在组件中插入外部内容,可以在 WXML 中使用 <slot> 标签,页面中的内容会自动插入到对应位置。 |
10. 组件生命周期 | 控制组件的创建、显示、销毁等行为 | 组件支持 created 、attached 、ready 、detached 等生命周期函数,可用于初始化数据或清理资源。 |
4、小程序的登录流程是怎样的?(了解)
面试回答模板(简洁版)
微信小程序的登录流程主要包括以下几个步骤:首先调用 wx.login()
获取临时登录凭证 code,然后将 code 发送到开发者服务器;服务器再向微信服务器请求用户的 openid 和 session_key;接着服务器根据这些信息生成自定义的登录态 token 并返回给小程序;之后小程序在每次请求时携带 token 来验证身份。这样可以实现安全、高效的用户登录机制。
- 用户触发登录操作
- 用户在小程序端点击"登录"按钮或其他触发登录行为的操作。
- 调用
wx.login()
获取临时登录凭证(code)
-
小程序通过微信提供的 API
wx.login()
获取一个临时登录凭证 code,这个 code 是一次性的、有效期为 5 分钟,且只能使用一次。 -
该 code 是微信服务器生成的,用于换取用户的唯一标识(openid)和会话密钥(session_key)。
- 将 code 发送到开发者服务器
- 小程序将获取到的 code 发送给自己的后端服务器,通常通过 HTTP 请求(如
wx.request
)发送给后台接口。
- 后端服务器向微信服务器请求用户信息
-
后端服务器使用 code 向微信服务器发起请求,调用微信的接口(
https://api.weixin.qq.com/sns/jscode2session
),传入小程序的appid
和appsecret
。 -
微信服务器验证通过后,返回用户的:
-
openid:用户的唯一标识(每个用户在每个小程序下唯一)
-
session_key:会话密钥,用于解密用户敏感数据(如手机号、加密信息)
-
- 后端生成自定义登录态(token)
-
后端服务器根据用户的
openid
和其他信息生成一个自定义的登录态 token(如 JWT、session ID 等)。 -
这个 token 用于后续小程序与服务器之间的身份验证,代替原始的
session_key
,避免敏感信息泄露。
- 返回 token 给小程序客户端
- 后端将生成的 token 返回给小程序客户端,小程序将 token 存储在本地(如
wx.setStorageSync
)。
- 后续请求携带 token 验证身份
-
小程序每次请求业务接口时,在请求头或参数中携带该 token。
-
后端通过校验 token 判断用户身份,并返回相应的数据。
实战问题
1、小程序如何实现下拉刷新和上拉加载更多?(了解)
(1)实现下拉刷新(Pull Down Refresh)
- 启用下拉刷新功能
-
在页面的
json
配置文件中设置"enablePullDownRefresh": true
,启用下拉刷新功能。 -
或者在全局
app.json
中设置,控制所有页面是否默认支持下拉刷新。
- 监听下拉刷新事件
-
页面中定义
onPullDownRefresh
生命周期函数,当用户下拉页面时会自动触发该函数。 -
在该函数中通常会执行:
-
重置当前页码为第一页
-
清空当前数据列表
-
重新请求接口获取最新数据
-
数据加载完成后调用
wx.stopPullDownRefresh()
停止刷新动画
-
- 停止刷新
- 数据加载完成后,必须手动调用
wx.stopPullDownRefresh()
来停止下拉刷新的 loading 动画,否则会一直显示。
(2)实现上拉加载更多(Reach Bottom)
- 监听页面滚动到底部事件
-
页面中定义
onReachBottom
生命周期函数,当用户滚动到底部时自动触发。 -
通常用于加载下一页数据。
- 实现分页加载逻辑
-
在该函数中执行:
-
当前页码自增(如 page + 1)
-
请求接口获取下一页数据
-
将新数据追加到已有数据列表中
-
如果没有更多数据,可以提示"没有更多了"或禁用后续加载
-
- 控制加载频率(可选)
-
可以添加节流机制,防止短时间内多次触发加载
-
也可以设置一个标志位,如
isLoading = true
,防止重复请求
2、如何处理小程序的兼容性问题?(了解)
面试回答模板(简洁版)
小程序的兼容性问题主要体现在设备适配、微信版本、基础库、组件样式和接口数据等方面。
对于设备适配,使用 rpx 单位和 flex 布局,结合设备信息动态调整;对于不同微信版本,使用 wx.canIUse()
判断 API 支持情况,做降级处理;对于基础库版本,设置最低要求并封装兼容层;样式方面避免复杂选择器,组件使用注意层级问题;接口和数据方面做好字段容错和异常捕获。
(1)设备兼容性问题处理
- 屏幕适配
-
使用
rpx
单位代替px
,rpx 是相对单位,可以根据屏幕宽度自动缩放,保证在不同尺寸设备上显示一致。 -
避免使用固定宽高值,尽量使用百分比、flex 布局、响应式设计。
- 设备信息获取
- 使用
wx.getSystemInfoSync()
获取设备信息(如屏幕宽度、高度、像素比等),根据不同设备动态调整布局或样式。
- 适配异形屏(如 iPhoneX 及以上)
-
使用
wx.getSystemInfoSync()
判断设备型号,对刘海屏、底部安全区域进行适配,避免内容被遮挡。 -
小程序原生组件支持
custom
模式,可以自定义导航栏,提升兼容性。
(2)微信客户端版本兼容性
- 检查客户端版本
- 使用
wx.getSystemInfoSync()
获取微信客户端版本号,判断是否支持某些新特性或 API。
- API 兼容性处理
-
对于某些新 API,使用
wx.canIUse()
判断当前客户端是否支持该 API,如果不支持,给出降级方案或提示。 -
例如:
wx.canIUse('button.open-type.contact')
可以判断是否支持打开客服按钮。
- 渐进增强策略
- 核心功能在低版本也应可用,新特性作为增强体验使用,避免强依赖高版本功能。
(3)基础库版本兼容性
- 设置最低库版本
- 在
app.json
中设置"requiredPrivateInfos"
或基础库版本限制,确保小程序运行在支持的库版本上。
- 动态降级
- 对于不支持某些功能的旧库版本,可以通过判断版本号,动态隐藏或替换相关功能模块。
- 使用兼容性插件或封装
- 将常用功能封装为兼容层,统一处理不同版本的差异,减少重复判断。
(4)组件和样式兼容性
- 组件样式隔离
-
使用自定义组件时,注意样式作用域问题,避免样式污染。
-
可通过
styleIsolation
设置组件样式隔离级别。
- 避免使用不兼容的 CSS 选择器
-
WXSS 支持的选择器有限,避免使用复杂 CSS 选择器(如
+
,~
,>
等)。 -
推荐使用类名控制样式,提高兼容性。
- 原生组件兼容性
- 某些组件如
map
、video
是原生组件,层级固定,容易被遮挡,需注意 z-index 和布局结构。
(5)接口和数据兼容性
- 接口兼容性
-
后端接口应保持向下兼容,新增字段不影响旧版本使用。
-
小程序端对返回字段做容错处理,避免因字段缺失导致崩溃。
- 数据结构兼容
-
使用默认值处理可能缺失的字段,避免空值报错。
-
使用
try...catch
捕获解析异常,防止 JSON 解析错误。
3、小程序如何实现数据缓存?(了解)
面试回答模板(简洁版)
微信小程序提供了便捷的本地缓存功能,包括同步和异步两种方式。通过 wx.setStorageSync
和 wx.getStorageSync
可以简单地实现数据的存储和读取;而 wx.setStorage
和 wx.getStorage
则提供了异步操作的选择。每个小程序默认拥有 10MB 的缓存空间,虽然微信不自动清理缓存,但开发时应设计合理的缓存管理和同步策略,确保数据的一致性和有效性。
- 同步存储与读取
-
存储数据 :使用
wx.setStorageSync
方法将数据以键值对的形式同步存储到本地缓存中。 -
读取数据 :通过
wx.getStorageSync
方法根据指定的键名同步读取本地缓存中的数据。 -
删除数据 :利用
wx.removeStorageSync
方法根据键名同步删除本地缓存中的特定数据项。 -
清除所有数据 :调用
wx.clearStorageSync
方法可以一次性清除所有的本地缓存数据。
- 异步存储与读取
-
存储数据 :采用
wx.setStorage
方法进行异步存储操作,支持回调函数来处理存储结果。 -
读取数据 :使用
wx.getStorage
方法异步读取缓存数据,同样可以通过回调函数获取结果。 -
删除数据 :通过
wx.removeStorage
方法异步删除指定键名的数据项。 -
获取所有键名 :利用
wx.getStorageInfo
方法可以异步获取当前缓存的所有键名及其相关信息(如大小、数量等)。
- 注意事项
-
缓存限制:每个小程序默认有 10MB 的本地缓存空间,超出限制会导致新的写入失败。
-
缓存有效期:微信小程序的本地缓存没有自动过期机制,需要开发者自行管理数据的有效性。
-
错误处理:无论是同步还是异步操作,都应该考虑异常情况下的错误处理,比如存储失败时给出相应的提示或者重试机制。
- 最佳实践
-
数据一致性:确保本地缓存的数据与服务器端保持一致,尤其是在数据更新频繁的情况下,可能需要设计合理的同步策略。
-
缓存策略:根据实际需求选择合适的缓存策略,例如 LRU(最近最少使用)、TTL(生存时间)等,避免不必要的缓存占用。
-
用户体验优化:合理使用缓存可以显著提升应用的响应速度和用户体验,特别是在网络条件不佳的情况下。
4、小程序如何调用微信原生 API?
面试回答模板(简洁版)
微信小程序通过 wx.
开头的 API 提供原生功能支持,开发者只需按照规范传入参数和回调函数即可调用。例如 wx.request()
用于发起网络请求,wx.getLocation()
获取地理位置,wx.chooseImage()
选择图片等。调用时通常传入一个对象,包含 success、fail、complete 回调。需要注意部分 API 需要用户授权,调用前应检查授权状态并做好失败处理。
- 了解 API 的使用规范
-
微信原生 API 都以
wx.
开头,如wx.request()
、wx.getLocation()
、wx.chooseImage()
等。 -
每个 API 都有对应的参数说明 、成功回调 、失败回调 和完成回调。
-
部分 API 需要用户授权才能调用,如获取位置、相册、通讯录等信息。
- 调用方式
-
微信原生 API 通常采用对象参数调用方式,传入一个包含参数和回调函数的对象。
-
一般支持以下字段:
-
success
:成功时的回调函数 -
fail
:失败时的回调函数(可选) -
complete
:无论成功或失败都会执行的回调(可选) -
其他具体参数,如 URL、数据、超时时间等
-
- 调用流程(以
wx.request
为例)
用文字描述代码逻辑如下:
调用
wx.request
方法,传入一个包含请求地址、请求方法、请求头、请求数据的对象。在成功回调中处理返回的数据,在失败回调中提示用户网络错误或接口异常。
示例(文字描述代码):
-
使用
wx.request()
方法发送一个 GET 请求到指定的 URL。 -
设置
url
参数为接口地址,例如:https://api.example.com/data
-
设置
method
为'GET'
-
设置
success
回调函数,接收返回的数据,并更新页面数据或提示用户。 -
设置
fail
回调函数,提示用户网络异常或接口错误。
- 授权类 API 的调用(如获取用户位置)
以调用
wx.getLocation()
为例:
-
调用
wx.getLocation()
方法,传入一个对象,指定返回的坐标类型(如 gcj02)。 -
如果用户之前未授权定位权限,系统会自动弹出授权提示。
-
成功回调中获取到经纬度等信息,可用于地图展示或业务逻辑。
-
失败回调中判断是用户拒绝授权还是其他错误,进行相应处理(如引导用户去设置授权)。
- 文件和图片上传 API(如
wx.uploadFile
)
以
wx.uploadFile
为例:
-
调用
wx.uploadFile()
方法,设置上传的文件路径、服务器地址、上传字段名等参数。 -
成功回调中获取服务器返回的结果,如文件 ID 或 URL。
-
失败回调中提示用户上传失败或重试。
5、小程序如何实现分享功能?(了解)
面试回答模板(简洁版)
"微信小程序的分享功能主要通过 onShareAppMessage
生命周期函数实现。开发者可以在页面中定义该函数,返回分享的标题、图片和路径信息。用户点击右上角菜单或自定义按钮时,即可触发分享行为。此外,还可以通过 onShareTimeline
实现分享到朋友圈的功能。页面加载时,可以通过 options
参数获取分享来源,用于统计和分析用户行为。
(1)小程序分享功能的实现原理(文字说明)
- 页面级分享功能
-
小程序默认在页面右上角菜单中提供"转发"按钮(即分享功能)。
-
开发者可以通过在页面 JS 文件中定义
onShareAppMessage
生命周期函数,来自定义分享的标题、图片、路径等信息。 -
当用户点击右上角菜单中的"转发"按钮时,微信会调用该函数并弹出分享面板。
- 自定义按钮触发分享
-
除了右上角菜单,开发者还可以在页面中添加一个自定义按钮(如"分享给好友"),通过绑定点击事件来触发分享。
-
在按钮的点击事件中调用
wx.showShareMenu
或直接使用onShareAppMessage
定义的逻辑,实现自定义分享行为。
- 分享内容的配置
-
在
onShareAppMessage
函数中可以返回一个对象,用于配置分享的:-
标题(title):分享卡片的标题
-
图片(imageUrl):分享卡片的缩略图
-
路径(path):分享跳转的页面路径(可携带参数)
-
内容(content):可选,部分场景下显示的简短描述
-
- 分享后的行为追踪
-
微信提供了
onShareTimeline
函数用于支持"分享到朋友圈"的配置。 -
可以通过
wx.getLaunchOptionsSync()
或页面onLoad
中的options
参数获取分享带来的参数,用于统计分享来源或用户行为分析。
(2)实现步骤总结(文字版)
步骤 | 说明 |
---|---|
1. 启用分享菜单 | 默认开启右上角"转发"按钮,或通过 wx.showShareMenu 显式开启。 |
2. 定义分享内容 | 在页面中实现 onShareAppMessage 函数,返回分享标题、图片、路径等信息。 |
3. 自定义按钮触发(可选) | 添加按钮并绑定事件,调用分享逻辑,提升用户点击率。 |
4. 支持朋友圈分享(可选) | 实现 onShareTimeline 函数,定义分享到朋友圈的内容。 |
5. 接收分享参数 | 页面加载时从 onLoad 的 options 中读取分享带来的参数,用于数据分析或页面跳转。 |
三、Uniapp 面试题
基础部分
1、Uniapp 是什么?它有什么优势?
Uniapp 是一个基于 Vue.js 的跨平台开发框架,开发者只需编写一套代码,即可编译到多个平台,包括但不限于:
- 微信小程序
- H5(Web)
- App(iOS 和 Android)
- 百度小程序
- 支付宝小程序
- QQ小程序
- 快应用
它极大地简化了多端开发的复杂度,让开发者能够更专注于业务逻辑的实现,而不是为每个平台单独开发和维护代码。
优势 | 描述 |
---|---|
一次编写,多端运行 | 使用 Vue.js 开发,一份代码可以同时编译成多个平台的应用,减少重复开发工作。 |
高效的开发体验 | 提供丰富的组件和API,支持Vue的语法糖,如v-model 、computed 等,提高开发效率。 |
强大的插件系统 | 支持通过插件扩展功能,例如支付、推送通知等功能,方便快捷地集成第三方服务。 |
良好的生态系统 | 拥有活跃的社区支持,大量的开源组件和模板可供选择,加速项目开发。 |
文档齐全 | 官方提供了详细的文档和教程,覆盖从基础到高级的各个方面,帮助新手快速上手。 |
2、Uniapp 如何实现多端兼容?
- 运行时根据不同平台编译为对应代码
- 条件编译处理平台差异
- 统一的API调用方式
面试回答模板(简洁版)
Uniapp 实现多端兼容的核心在于统一的开发语言(Vue)、统一的 API 调用方式和组件系统。所有平台都使用 Vue 语法开发,通过 uni.xxx()
调用统一接口,内部自动适配不同平台。同时,Uniapp 提供了条件编译机制,可以针对特定平台编写差异代码。构建时会根据目标平台自动转换代码格式,从而实现一次开发、多端运行。
步骤 | 说明 |
---|---|
1. 统一使用 Vue 语法开发 | 所有页面使用 Vue 的单文件组件结构进行开发。 |
2. 使用 uni API 替代原生 API | 所有接口调用统一使用 uni.xxx() 方法,屏蔽平台差异。 |
3. 使用通用组件进行布局 | 页面结构使用 Uniapp 提供的跨平台组件,如 <view> 、<text> 等。 |
4. 条件编译处理平台差异 | 遇到平台特有功能时,使用条件编译编写特定平台代码。 |
5. 编译构建目标平台代码 | 使用 HBuilderX 或命令行工具编译为指定平台的代码(如微信小程序、H5、App 等)。 |
6. 真机测试和调试 | 在不同平台上进行真机测试,确保功能和样式表现一致。 |
3、Uniapp 的生命周期有哪些?
- 应用生命周期:onLaunch, onShow, onHide
- 页面生命周期:onLoad, onShow, onReady, onHide, onUnload
- 组件生命周期:与Vue相同(beforeCreate → created → beforeMount → mounted → beforeUpdate → updated →beforeDestroy → destroyed)
面试回答模板(简洁版)
Uniapp 提供了应用和页面两个层次的生命周期钩子。应用级别的生命周期包括 onLaunch
、onShow
和 onHide
,分别在应用初始化、显示和隐藏时触发。页面级别的生命周期则更为丰富,包括 onLoad
、onShow
、onReady
、onHide
、onUnload
等,覆盖了页面从加载到卸载的全过程。此外,还有专门的钩子用于处理下拉刷新、滚动到底部、分享等功能。
(1)应用生命周期
应用生命周期指的是整个应用从启动到关闭的各个阶段。在 App.vue
文件中定义这些生命周期钩子。
生命周期钩子 | 描述 |
---|---|
onLaunch | 当应用初始化完成时触发(全局只触发一次)。常用于初始化操作,如用户登录检查、数据预加载等。 |
onShow | 当应用启动或从后台进入前台显示时触发。适用于处理应用重新激活时的操作。 |
onHide | 当应用从前台进入后台时触发。适合执行一些资源释放或状态保存的操作。 |
(2)页面生命周期
页面生命周期指的是单个页面从加载到卸载的各个阶段。在每个页面的 .vue
文件中定义这些生命周期钩子。
生命周期钩子 | 描述 |
---|---|
onLoad | 页面加载时触发,参数为页面跳转过来的参数。常用于根据传入参数初始化页面数据。 |
onShow | 页面显示/切入前台时触发。可用于刷新页面数据或恢复页面状态。 |
onReady | 页面初次渲染完成后触发。此时页面 DOM 已经准备好,适合进行一些依赖于 DOM 结构的操作。 |
onHide | 页面隐藏/切入后台时触发。适合暂停定时器、停止动画等操作。 |
onUnload | 页面卸载时触发。可用于清理资源或取消订阅等操作。 |
onPullDownRefresh | 监听用户下拉动作。通常用于实现下拉刷新功能。 |
onReachBottom | 页面滚动到底部时触发。常用于实现分页加载更多内容的功能。 |
onShareAppMessage | 用户点击右上角菜单"转发"按钮时触发。返回自定义的分享信息。 |
onPageScroll | 页面滚动时触发。参数包含页面滚动距离信息,适合监听滚动事件。 |
onTabItemTap | 点击 tab 时触发。参数包含被点击的 tab 信息。适用于底部导航栏相关的交互处理。 |
页面生命周期的特点:
-
页面生命周期钩子允许开发者更精细地控制页面的行为,特别是在页面加载、显示、隐藏和卸载的不同阶段。
-
某些钩子(如
onPullDownRefresh
、onReachBottom
)专为特定的交互场景设计,提供了丰富的用户体验增强手段。
4、Uniapp 如何调用原生功能?
在 UniApp 中调用原生功能主要通过 API 调用 、条件编译 和 原生插件扩展 三种方式实现
5、Uniapp 的页面路由与微信小程序有什么不同?
-
路径写法:
- 微信小程序 :
app.json
的pages
数组里写路径时不带文件后缀 (如"pages/index/index"
)。 - UniApp :
pages.json
的pages
数组里写路径时必须带.vue
后缀 (如"pages/index/index.vue"
)。
- 微信小程序 :
-
路由跳转 API:
- 微信小程序 :使用原生 API,如
wx.navigateTo({ url: '...' })
。 - UniApp :使用统一的
uni.navigateTo({ url: '...' })
等 API。这些 API 在编译时会被转换成对应平台(如微信小程序的wx.navigateTo
)的代码,实现了跨平台兼容。
- 微信小程序 :使用原生 API,如
核心 :UniApp 通过 uni.xxx
API 和 .vue
后缀的路径,在保持与小程序相似配置结构的同时,提供了跨平台能力。
进阶部分
1、Uniapp 如何实现条件编译?
// #ifdef H5
console.log('只在H5平台执行')
// #endif
// #ifdef MP-WEIXIN
console.log('只在微信小程序执行')
// #endif
2、Uniapp 如何优化多端应用的性能?
- 代码分割与懒加载:通过使用分包,可以将应用分割成多个较小的包,在需要时才进行加载。这样可以减少启动时间,提升用户体验。
- 图片资源优化:使用合适的图片格式(如 WebP),并根据设备分辨率提供不同大小的图片资源,以减少加载时间。
- 减少不必要的组件更新 :合理使用
v-if
和v-show
,避免不必要的组件重绘和DOM操作。 - 使用原生组件:在可能的情况下,使用uni-app支持的原生组件来替代H5组件,因为它们通常具有更好的性能。
- 性能监控与分析:利用工具如小程序管理后台提供的性能分析工具,找出性能瓶颈,并针对性地进行优化。
3、Uniapp 如何实现原生插件开发?
- 准备环境:首先确保安装了HBuilderX最新版,并且配置好Android/iOS开发环境。
- 创建插件项目:可以通过HBuilderX创建一个uni-app插件项目,选择相应的平台(Android或iOS)。
- 编写原生代码 :根据需求编写Java(Objective-C/Swift)代码实现功能,然后在uni-app中通过
uni.requireNativePlugin
调用这些本地方法。 - 打包发布:完成开发后,可以将插件打包上传至插件市场供其他开发者使用,或者直接集成到自己的项目中。
4、Uniapp 如何处理多端样式兼容问题?
- 使用条件编译 :针对不同的平台使用
.scss
或.less
预处理器中的条件语句,或者直接在.vue
文件里使用<style platformName>
标签来写特定平台的样式规则。 - rpx单位:uni-app支持rpx作为响应式单位,它会根据不同设备的屏幕宽度自动调整尺寸,从而保证良好的视觉效果。
- Flex布局:尽量采用flex布局,因其能较好地适应不同尺寸的屏幕。
- 自定义变量与混合宏:利用CSS预处理器特性定义一些公共变量和混合宏,简化跨平台样式的维护工作。
5、Uniapp 如何实现热更新?
- 云函数/服务器端部署:首先需要有一个服务器来托管你的新版本应用资源(js、css等文件)。可以是自己的服务器,也可以使用云服务提供商的服务。
- manifest.json配置 :在项目的
manifest.json
文件中开启热更新的相关设置,包括但不限于是否启用热更新、检查更新的周期等。 - 客户端检测更新逻辑:在应用启动时,添加逻辑去请求服务器检查是否有可用的新版本。如果有,则下载并应用更新。
- 注意事项:考虑到安全性和稳定性,建议先在一个小范围内测试热更新的效果,确保没有问题之后再推广给所有用户。同时,遵守各平台关于热更新的规定,以免被封禁。
实战问题
1、Uniapp 如何实现微信登录?
2、Uniapp 如何实现支付功能?
3、Uniapp 如何实现消息推送?
4、Uniapp 如何适配不同屏幕尺寸?
5、Uniapp 如何打包发布到不同平台?
四、跨框架问题
1、Vue、微信小程序和 Uniapp 在数据绑定方面的异同
- Vue:双向绑定,v-model
- 小程序:单向绑定,需手动setData
- Uniapp:类似Vue,但部分平台有限制
2、如何将 Vue 项目迁移到 Uniapp?
- Vue:双向绑定,v-model
- 小程序:单向绑定,需手动setData
- Uniapp:类似Vue,但部分平台有限制
3、Vue 组件和小程序/Uniapp 组件的区别
- 图片懒加载
- 减少DOM节点
- 节流防抖
- 合理使用缓存
- 避免频繁setData
4、如何解决跨平台开发中的样式兼容问题?
5、移动端开发中常见的性能优化手段有哪些?
6、如何实现一套代码适配多个平台?
7、H5、小程序和 App 开发的主要区别是什么?
8、如何调试多端应用?
9、你如何处理不同平台的 API 差异?
五、项目经验相关
1、你做过的最复杂的 Vue/小程序/Uniapp 项目是什么?遇到了什么挑战?
- 跨平台兼容性问题
- 性能优化(如长列表渲染)
- 与原生功能交互
- 多端UI一致性
2、你是如何解决跨平台兼容性问题的?
3、你在性能优化方面做过哪些工作?
- 使用虚拟列表优化长列表
- 图片压缩和懒加载
- 减少不必要的数据响应
- 合理使用缓存策略
4、你如何处理移动端的用户体验问题?
5、你是如何进行移动端测试的?
- 真机测试
- 多平台兼容性测试
- 性能分析工具
- 用户行为测试