2

微信小程序迁移支付宝踩坑

 1 year ago
source link: https://mirari.cc/2023/06/02/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%BF%81%E7%A7%BB%E6%94%AF%E4%BB%98%E5%AE%9D%E8%B8%A9%E5%9D%91/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

微信小程序迁移支付宝踩坑

2023-06-02 学习笔记

5.7k 5 分钟

需要迁移的小程序是原生的微信小程序,涉及大量微信小程序的原生api和功能,工作量不小。

首先还是要用到迁移工具Antmove,可惜这个工具已经多年未更新,生成的代码必然是没法直接运行的,而且后来的使用中发现,有一些支付宝原本不支持的功能做了降级适配,实际上现在已经支持了,而Antmove做的处理反而会出问题。

基础的迁移操作和差异对比可参考以下文章:

一些微信小程序和支付宝小程序对应的差异

微信小程序迁移到支付宝记坑

这边只记录我遇到的问题:

目前只能做到自身不影响外部,但外部始终能影响内部。

因此所有自定义组件的样式如果起得过于简单,一旦冲突,都需要重新命名。

如果有的页面样式很多,其中有些希望影响内部,有些又不希望影响的话,只能重命名那些不希望影响组件的,确保样式名唯一。

页面样式隔离

如何防止页面样式影响到组件内部?

background-image不支持,需要改为image组件写法。

获取子组件 selectComponent

Antmove抹平了查找子组件的差异,从而保留了selectComponent(s)方法。

由于要尽量保留微信原生写法,这里后面提到的获取子组件都指的是包装过的selectComponent

在生命周期的onLoad和onShow时不能使用查找子组件,此时拿不到对象,需要套一层setTimeout(() => {}, 0)

无法获取到抽象节点,只能改写法,使用ref来实现,参考如下:

<abstracta:for='{{list}}'ref="refNavList"id='nav_list'a:key='{{categoryId}}'a:if='{{index===selected}}'item='{{item}}'ref-numbers='{{list}}'onOnClickCard='onClickCard'>
</abstract>
addMore(){
constlist=this.$navList
if(list){
list.addMore()
}
},
refNavList(ref){
//存储自定义组件实例,方便以后调用
this.$navList=ref;
},

子组件的点击

直接写<foo onTap="onTap">是无法触发的。需要在自定义组件外面套一层view再加点击事件,或者自定义组件做转发:

<view class="子组件最外层的view" onTap="onTap">...</view>
onTap (e) {
this.triggerEvent('tap', e);
},

注意:自定义组件的事件(如 onTap 等),并不是每个自定义组件默认支持的,需要自定义组件本身明确支持才能使用。

npm的使用

在微信中使用npm库,开发工具会将npm库的入口文件重新打包输出并放到转换目录对应文件夹的根路径下。

而在支付宝中,npm包在引入后不会出现转换目录,而是直接使用node_modules下的代码了。

因此如果代码中出现了对npm的引用,其引入路径全部都需要更改。

考虑到有些npm库的代码也是原生微信小程序的,同样需要转换代码,最终的处理方案是将所有npm包都手动拷贝到指定目录,一起参与antmove的转换,并手动修改所有涉及的引入路径。

Behavior

支付宝中不存在该对象,只能用Mixin对象和mixins属性平替。

复制到剪贴板api

不知道出于什么实际原因,文档里虽然还有,但该接口已废弃。小程序中如果有类似需求,只能舍弃。

目前my.setClipboard这个api支付宝开放平台文档已下架,已不支持使用

my.setClipboard 在预览和真机调试下无效

查找元素 createSelectorQuery

与微信不同,不支持查询子组件内部元素的位置信息,只能查原生组件的。

所以需要改变写法,先在子组件上实现一个createSelectorQuery相关逻辑,然后让父组件用selectComponent获取子组件,再执行其方法获取结果。

另外Antmove对createSelectorQuery做了兼容性处理,因为早期的支付宝原生方法不支持局部查询,所以使用this.createSelectorQuery时也会变成全局查询。现在的版本需要移除此适配。

可选操作符

比如a?.ba ?? b语法目前都不支持,据说2023年6月后会支持。

目前只能手动改成&&||

不能隐藏返回、首页按钮

不能完全自由地用脚本控制返回、首页按钮的显隐。因此,原本在微信上自定义过返回、首页按钮的自定义导航栏,只能改回系统按钮。

以下是官方回复:

Q:导航栏左上角的 “返回小程序首页” 按钮和 “返回上一页” 按钮何时会展示?

A:当页面为最底层页面(页面栈深度为 1 ),且页面为非首页、非 tabBar 页面时,标题栏左上角默认展示 “返回首页” 按钮;
当页面栈深度大于 1 时,默认展示 “返回上一页” 按钮
页面栈 是小程序框架管理界面的方式,可以使用 my.getCurrentPages().length 查看当前页面栈深度。

Q:如何隐藏标题栏上的返回按钮?

A:暂无 API 可以直接隐藏页面的返回上一页按钮;可以先通过 my.reLaunch 进行页面跳转,使用页面栈深度为 1,返回上一页按钮自然隐藏。如有必要,在目标页面里调用 my.hideBackHome,将返回小程序首页按钮也隐藏掉。

