本文写作已有一年半了迁移自老博客。系统梳理了uni-app开发小程序与web开发的异同,踩坑笔记。另外简单介绍了Uniapp框架小程序端的设计思路。
uni-app理念
- 为开发者提供免费、高效的开发工具,让天下没有难做的应用
- 改进应用形态,让用户更方便的获取数字服务
uncloud 解决小程序云开发跨平台问题api 与微信一致weex原生渲染vue的语法微信的apimpvuenpm引用第三方包mpvue组件及项目App端支持和原生混合编码DCloud将发布插件市场vue语法开发h5端支持vue的完整语法app和小程序实现了大部分vue语法uni-app并不难学,但我们注意到很多新人在适应各个平台的规则限制时比较急躁。 每个端,有每个端的管理规则,这不是uni-app在技术层面上可以抹平的:
- 比如H5端的浏览器有跨域限制;
- 比如微信小程序会强制要求https链接,并且所有要联网的服务器域名都要配到微信的白名单中;
- 比如App端,iOS对隐私控制和虚拟支付控制非常严格;
- 比如App端,Android、国产rom各种兼容性差异,尤其是因为谷歌服务被墙,导致的push、定位等开发混乱的坑;
- 如果你的App要使用三方sdk,比如定位、地图、支付、推送...还要遵循他们的规则和限制;
遇事耐心,不急不躁,虽然这不是成功的唯一要素,但它是你技术路上长远走下去的基础。
本人有一年多的
uni-app开发三端(h5、微信小程序、支付宝小程序),老实说跨端的坑太多了,尤其是早期。 下面的踩坑总结 也说明uni-app跨端只做了浅层磨平。事实上根据uniapp官网文档 跨端注意 、 非h5端不支持的的vue语法 这两篇文章的介绍,真正属于
uniapp的坑很少, 官方文档也只是说了大概,还有很多坑时来自h5与小程序差异的细节(比如IntersectionObserver、下拉刷新)
准确来说这一块并非uni-app问题,以下内容是本人使用uni-app项目开发中遇到的问题。
calc函数 ios 10系统不支持, android有些低版本也不支持具体版本记不清了position: fixed
transform, 然后其子元素fixed-to-container便以父元素为参考对象了。这其实也不算是兼容性问题,属于CSS知识点了fixed布局 微信小程序的上拉刷新ios 10 不支持 HTMLElement.style直接赋值,推荐使用setAttribute方法autofocus
h5 andriod上会自动聚焦但不会弹软键盘,但如果手动点击过一次,再focus方法就可以了h5 ios上 既不会自动聚焦也不会弹软键盘,但手动点击过一次后,再调用focus方法就可以了overflow:hidden,在开启scroll11.0 ~11.2(不包含) 使用 constant>=11.2 使用 envanroid建议给一个默认高度就好一般40px, 或者让app提供bridge方法获取状态栏高度position:sticky 在 android 5~6系统中存在兼容问题scoped不生效scroll-view中如果有fixed布局,在ios手机中滚动会出现一些奇怪的渲染问题scroll-view
scroll-view区域,不能使用小程序的下拉刷新功能@scrolltolower (原生bindscrolltolower)事件,滑动过快可能不会触发,可以把lower-threshold设置大一点,会缓解很多很多。v-else-if v-else:style="customeStyle" 但是支持 :style="{height: customeHeight}"v-for="it in list.slice(0,3)" 小程序上不支持 ,要这样写 v-for="it in computedList"<comp :text="getText(classes[index])"></comp> 不支持,要写成 :test(getText(index)){this.$emit('input', 123); this.$emit('select', 123)}v-show 微信小程序组件上v-show不生效
uniapp官方对组件上v-show不支持的解释
因为小程序没有v-show,只有if,
另外还有hidden这个属性,但这个是作为属性而不是条件控制。
所以如果打算生成小程序的话,还是用v-if来控制,非要用v-show的话,可以自己通过style模拟这个效果。
小程序对变量赋值undfined不会触发刷新 原因点这里
e.preventDefault e.stopPropagation 不支持条件控制,只能在模版上写死
uni.createIntersectionObserver 该API坑比较多
reactiveToViewport
observe
easycom的bug,不支持作用域插槽
先来看一个案例
左侧是h5 右侧是 微信小程序
之所以渲染的结果不一样 是因为微信小程序的组件使用后了 ShadowDOM(这个差异正式ShadowDom产生的)
解决方案
<testComp class="hack"></testComp> .hack{width: 100%}:host {width: 100%}讲道理 如果使用了ShadowDOM那么样式应该是隔离的,
事实上确实有部分东西是隔离的如css变量的获取,但组件的样式却不是隔离的,也就是 使用 .content .test-comp{} 外层可以修改组件样式。
后来看了下微信的文档 ,微信小程序使用的Exparser框架,Exparser的组件模型与WebComponents标准中的ShadowDOM高度相似,但并非完全一致
补充: 支付宝小程序自定义组件没有使用WebComponets技术。
class不生效my.getSystemInfo 返回值有属性screenWidth是逻辑宽度(物理宽度*像素比DPR)slot不支持备用插槽@touchmove.stop.prevent不生效vue的生命周期onShow开启, 在onHide onUnload生命周期中销毁onShow onHide方法, 详见这里onHide跳到其它页面触发 onUnload在redirectTo或navigateBack时触发注: 这里是官方文档的两张图,先体会一下。


