垂直导航
在mytrips.wxml
加组件
scroll-into-view
跳转到main-{{item.id}}
的view
1 2 3 4 5 6 7 8 9 10
| <scroll-view scroll-y scroll-with-animation enable-back-to-top style="height:{{tripsHeight}}px" scroll-into-view="{{scrollIntoView}}"> <view wx:for="{{trips}}" wx:key="id" class="trip" id="main-{{item.id}}"> <view class="action"> <text class="cuIcon-title text-green"></text> {{trip.id}} </view> </view> </scroll-view>
|
因为高度是变化的,使用下面函数来计算scroll-view的高度
1 2 3 4 5 6 7 8
| onReady(){ wx.createSelectorQuery().select("#heading") .boundingClientRect(rect =>{ this.setData({ tripsHeight: wx.getSystemInfoSync().windowHeight - rect.height }) }).exec() }
|
注意要加exec()
不然不会运行
生成假数据演示
定义数据类型
1 2 3 4 5 6 7 8
| interface Trip{ id: string start: string end: string duration: string fee: string distance: string }
|
在page data中添加trips
生成数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| populateTrips(){ const trips: Trip[] = [] for (let i = 0; i < 100 ; i++){ trips.push({ id: (10001+i).toString(), start:'东方明珠' end: '迪士尼' distance: '22.0公里' duration:'0时52分' fee: '120.00元' }) } this.setData({ trips, }) }
|
前端页面调试的小Tips
1 2 3
| flex-direction: column;//排列方向 align-items: center;// justify-content: space-between;
|
控制右侧内容的滚动
在左边使用swiper
控件
navCount表示展示的数目,不同机型的高度是不一样的,这个值需要计算
1 2 3 4 5 6 7 8 9 10 11
| <swiper duration="500" display-multiple-items="{{navCount}}" vertical class="bg-white nav" style="height:{{tripsHeight}}px" current-item-id="{{navScroll}}"> <swiper-item class="cu-item {{navSel===item.id?'text-green':''}}" wx:for="{{navItems}}" wx:key="id" id="{{item.id}}" item-id="{{item.id}}" data-main-id="{{item.mainId}}" bindtap="onNavItemTap"> <view >{{item.label}}</view> <view wx:if="{{navSel===item.id}}" class="cur"></view> </swiper-item> </swiper>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| .nav-container{ display: flex; } .nav-container swiper{ width: 152rpx; } .swiperItem{ display: flex; align-items: center; justify-content: center; } .cur{ height: 50%; width: 8rpx; border-radius: 10rpx 0 0 10rpx; position: absolute; background-color: currentColor; top: 0; right: 0rpx; bottom: 0; margin: auto; } .nav .cu-item{ text-align: center; margin: unset; padding: unset; }
|
数据结构如下:
1 2 3 4 5 6 7 8 9 10 11 12
| interface MainItem{ id: string navId: string data: Trip }
interface NavItem{ id: string mainId: string label: string }
|
在data中加入
1 2 3 4 5 6 7 8
| mainItems: [] as MainItem[],
navItems: [] as NavItem[],
navCount: 0,
navSel:'',
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| populateTrips(){ const mainItems: MainItem[] = [] const navItems: NavItem[] = [] let navSel= '' for (let i = 0; i < 100 ; i++){ mainItems.push({ id:'main-'+i, navId:'nav-'+i, data: { id: (10001+i).toString(), start:'东方明珠', end: '迪士尼', distance: '22.0公里', duration:'0时52分', fee: '120.00元', status: '已完成', }, }) navItems.push({ id: 'nav-'+i, mainId: 'main-'+i, label: (10001+i).toString(), }) if (i===0){ navSel = 'nav-'+i } } this.setData({ mainItems, navItems, navSel, }) },
|
开发中遇到一个小问题,bindtap的点击函数无法激活,原因:前端的标签没有指定高度和宽度。
控制左侧导航滚动
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface MainItem{ id: string navId: string navScrollId: string data: Trip } interface MainItemQueryResult{ id: string top: number dataset:{ navId: string navScrollId: string }
|
data中加入
1 2 3 4 5
| scrollStates: { mainItems: [] as MainItemQueryResult[], },
navScroll: '',
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| populateTrips(){ const mainItems: MainItem[] = [] const navItems: NavItem[] = [] let navSel= '' let prevNav = '' for (let i = 0; i < 100 ; i++){ if (!prevNav) { prevNav = 'nav-'+i } mainItems.push({ id:'main-'+i, navId:'nav-'+i, navScrollId: prevNav, data: { id: (10001+i).toString(), start:'东方明珠', end: '迪士尼', distance: '22.0公里', duration:'0时52分', fee: '120.00元', status: '已完成', }, }) navItems.push({ id: 'nav-'+i, mainId: 'main-'+i, label: (10001+i).toString(), }) if (i===0){ navSel = 'nav-'+i } prevNav = 'nav-'+i } this.setData({ mainItems, navItems, navSel, },() =>{ this.prepareScrollstatus() }) }, prepareScrollstatus(){ wx.createSelectorQuery().selectAll('.main_items').fields({ id: true, dataset:true, rect: true, }).exec(res =>{ console.log(res) this.scrollStates.mainItems = res[0] }) },
|
这里的data-nav-scroll-id
是第一nav的Id,审美上,当前的nav在第一个并不好看。这里选择的是第二个,所以滚动的实际位置是第一个,高亮的是下一个。data-nav-scroll-id
表示的就是高亮的上一个nav
1 2 3 4 5 6
| <scroll-view scroll-y scroll-with-animation enable-back-to-top style="height:{{tripsHeight}}px" scroll-into-view="{{mainScroll}}" bindscroll="onMainScroll"> <view wx:for="{{mainItems}}" wx:key="id" class="padding-bottom padding-lr main_items" id="{{item.id}}" data-nav-id="{{item.navId}}" data-nav-scroll-id="{{item.navScrollId}}">
|
滚动事件函数
思路:计算当前滚动的像素和本身的元素像素的大小比较。
scrollStates表示每个item的属性,包含了每个item的像素位置,通过prepareScrollstatus()
函数获取。
计算当前滚动到的像素值和scrollStates中每个item的像素位置比较,找到第一个scrollStates中的item的高度大于当前的像素高度,就表示当前item是第一个完全展现在屏幕中的item。
找到这个item之后,我们设置左边的滚动为上一个nav。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| onMainScroll(e: any){ console.log(e) const top: number = e.currentTarget?.offsetTop + e.detail?.scrollTop if (top === undefined){ return } const selItem = this.scrollStates.mainItems.find(v => v.top>=top) if (selItem === undefined){ return } this.setData({ navSel:selItem.dataset.navId, navScroll:selItem.dataset.navScrollId, }) },
|