第一部分:swiper + 顶部/底部导航栏实现
这里的思想与安卓的fragment+viewpager是很类似的,用swiper作为左右滚动区间,联动tab导航栏,中间展示内容组件化
导航栏部分大家可以自定义,我整个界面采用的是底部导航栏用position:fixed浮动,swiper部分的current注意是与tab的下标一致,并且注意swiper的高度一定要动态自适应,这个等下滑动冲突会讲到。swiper-item内部内容是抽成组件化了,这样代码看着更整洁规范,注意内部class一定要写。
一个简单的swiper联动导航栏例子就好了,当然只是简单的,因为实际上还有不少问题。
第二部分:滑动冲突处理
如果你按照上面自己敲出来一个demo 你就会发现,如果你的页面内容过长涉及滚动,你的组件内就根本就不能滚动,原理是这些组件的父组件是swiper这货,而swiper样式中本身是不支持上下滑动滴,当然这个也好处理,我们在样式中加入:
/deep/ uni-swiper .uni-swiper-wrapper {
overflow-y: auto !important;
}
/deep/ uni-swiper-item {
overflow-y: auto !important;
}
加完了滚动以后你就会惊喜的发现页面滚动上去以后再也下不来了!因为下拉事件被原生的下拉刷新占用咯~ 你想着这还不简单,我加个scrollview还不行么,那你试试吧真不行嘿嘿!
首先让我告诉你原理:我们的swiper这货是必须有高度的, 而由于swiper高度是固定的,导致就算组件内部内容已经过长了,但下拉的时候body其实并没有过长,因此,无论你是什么scrollview或者overflow:auto,都会优先触发body滚动,也就是下拉刷新,这就是造成冲突的主要原因,我可以用一张图更清晰的解释:
针对这点,网上一种解决办法@touch.stop和@touchmove.stop你们可以试一下,反正H5可以,真机上不行,就算真机上可以,但这种方法只会在swiper区域拦截,造成下拉刷新区域很小,用户体验也是很差的。所以被我淘汰了。
根据上面的原理图,我们可以想到,既然swiper内部不能滚动,那就让swiper自身高度自适应撑起来,这样就会完美解决问题
所以首先我们需要解决swiper高度自适应问题
这里给了高度,的确已经解决了初步的问题,但是实际运用中,不可能所有的内容都是一上来就确定的,肯定要有网络请求在随时更新内容和高度的,比如有一个列表,那么上面的代码就失效了,因为高度在onReady周期已经定死了。
所以 我们的最后一步 需要随时更新高度,那么想到的思路就是子组件中emit通知父组件的swiper更新高度咯,尝试一下:(我这里用了个测试box来实验)
<view style="height: 100px;background-color: #007AFF;" v-show="testShow"></view>
uni.$on('updateSwiperHeight', () => {
console.log('收到通知');
this.getCurrentSwiperHeight('.fragment');
}); //父组件中注册监听
父组件在收到通知后会重新获取子组件高度并更新界面,这是美好的逻辑设想,但实际上获取dom高度的方法中,此时高度还没有及时更新,所以我们首先会想到将getCurrentSwiperHeight方法放在this.$nextTick方法中,但是在我的尝试下 就算包裹在nexttick中,高度也是没有及时更新,所以我只能使用了最终解决办法:
使用setTimeout,延迟一段时间再获取高度,事实证明暂时只有这种方法能获取到高度。如果大家有什么更好的办法,可以留言告诉我谢谢!