总结
uniapp以微信小程序API为基准,把通用的组件和接口都uni化了uni-app是比较传统的小程序框架,包括编译器和运行时。
小程序是视图层和逻辑层分开的双线程架构。
那么我们来分析一下使用Vue开发的代码如何在微信小程序上运行呢?
page.json,那么对于uni-app来说就需要多入口打包,生成小程序各页面所需JS。这两步是编译器做的事情,除此之外还有css的转换。data-event-opts上)
compile不需要静态标注render不需要生成VNodediff,然后setData思路有了,还是建议在 uni-app项目中通过 JavaScript调试终端 运行npm run build:mp-weixin命令进行调试, 入口文件是node_modules/.bin/vue-cli-server,在这里设置断点。
可以参考这篇文章《uni-app是如何构建小程序的》 边读边调试。好文章在我这里绝不藏着掖着,也绝不照搬抄袭,这里我也偷个懒,以下内容记录我个人的总结,不做深入解读,仅供参考。
uni-app runtime 主要做了三件事情

uni-app 是基于 vue-cli 的扩展vue-cli 运行会加载 package 的 devDependencies 对象中 以 vue-cli-plugin-* 命名的插件,即加载 @dcloudio/vue-cli-plugin-uni 插件vue-cli 的插件机制在执行插件时会传入两个参数一个是service实例对象(有个plugins属性包含所有插件实例),一个是webpack参数对象,有了这两个参数,@dcloudio/vue-cli-plugin-uni可以做任何事情。@dcloudio/vue-cli-plugin-uni做了以下事情
lib/mp.js, mp.js会一个新的webpack参数对象,它内部会解析pages.json生成多入口对象process.UNI_ENTRY,即webpack参数对象的entry属性,entry: () => process.UNI_ENTRYmodule-alias修改template编译指向,分发个平台webpack-preprocess-loader 处理条件编译webpack-uni-pages-loader 该 loader 作用于 src/pages.json,解析生成项目及各页面的 config,并配合 wrap-loader 将转换后的结果引入 src/main.js 中wrap-loader 自动引入各平台运行时兼容vue-loader会把vue拆分为template、style、script三块内容再分发给不同的loader。 uni-app则对vue-loader的分发进行了更改js{
resourceQuery: /vue&type=script/,
use: [{
loader: '@dcloudio/webpack-uni-mp-loader/lib/script'
}]
},
{
resourceQuery: /vue&type=style/,
use: [{
loader: '@dcloudio/webpack-uni-mp-loader/lib/style'
}]
}
{
resourceQuery: /vue&type=template/,
use: [{
loader: '@dcloudio/webpack-uni-mp-loader/lib/template'
}]
}
uni-mp-loader/lib/template.js 把vue模版语法转换为小程序模板语法uni-mp-loader/lib/script.js 使用babel对js句法翻译,生命周期映射、事件代理等uni-mp-loader/lib/style.js 多插入一些nomaliize样式用于磨平平台差异vue语法转成小程序语法
:key="val" >> key={{val}}v-show/v-if >> hidden/wx:ifv-for >> wx:forv-model="myModel" >> value={{myModel}}/bindinput/setDatathis.key >> this.data.key@event >> bindtap="" catchtap="":prop >> bind:propthis.$emit('myevent', data) >> this.triggerEvent('myevent', data)$refs >> selectComponentimport + 配置components >> 子组件component: true 父组件 配置useComponents此外还有一些loader
webpack-preprocess-loader 处理条件编译wrap-loader 自动引入个平台运行时兼容
减少调用setData数据量
Vue的patch实现,删掉了vnode,仅Diff Data数据 (包减少30%)nextTick机制保证不会重复setDataJSON Diff 实现高效、精准的差量数据差量更新的本质是调用小程序的setData方法(小程序支持setData本身支持细粒度更新)this.setData({'obj.list.0.name': '细粒度更新'})
以下内容为草稿
uniapp项目升级
npx @dcloudio/uvm npx @dcloudio/uvm 3.2.12.20211029本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!