而用于获取左侧按钮和右侧菜单按钮的api写得像是一坨屎,有很多历史包袱,且没有官方示例。

以下是我的代码供参考:

export function getHeader () {
const {
titleBarHeight,
statusBarHeight,
} = wx.getSystemInfoSync()
let titleBarLeft = 30
if (wx.canIUse('getLeftButtonsBoundingClientRect')) {
const {
backButtonIcon,
backButtonInteractive,
homeButtonIcon,
} = wx.getLeftButtonsBoundingClientRect();
titleBarLeft = 0
if (homeButtonIcon) {
titleBarLeft += homeButtonIcon.right
} else if (backButtonInteractive) {
titleBarLeft += backButtonInteractive.right
}
}
return {
titleBarHeight,
statusBarHeight,
titleBarLeft,
}
}

不能自定义前景色

首先,在页面的json配置文件中只能修改背景色backgroundColor。微信上的前景色属性titleBarColor并不会生效。

而背景色只要不为白色#FFFFFF时,前景色就会被强制固定为白色。

我这里原本的UI配色是将背景色设置为较浅的灰色#F7F7F7,结果标题文字变成白色完全看不清。

解决方案是把导航栏的颜色配置挪到onLoad时用脚本修改:

wx.setNavigationBar({
backgroundColor:'#f7f7f7',
frontColor:'#333333',
})

然后又发现前景色frontColor实际上只接受黑白两种色值。
这个写法会提示不合法,只能把frontColor改为#000000

wx.setNavigationBar({
backgroundColor: '#f7f7f7',
frontColor: '#000000',
})

Antmove处理

mixins

支付宝现在已原生支持,但antmove做了适配,反而导致不兼容。

需要到__antmove/component/classSubdirectory/component.js找到以下代码,注释掉对options.mixins属性的删除

const behaviors = options.behaviors || []
const mixins = options.mixins || []
const _export = options.export || ''
delete options.behaviors
// delete options.mixins
const retMixins = {}

_opts.observerObj = {}
_opts.observersObj = {}
_opts.behaviorsArr = []

processBehavior(retMixins, behaviors, _opts.behaviorsArr)
processBehavior(retMixins, mixins, _opts.behaviorsArr)
mergeOptions(retMixins, options)
processBehaviorId(behaviors)
processBehaviorId(mixins)

createSelectorQuery

支付宝现在已原生支持,但antmove做了适配,反而导致不兼容。

需要到__antmove/component/classSubdirectory/component.js找到以下代码,注释掉对createSelectorQuery的包装。

fnApp.insert('onInit', function() {
this.__wxExparserNodeId__ = nextUid()
// processIntersectionObserver(this)
// this.createSelectorQuery = function() {
// if (config.env !== 'production') {
// console.warn(
// '支付宝createSelectorQuery不支持限定选择器的选择范围,如使用,请保证对应选择器使用的唯一性',
// )
// }
// return createSelectorQuery.fn()
// }
for (const method in this) {
if (typeof this[method] === 'function') {
this[method] = this[method].bind(this)
}
}

微信现在有好几种形式发起客服,比如企业微信,但支付宝下只有一种,就是放个按钮让用户点击。

需要覆写这个按钮的样式才能实现UI适配,否则很丑。

为了有一个清晰且低耦合的页面结构,更好的做法是自定义样式后,把一个透明的客服按钮盖在上面。

这样客服按钮可以有多种表现形式,而接入写法很简单,在响应范围最外层加上contact-button-wrapper样式,再在内部最末尾加上contact-button即可。

参考如下:

.contact-button-wrapper {
position: relative;
}

.contact-button-wrapper contact-button {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
opacity: 0;
z-index: 1;
}
<view class="contact-button-wrapper">
如遇到定位不准确等问题,请<text class='text-primary'>联系客服</text>
<contact-button
tnt-inst-id="你的客服id"
scene="你的客服scene"
/>
</view>

分享 showShareMenu

在微信中由于限制滥用,从某个时间点起这个按钮已经不具备弹出分享页面的功能了,只是控制右上角分享按钮是否展示。

用户只能通过open-type的按钮和右上角来手动操作打开分享页面。

但是文档始终没有修改,容易引起误会。

但支付宝中,这个api仍然可以唤起分享页面,并且没有操作来源的限制。

而且文档删除了showShareMenu,改名为showSharePanel,但前者仍然可用。

因此在微信中习惯性地在onShow回调里打开右上角分享按钮,在支付宝中会变成弹出分享页面。

需要删除该语句。

数据变化观测器 observer

支付宝已原生支持。

但某些场景的表现与微信有不同,需要仔细检查。比如:

页面属性a有一个数组子属性b,这个数组b被子组件监听。

当数组成员b[c]被修改时,observe不会触发。

数组被重新赋值b = [...b],也不会触发。

页面属性被旧对象组装后重新赋值a = {...a, b},也不会触发。

只有该页面属性被全新对象赋值时才会触发。(怀疑跟diff算法有关)

因此在所有值变化结束后,需要靠lodash.deepCopy复制对象,然后重新setData。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK