Uniapp 面试题及解答
1. 什么是 Uniapp?它的主要特点是什么?
解答: Uniapp 是一个基于 Vue.js 的多端应用开发框架,由 DCloud 开发。它允许开发者使用一套代码同时构建 iOS、Android、H5、小程序(微信、支付宝、百度、字节跳动、QQ、钉钉)、快应用等多个平台的应用。
主要特点:
- 跨平台开发:使用一套代码,编译到多个平台,节省开发成本和时间。
- 丰富的生态系统:兼容 Vue.js 语法,支持丰富的插件和扩展。
- 高性能:通过优化编译和运行时性能,提供接近原生的性能体验。
- 统一的 API:封装了各平台的原生 API,开发者可以使用统一的 API 调用各平台功能。
- 丰富的 UI 组件库:提供了大量预置的 UI 组件,提升开发效率和应用的 UI 一致性。
2. 如何在 Uniapp 中创建一个项目?有哪些基本步骤?
解答: 创建一个 Uniapp 项目可以通过以下步骤实现:
-
安装 HBuilderX:下载并安装 HBuilderX,这是 DCloud 推出的开发工具,集成了 Uniapp 的开发支持。
-
创建项目:
- 打开 HBuilderX,点击“文件”->“新建”->“项目”。
- 在项目模板中选择 “uni-app” 项目模板。
- 设置项目名称和路径,点击“创建”。
-
运行项目:
- 在项目根目录下打开终端,运行
npm install
安装依赖。 - 使用 HBuilderX,可以选择“运行”->“运行到浏览器”或“运行到模拟器”来查看效果。
- 在项目根目录下打开终端,运行
3. Uniapp 的生命周期函数有哪些?它们分别在什么时候触发?
解答: Uniapp 中的生命周期函数与 Vue.js 类似,但也包含了一些特定于不同平台的生命周期函数。常见的生命周期函数如下:
- onLaunch:小程序启动时触发,仅触发一次。
- onShow:小程序启动或从后台进入前台时触发。
- onHide:小程序从前台进入后台时触发。
- onError:小程序发生脚本错误或 API 调用失败时触发。
- mounted:页面挂载完成时触发,相当于 Vue.js 的
mounted
钩子。 - onLoad:页面加载时触发,相当于 Vue.js 的
created
钩子。 - onReady:页面初次渲染完成时触发。
- onUnload:页面卸载时触发。
4. 如何在 Uniapp 中实现页面跳转?
解答: 在 Uniapp 中,可以使用 uni.navigateTo
、uni.redirectTo
、uni.switchTab
等方法实现页面跳转。以下是一些简单的示例代码:
使用 uni.navigateTo
uni.navigateTo
用于保留当前页面,跳转到应用内的某个页面。
uni.navigateTo({
url: '/pages/target/target' // 跳转的目标页面路径
});
// 使用 uni.navigateTo 方法跳转到登录页面 掉接口前判断是否登录
uni.navigateTo({
// 指定要跳转的页面的 URL
url: '/pages/login/login',
// 'complete' 函数是一个回调函数,它会在导航尝试完成后执行,无论成功与否
complete: () => {
// 显示一个提示框通知用户
uni.showToast({
// 设置提示框的标题(消息内容)
title: '请先登录!', // 这句话的意思是“请先登录!”
// 设置提示框的图标。'none' 表示不显示图标
icon: 'none'
});
}
});
// 在起始页面跳转到test.vue页面,并监听test.vue发送过来的事件数据
uni.navigateTo({
url: '/pages/test?id=1',
events: {
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
acceptDataFromOpenedPage: function(data) {
console.log(data)
},
someEvent: function(data) {
console.log(data)
}
...
},
success: function(res) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'data from starter page' })
}
})
// 在test.vue页面,向起始页通过事件传递数据
onLoad: function(option) {
const eventChannel = this.getOpenerEventChannel();
eventChannel.emit('acceptDataFromOpenedPage', {data: 'data from test page'});
eventChannel.emit('someEvent', {data: 'data from test page for someEvent'});
// 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
eventChannel.on('acceptDataFromOpenerPage', function(data) {
console.log(data)
})
}
使用 uni.redirectTo
uni.redirectTo
关闭当前页面,跳转到应用内的某个页面。
在项目中 充值审核结果页面 如果在当前界面,会持续请求查询的状态结果,将结果最终展示出来;所以跳转到其他页面后 关闭当前页面
uni.redirectTo({
url: '/pages/manage/recharge-record/recharge-record' // 跳转的目标页面路径
});
使用 uni.switchTab
uni.switchTab
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
uni.switchTab({
url: '/pages/home/home' // 跳转的 tabBar 页面路径
});
uni,reLaunch 销毁所有页面跳转至指定页面
uni.navigateBack 返回上一页
exit 退出小程序,target = "miniProgram"时生效
5. Uniapp 中如何调用原生设备功能,比如相机或地理位置?
解答: Uniapp 提供了统一的 API 来调用原生设备功能。以下是调用相机和获取地理位置的示例代码:
调用相机
uni.chooseImage({
count: 1, // 默认 9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
var tempFilePaths = res.tempFilePaths; // 图片的本地文件路径列表
console.log(tempFilePaths);
},
fail: function (err) {
console.error('Failed to choose image:', err);
}
});
获取地理位置
- **WGSwgs8484**:适用于全球定位和导航系统,以及需要全球统一坐标的应用。
- **gcj02**:主要适用于中国大陆境内的地图应用和位置服务,以及涉及到国家安全或地理信息保护的应用场景。
uni.getLocation({
type: 'wgs84', // 返回 gps 坐标,默认为 wgs84
success: function (res) {
var latitude = res.latitude; // 纬度
var longitude = res.longitude; // 经度
console.log('Latitude:', latitude, 'Longitude:', longitude);
},
fail: function (err) {
console.error('Failed to get location:', err);
}
});
使用 Pinia
安装 Pinia
npm install pinia --save
创建 Pinia Store
// store/container.js
// 导入 Pinia 库中的 defineStore 方法
import {
defineStore
} from 'pinia';
// 定义名为 'container' 的状态仓库,并导出
export const useContainerStore = defineStore('container', {
// 定义状态(state),返回一个对象
state: () => ({
// 用户信息
userInfo: {
id: '', // 用户ID
mobile: '', // 手机号码
name: '', // 姓名
},
// 当前车辆信息
currCarInfo: {
label: '选择车辆', // 车辆标签
id: '', // 车辆ID
index: 0, // 车辆索引
},
// 车辆列表
carList: [
[]
], // 初始为空的二维数组
}),
// 定义动作(actions),这里暂时没有具体的动作函数
actions: {
// 可以在这里定义各种操作状态的方法,例如更新用户信息、添加车辆信息等
},
// 持久化配置,表示状态的持久化设置
persist: {
enabled: true, // 启用状态持久化
// 在这里可以设置更多持久化的配置,如存储位置、键名等
}
});
在项目中使用 Pinia
pinia持久化插件
# npm
npm install pinia-plugin-persist
# yarn
yarn add pinia-plugin-persist
# pnpm
pnpm add pinia-plugin-persist
// main.js
// 导入 App 组件
import App from './App'
// 导入 uview-plus 组件库(uView UI 框架)
import uviewPlus from '@/uni_modules/uview-plus'
// 导入 Pinia 相关依赖
import { createPinia } from 'pinia' // 导入 Pinia 的 createPinia 方法
import piniaPersist from 'pinia-plugin-persist-uni' // 导入 Pinia 的持久化插件
// #ifndef VUE3
// 在 Vue 2 环境下的处理
import Vue from 'vue' // 导入 Vue 库
import './uni.promisify.adaptor' // 导入适配器(可能是用于兼容 Uni-App 中的某些异步操作)
Vue.config.productionTip = false // 配置 Vue 的生产提示为 false
App.mpType = 'app' // 指定 App 类型为 'app'
const app = new Vue({
...App // 创建 Vue 应用,传入 App 组件配置
})
app.$mount() // 手动挂载应用
// #endif
// #ifdef VUE3
// 在 Vue 3 环境下的处理
import { createSSRApp } from 'vue' // 导入 Vue 3 的 createSSRApp 方法
const Pinia = createPinia() // 创建 Pinia 实例
Pinia.use(piniaPersist); // 使用 Pinia 的持久化插件
export function createApp() { // 导出 createApp 函数,用于创建应用
const app = createSSRApp(App) // 创建 Vue 3 SSR 应用,传入 App 组件
app.use(uviewPlus); // 在应用中使用 uView Plus 组件库
app.use(Pinia); // 在应用中使用 Pinia 状态管理
return {
app, // 返回创建的应用实例
Pinia // 返回 Pinia 实例,以便在需要时进行访问
}
}
// #endif
在组件中使用 Pinia 状态
// index.vue
<template>
<view>
<view>{{ Container.userInfo }}</view>
</view>
</template>
<script setup>
import { useContainerStore } from '@/stores/container';
const Container = useMainStore();
}
</script>
7. Uniapp 中如何处理异步请求?
解答: 在 Uniapp 中,可以使用 uni.request
方法进行 HTTP 请求。以下是一些详细的示例:
import {
useContainerStore
} from '@/stores/container';
// 设置基础 URL
let baseUrl = '';
// #ifdef MP-WEIXIN || APP-PLUS
// 小程序和 APP 端的基础 URL
baseUrl = http://192.168.110.142:9812/app-api-driver';
// baseUrl = 'http://192.168.110.142:9812/app-api-driver'; // 本地开发调试用的基础 URL
// #endif
// #ifdef H5
// H5 端的基础 URL,根据开发环境选择不同的地址
baseUrl = process.env.NODE_ENV === 'development' ? '/devHost' : http://192.168.110.142:9812/app-api-driver';
// #endif
// 带 Token 请求的函数
const httpTokenRequest = (opts) => {
let Container = useContainerStore(); // 使用状态管理器获取容器
let token = uni.getStorageSync('accessToken'); // 获取本地存储的 accessToken
let httpDefaultOpts = {
url: `${baseUrl}/${opts.url}`, // 拼接完整的请求 URL
data: opts.data,
method: opts.method || 'GET',
header: opts.method == 'get' ? { // 根据请求方法设置不同的请求头
'token': token,
'X-Requested-With': 'XMLHttpRequest',
"Accept": "application/json",
"Content-Type": opts.ContentType,
"tenant-id": "1"
} : {
'token': token,
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': opts.ContentType,
"tenant-id": "1"
},
dataType: 'json',
};
let promise = new Promise(function(resolve, reject) {
// 发起请求
uni.request(httpDefaultOpts).then((res) => {
if (res.statusCode === 404) { // 处理 404 错误
uni.showToast({
title: '接口未找到',
icon: 'none'
});
} else if (res.data.code === 401) { // 处理 token 失效或未认证错误
uni.clearStorageSync(); // 清空本地存储中的登录信息
uni.navigateTo({
url: '/pages/login/login' // 跳转到登录页
});
} else if (res.data.code === 0 || res.data.code === 1) { // 处理成功返回数据的情况
resolve(res.data); // 将返回数据传递给调用者
} else if (res.data.code === 502) { // 处理系统繁忙的情况
uni.showToast({
title: '系统繁忙',
icon: 'none'
});
} else {
resolve(res.data); // 其他情况直接将数据传递给调用者
}
}).catch((response) => {
reject(response); // 处理请求异常
});
});
return promise; // 返回 Promise 对象
};
// 导出带 Token 请求函数
export default httpTokenRequest;
import request from "./request";
发送 GET 请求
export function getOpenidApi(data) {
return request({
url: 'wx/app/getUserBaseInfo', // 接口地址
method: 'get',
ContentType: "application/json; charset=UTF-8",
data
})
}
发送 POST 请求
export function wechatLogin(data) {
return request({
url: 'wx/app/loginPhoneOpenid',
method: 'post',
ContentType: "application/json; charset=UTF-8",
data
})
}
8. Uniapp 中如何进行组件通信?
解答: 在 Uniapp 中,可以使用 Vue.js 的组件通信机制,包括 props、events、自定义事件和 Vuex 或 Pinia 状态管理等。以下是一些常见的组件通信方法:
父组件向子组件传递数据(使用 props)
子组件向父组件传递数据(使用事件 events)
使用 Vuex 进行全局状态管理
如前面所述,可以使用 Vuex 进行全局状态管理,将数据存储在 Vuex 中,组件之间共享状态。
使用 Pinia 进行全局状态管理
如前面所述,可以使用 Pinia 进行全局状态管理,将数据存储在 Pinia 中,组件之间共享状态。
9. UniApp中,条件编译。
平台判断条件: UniApp支持根据不同的平台进行条件编译,常见的平台有:h5、app-plus、mp-weixin、mp-alipay等。
```
#ifdef H5
// 在H5平台下编译的代码
#endif
#ifdef APP-PLUS
// 在App平台下编译的代码
#endif
#ifdef MP-WEIXIN
// 在微信小程序下编译的代码
#endif
// 可以根据需要添加更多平台的判断
```
###. 环境变量: 可以通过配置环境变量来进行条件编译。
在 `manifest.json` 或 `vue.config.js` 中配置环境变量:
```
{
"h5": {
"env": {
"BASE_URL": "/",
"ENV_TYPE": "h5"
}
},
"app-plus": {
"env": {
"BASE_URL": "https://api.example.com/",
"ENV_TYPE": "app"
}
}
}
```
然后在代码中根据环境变量进行条件判断:
```
if (process.env.ENV_TYPE === 'h5') {
// H5环境下的代码
} else if (process.env.ENV_TYPE === 'app') {
// App环境下的代码
}
```
全局变量判断: UniApp提供了一些全局变量,可以根据这些变量进行条件编译。
```
if (uni.getSystemInfoSync().platform === 'android') {
// Android平台下的代码
} else if (uni.getSystemInfoSync().platform === 'ios') {
// iOS平台下的代码
}
```
这些方法可以根据需要灵活地在不同平台或环境下执行特定的代码逻辑,确保应用在各个平台的兼容性和功能性。
10.uni-app项目的目录树结构
uniCloud —— uniCloud云服务的目录
components —— 存放可复用的组件
├── comp-a.vue —— 可复用的a组件
hybrid —— App端存放本地HTML文件的目录
platforms —— 存放各平台专用页面的目录
pages —— 业务页面文件存放的目录
└── static —— 存放本地静态资源
uni_modules —— 存放符合uni_module规范的插件
wxcomponents —— 存放小程序组件的目录
main.js —— Vue初始化入口文件
App.vue —— 应用配置,用来配置App全局样式以及监听
manifest.json —— 配置应用名称、App ID、logo、版本等打包信息
page.json —— 配置页面路由、导航条、选项卡等页面类信息
uni.scss —— uni-app内置的常用样式变量
11. 如何在 Uniapp 中调试代码?
解答: 在 Uniapp 中,可以通过多种方式调试代码,包括使用 HBuilderX、自带的调试工具和浏览器开发者工具。
使用 HBuilderX 调试
- 实时预览:在 HBuilderX 中打开项目,选择“运行”->“运行到浏览器”或“运行到模拟器”。
- 断点调试:在代码中设置断点,使用 HBuilderX 的调试工具进行断点调试。
- 日志输出:使用
console.log
输出调试信息到控制台。
使用浏览器开发者工具调试 H5 应用
- 运行到浏览器:在 HBuilderX 中选择“运行到浏览器”,然后打开浏览器开发者工具(F12)。
- 调试代码:在开发者工具中设置断点,查看日志和网络请求等。
使用小程序开发工具调试小程序
- 编译到小程序:在 HBuilderX 中选择“发行”->“小程序-微信”。
- 使用微信开发者工具:打开微信开发者工具,导入生成的项目,进行调试。