我们在做的这个产品目前的结构是这样的,使用nvue编写的uni-app项目作为app端,使用vue编写的vue项目作为H5端。在app端一共有三个页面,分别为loading页面、setting页面、index页面。 一些基本的交互逻辑如下:
一、app打开时,默认加载loading页面,此时判断是否存在服务端缓存地址和H5缓存地址(如果存在缓存就直接跳转页面)
1、如果服务端缓存地址为空,直接跳转到setting页面。(因为没有地址就无法建立连接,无法监测设备状态)
2、如果存在H5缓存地址,并且校验地址可以访问,就加载H5缓存地址,当页面加载完成后,APP收到来自H5的消息,就跳转到index页面,这个页面主要用来展示数据,其中嵌套webview,地址是H5缓存地址。(H5地址能够访问,就直接展示,避免服务停掉时直接跳转设置页面不友好)
2.1、自动连接服务端,如果连不上就一直重连 (开启重连机制,当服务端启动时,能够及时恢复连接)
3、如果H5缓存地址,不可访问,就跳转到setting页面,并且清空缓存。(地址不可访问,说明地址可能错误,需要跳转到设置页面重新设置)
4、如果H5缓存地址为空,则直接请求服务端,等待服务端返回H5端地址
4.1、如果服务端连接失败,则会跳转到setting页面,并且清空缓存(地址不可访问,说明地址可能错误,需要跳转到设置页面重新设置)
4.2、如果服务端连接成功,则会返回H5地址,并且将其加入缓存中
4.2.1、校验地址可以访问,加载H5地址,当页面加载完成后,APP收到来自H5的消息,就跳转到Index页面。
4.2.2、校验地址不可访问,则跳转到setting页面,并且清空缓存(地址不可访问,说明地址可能错误,需要跳转到设置页面重新设置)
二、当前在setting页面时,可以输入服务端地址(IP+Port),点击按钮时,会向服务端发起请求,由服务端返回一个H5端的地址(通过服务端返回H5端地址,再进行跳转页面)
1、点击按钮时,就会缓存当前的服务端地址
2、如果服务端连接失败,则会直接提示服务加载失败。
3、如果服务端请求成功,会返回H5地址,并且将其加入缓存中
3.1、校验地址可以访问,加载H5地址,当页面加载完成后,APP收到来自H5的消息,就跳转到Index页面。
3.2、校验地址不可访问,则直接提示页面加载失败,并且清空缓存。
三、当前在index页面时,可用点击设置按钮,会跳转到setting页面(可重新配置地址)
1、点击设置,H5会向APP发送一条消息
2、APP收到消息,判断消息类型,为APP页面跳转消息,则会执行页面跳转操作。
loading页面
setting页面
index页面
那么接下来,就开始踩坑了。而在同一坑里掉下来去两次,当然是两种不同的现象,只是原理是相同的。先来讲一下现象:
现象一:
在起初的模式中,只做了setting页面和index页面,setting页面默认给了一个加载图片。在setting页面的onLoad中,预载了index页面,而在index的onLoad方法中,预加载webview。再根据是缓存中的h5url判断是否将创建的webview添加到当前窗口。另外再根据一些逻辑进行反复横跳。目的是默认进入setting页面,如果缓存均有值,当页面加载完成后,在跳转到index页面,载图片起到一个过渡的作用。而如果加载失败,只是将加载图隐藏,显示具体的设置页面。而跳转的方式采用了uni.navigateTo方法。这种模式下,缓存值都存在时访问直接跳转是正常的,当没有缓存时,跳转到setting页面,再通过点击按钮跳转index页面,就会出现页面无限跳转,不停的在跳index页面。
初步分析:怀疑过绑定了多个事件,导致事件重复触发,进行跳转;怀疑是预加载导致;等... 结果没有一项是正确的。
现象二:
在现在的模式中,分为了三个页面,loading页面、setting页面、index页面,在loading页面中预加载setting页面和index页面。在loading页面做缓存的判断以及loading效果的展示,在setting页面做ip和端口的设置,跳转index页面。在index页面做webview的加载以及app与h5之间的相互通讯。这样设计之后就不存在反复横跳了,从loading要么进入到setting页面,要么进入到index页面。所以当时,同事改造完之后,这个问题解决了,我以为万事大吉了。直到后来做到点击设置跳回setting页面时,这第一步操作是成功了,正常返回了setting页面,但是再次点击注册设备时,页面一片空白。这里的所有跳转方式,均采用了uni.naviagteTo方法。
初步分析:通过plus.webview.all()打印全部窗体,在不同时机打印,在前面所有步骤中均显示正常,而在跳转到setting页面后,再次点击设置时,窗体发生了变化,新增了一个窗口。并且窗体中的方法都没有了。所以问题出在跳转后。
全局分析:
看到这里,细心的同学应该已经发现了端倪。在我前面所有的表述中,认为navigateTo方法为跳转页面。我们先来看看官网上是怎么讲的。保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack方法可以返回到原页面。我是这样理解的,我以为保留当前页面的意思就是,当前页面不会销毁,然后跳转到应用内的一个页面。对比uni.redirectTo和uni.reLaunch方法,redirectTo是关闭当前页面,然后跳转。reLaunch方法是关闭全部页面,然后跳转,但是调用过preLoadPage方法的仅仅触发onHide生命周期。所以,我认为这里的跳转就是,这个应用内有很多个页面,在这些页面之间跳来跳去,仅仅只是是否关闭页面的区别,也就是说,我认为这个跳转就是平级页面之间的跳转,并且每个页面只会存在一个,但是实际上并不是这样的。
仔细看navigateTo的描述,保留当前页面,跳转到应用内的某个页面。保留当前页面,就是当前页面不关闭,跳转到某个页面,就是以那个页面为模板创建一个新的页面。所以,这是一个叠加的关系,打开一个页面,放在前一个页面上面,展示的就是最上面的页面。根据描述,可以使用navigateBack返回到原页面,应该就是关掉最上面的页面,重新回到之前的页面。
可以设想一下,如果一个页面中有两个按钮,一个触发navigateTo方法,设置跳转到与当前相同地址的页面,一个触发naviagateBack方法。点击五次navigateTo方法的按钮,你猜会发生什么呢?肯定是闪了五下,那如果再点击五次navigateBack方法的按钮又会怎么样呢?如果猜想的没错的话,应该是以当前页面为模板,重新创建了五个页面,每次创建都保留了之前的页面。再点击五次又会返回到第一个页面。
所以,现象一,可以解释为,因为多次调用了navigateTo方法,创建了多个页面,每个页面都未被关闭,所以相同的方法就触发了多次,导致了一直刷新。现象二,可以解释为,收到APP收到消息后,新建了一个setting页面。不过这个setting页面,最开始的时候,在loading页面中进行了preLoadPage,根据以下图中说明,由于已经预加载过这个setting页面,且参数和url都相同,所以新的页面仅触发生命周期onShow,导致窗体的方法都不存在。
解决方案:
这里采用了一个取巧的办法,我们需要的不是创建一个新的页面,而是跳转回去之前创建好的页面,那什么方法能够做到呢?uni.switchTab方法的描述是,跳转到tabBar页面,并关闭其他所有非tabBar页面。另外需要注意的是,如果调用了preloadPage不会关闭,仅触发生命周期onHide。那我们只要这个三个页面都属于tabBar页面,然后采用uni.switchTab方法进行跳转。这样,由于setting页面和index页面调用过preLoadPage方法,仅会触发生命周期onHide,tabBar页面本身也不会关闭,那么就可以随意的反复横跳了。最后只需要将tabBar给隐藏掉,就可以完美解决问题了。将高度设置为了0.01px,直接设置为0px不生效。
发表评论