一、什么是 uni-app
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
并且兼容对于小程序的场景,其他场景(例如H5),功能也会有所影响;同时还会存在在不同场景表现不一致的情况(他们的底层原理毕竟是不同的)
二、使用 cli 创建项目和使用 HBuilderX 可视化界面创建项目有什么区别
编译器的区别
cli 创建的项目,编译器安装在项目下。并且不会跟随HBuilderX升级。如需升级编译器,执行 npm update,或者手动修改 package.json 中的 uni 相关依赖版本后执行 npm install。更新后可能会有新增的依赖并不会自动安装,手动安装缺少的依赖即可。
HBuilderX可视化界面创建的项目,编译器在HBuilderX的安装目录下的plugin目录,随着HBuilderX的升级会自动升级编译器。
已经使用cli创建的项目,如果想继续在HBuilderX里使用,可以把工程拖到HBuilderX中。注意如果是把整个项目拖入HBuilderX,则编译时走的是项目下的编译器。如果是把src目录拖入到HBuilderX中,则走的是HBuilderX安装目录下plugin目录下的编译器。
cli版如果想安装less、scss、ts等编译器,需自己手动npm安装。在HBuilderX的插件管理界面安装无效,那个只作用于HBuilderX创建的项目
开发工具的区别
发布App时,仍然需要使用HBuilderX。其他开发工具无法发布App,但可以发布H5、各种小程序。如需开发App,可以先在HBuilderX里运行起来,然后在其他编辑器里修改保存代码,代码修改后会自动同步到手机基座
如果使用cli创建项目,那下载HBuilderX时只需下载10M的标准版即可。因为编译器已经安装到项目下了。
三、条件编译解决各端差异
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同的平台。写法:以 #ifdef 或 #ifndef 加 %PLATFORM% 开头,以 #endif 结尾 可参考
#ifdef: if defined 尽在某平台存在
#ifndef: if not defined 除了某平台均存在
%PLATFORM%: 平台名称
四、编译原理相关
uni-app能打包到不同的平台,跟它的编译原理相关,即是对于不同的平台有着不同的打包策略;
通过 cli 的方式本地编译更方便了解他的整个流程。
H5 环境
基本的场景,构建情况和 web 端基本是一致的,但是由于模拟兼容小程序场景,代码会做一定的调整和适配,会写一些用于兼容和处理 webpack loader 和 plugin 。 可参考
微信小程序
小程序的编译会麻烦一些,template 的编译内部采用了 mpvue,进行了模版语法的转化。并且由于小程序需要有指定的文件产出(例如 index.js、index.json等),所以对 webpack 的文件输出就需要做兼容,基本通过 webpack plugin 完成。可参考
原理参考
总结
web 开发、轻应用(小程序等)、App 不同平台下,会有不同的底层原理实现。
webpack loader plugin 的开发及使用场景值得借鉴,代码的组织方式和架构设计方面同样值得思考。
五、H5 项目中遇到的问题
input 等组件渲染的问题 可参考
H5 环境下,页面缓存问题:uni-app 为保持和小程序端一致,对页面做了缓存处理,即后退不刷新页面(这种表现和小程序的实现原理有关)
内部用了 keep-alive 做了路由缓存
scroll-view 组件 当设置 scrollTop 时,会出现滑动抖动的情况
尽量不去设置 scrollTop,或尝试降低视图层和逻辑层的交互频率
h5 环境 使用浏览器 history api,防止 uniapp 刷新之后丢失历史记录(可调用 vue-router api 处理)
// App.vue
this.$router.go(-1);
h5 环境 动画实现:uni.createAnimation 的原理相关
animation属性:收集动画节点的样式队列。依赖 setTimeout 逐一变更 style 属性,实现动画效果
setTimeout 并不能保证当前动画一定执行完成,应该采用事件绑定比较好。
android 平台 当调起相册选择图片时,会触发页面级的生命周期函数 onHide、onShow
页面进行前进跳转时,会执行 onHide 函数
// 判断真正执行 onHide 的时机
const pathname = getLogicPathname();
this.$nextTick(() => {
const nextPathname = getLogicPathname();
if (pathname !== nextPathname) {
// 此时离开真正离开了当前页面
}
});
处理页面后退操作
onBackPress: function() {
// 后退时的处理逻辑
},
onUnload: function() {
// 后退时的处理逻辑
}
此时 Vue 的生命周期函数是不可靠的。微信小程序环境下,是由不同的webview实现的,不会做销毁动作。web 环境实现原理待调研
六、微信小程序项目中遇到的问题
- 图片上传不支持批量上传,需要一张张递归上传
- 回退页面不会重新刷新渲染页面,请求数据函数,需要写到 onShow 函数中
- 切换 tabBar 页面 uni.switchBar({ url: ‘url’ }), 无法携带查询参数,可以通过 globalData 及 发布订阅模式解决
- 图片尽量是用二倍的外链图片,防止打包超出体积
- 小程序的生命周期函数,必须用在最外层的页面,例如 onShow 等,所以在子组件的 mounted 函数请求接口数据,可能第二次会无法执行
- 第一次发布需要提前一周提审