1. 如何实现父子组件的双向数据绑定?对比.sync
修饰符与自定义v-model
的差异
-
双向绑定实现:
-
.sync
修饰符 :父组件通过:prop.sync="value"
传递数据,子组件通过this.$emit('update:prop', newValue)
更新。 - **自定义
v-model
**:在子组件中定义model
选项,指定prop
和event
名称,父组件使用v-model
绑定。
-
javascript
// 子组件
model: { prop: 'value', event: 'change' },
props: { value: String },
methods: { updateValue(val) { this.$emit('change', val) } }
-
差异:
.sync
支持多个属性双向绑定,v-model
通常用于单一数据源(如表单输入)。v-model
默认绑定value
属性和input
事件,.sync
更灵活,可自定义事件名。
2. UniApp中如何实现页面预加载(预渲染)?说明onReachBottom
和onPullDownRefresh
的优化策略
- 页面预加载:
使用uni.preloadPage({ url: '/pages/detail' })
提前加载目标页面资源,提升用户体验。
-
优化策略:
-
**
onReachBottom
(上拉加载)** :- 分页请求数据,避免一次性加载过多数据。
- 使用防抖(
debounce
)避免重复触发。 - 显示加载状态(如"加载中..."),数据加载完成后隐藏。
-
**
onPullDownRefresh
(下拉刷新)** :- 调用
uni.startPullDownRefresh()
和uni.stopPullDownRefresh()
控制刷新状态。 - 刷新后重置分页参数,清空旧数据重新加载。
- 调用
-
3. 如何处理UniApp中跨端字体图标(如Iconfont)的兼容性问题?
- 条件编译字体文件路径:
css
/* #ifdef H5 */
@font-face { src: url('/static/fonts/iconfont.ttf'); }
/* #endif */
/* #ifdef MP-WEIXIN */
@font-face { src: url('https://cdn.example.com/iconfont.ttf'); }
/* #endif */
- Base64内联:将字体转换为Base64嵌入CSS,避免路径问题。
- 动态加载 :使用
uni.loadFontFace({ family: 'iconfont', source: 'url(...)' })
。
4. 如何封装一个支持插槽和自定义样式的弹窗组件?
xml
<!-- 弹窗组件 -->
<template>
<view v-if="visible" class="modal">
<view class="modal-content" :style="{ width: width }">
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</view>
<view class="modal-mask" @click="close"></view>
</view>
</template>
<script>
export default {
props: {
visible: Boolean,
width: { type: String, default: '80%' }
},
methods: {
close() { this.$emit('update:visible', false); }
}
};
</script>
关键点:
- 使用具名插槽(
name="header"
)和默认插槽。 - 通过
props
传递样式参数(如宽度)。 - 点击遮罩层触发
close
事件,父组件通过v-model
控制显隐。
5. 解释UniApp的uni.$once
和uni.$off
的使用场景,如何避免全局事件重复触发?
- **
uni.$once
**:监听一次事件,触发后自动解绑。适用于单次回调(如页面跳转后获取结果)。 - **
uni.$off
**:手动解绑事件,避免内存泄漏。 - 避免重复触发:
javascript
// 页面销毁时解绑事件
onUnload() { uni.$off('customEvent'); }
// 使用命名空间区分事件
uni.$on('pageA:event', () => { ... });
6. 如何实现一个支持懒加载和错误占位的图片组件?
xml
<template>
<view>
<image
v-if="loaded"
:src="src"
@error="handleError"
:style="{ display: error ? 'none' : 'block' }"
/>
<image v-else :src="placeholder" />
</view>
</template>
<script>
export default {
props: ['src', 'placeholder'],
data() {
return { loaded: false, error: false };
},
mounted() {
// 监听图片进入视口后加载
const observer = uni.createIntersectionObserver(this);
observer.relativeToViewport().observe('.lazy-img', () => {
this.loaded = true;
observer.disconnect();
});
},
methods: {
handleError() { this.error = true; }
}
};
</script>
7. UniApp中如何集成第三方原生SDK(如高德地图)?说明Android/iOS的差异化配置
-
原生插件开发:
- Android:将SDK的
.aar
或.jar
文件放入nativeplugins/amap/android
目录,配置dependencies
。 - iOS:将SDK的
.framework
文件放入nativeplugins/amap/ios
目录,配置Podfile
。
- Android:将SDK的
-
UniApp调用:
ini
const amap = uni.requireNativePlugin('amap');
amap.init({ key: 'your-key' });
-
差异化处理:
- Android需配置
manifest.json
的permissions
(如定位权限)。 - iOS需在
Info.plist
中添加NSLocationWhenInUseUsageDescription
。
- Android需配置
8. 如何优化UniApp的启动速度?列举至少三种性能优化手段
- 分包加载 :在
pages.json
中配置subPackages
,将非首屏页面拆分。 - 资源懒加载 :图片使用
v-lazy
或动态加载,组件按需引入。 - 减少全局样式 :避免在
App.vue
中定义过多全局样式。 - 启用压缩 :使用
uni-app
构建时的optimization
选项压缩代码。
9. 如何处理UniApp在微信小程序中tabBar
动态显示/隐藏的需求?
scss
// 在页面onShow生命周期中控制
onShow() {
if (需要隐藏) {
uni.hideTabBar({ animation: false });
} else {
uni.showTabBar();
}
}
注意:
- 使用
getCurrentPages()
判断页面栈,避免误操作。 - 部分安卓机型需在
setTimeout
中调用API确保生效。
10. 如何实现UniApp应用的热更新(无需重新发布)?说明技术方案与限制
-
技术方案:
- 生成wgt包 :通过HBuilderX生成
.wgt
文件,包含更新代码。 - 服务端更新 :客户端检测版本号,下载wgt包后调用
uni.applyUpdate()
静默更新。
- 生成wgt包 :通过HBuilderX生成
-
限制:
- 小程序端无法热更新(需重新提审)。
- iOS对热更新有严格审核限制(需谨慎使用)。
-
降级方案:H5端可通过CDN动态更新资源。