本文写作已有一年半了迁移自老博客。系统梳理了uni-app开发小程序与web开发的异同,踩坑笔记。另外简单介绍了Uniapp框架小程序端的设计思路。
uni-app理念
- 为开发者提供免费、高效的开发工具,让天下没有难做的应用
- 改进应用形态,让用户更方便的获取数字服务
uncloud
解决小程序云开发跨平台问题api
与微信一致weex
原生渲染vue
的语法微信的api
mpvue
npm
引用第三方包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
使用 env
anroid
建议给一个默认高度就好一般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
不需要生成VNode
diff
,然后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_ENTRY
module-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:if
v-for
>> wx:for
v-model="myModel"
>> value={{myModel}}
/bindinput
/setData
this.key
>> this.data.key
@event
>> bindtap="" catchtap=""
:prop
>> bind:prop
this.$emit('myevent', data)
>> this.triggerEvent('myevent', data)
$refs
>> selectComponent
import
+ 配置components
>> 子组件component: true
父组件 配置useComponents
此外还有一些loader
webpack-preprocess-loader
处理条件编译wrap-loader
自动引入个平台运行时兼容减少调用setData数据量
Vue
的patch
实现,删掉了vnode
,仅Diff Data
数据 (包减少30%)nextTick
机制保证不会重复setData
JSON Diff
实现高效、精准的差量数据差量更新的本质是调用小程序的setData方法(小程序支持setData本身支持细粒度更新)this.setData({'obj.list.0.name': '细粒度更新'})
以下内容为草稿
uniapp项目升级
npx @dcloudio/uvm
npx @dcloudio/uvm 3.2.12.20211029
本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!