这个tab pro,是高级一点的小程序tab选项卡
选项卡页面
类似于腾讯新闻的标签选项卡
- 点击菜单栏的选项开,切换内容页
- 滑动内容页,切换菜单栏的分类项
- 保持被激活的分类选项卡始终在页面显示区内
思路
- 需要一个scroll-view容器作为菜单容器,并支持横向滚动
- 需要一个swiper-view容器作为内容存放页
- swiper-view切换时,切换菜单分类,可以使用scroll-view的
scroll-into-view
属性 - 点击菜单分类时,切换swiper-view显示对应内容,使用swiper-view的
current
属性
实现效果
完整源码
github搜索 aotoo-xquery -> pages -> tabpro
微信搜索小程序: xquery
小程序代码片段
wxml
<view class="container">
<ui-list list="{{tabConfig}}" class="tab-boxer" />
</view>
使用xquery内置的list组件可以生成菜单结构
构建菜单选项卡
listConfig = {
$$id: id,
listClass: 'tab-header',
itemClass: 'tab-item',
type: {
"is": 'scroll',
"scroll-x": true,
},
data: [
{title: '选项-1', id: 'sc-1', tap: 'onTap?id=1'},
{title: '选项-2', id: 'sc-2', tap: 'onTap?id=2'},
{title: '选项-3', id: 'sc-3', tap: 'onTap?id=3'},
{title: '选项-4', id: 'sc-4', tap: 'onTap?id=4'},
{title: '选项-5', id: 'sc-5', tap: 'onTap?id=5'},
...
]
}
$$id
list组件的实例id,通过此id可以调用list组件的实例及使用定义的方法
type
指定list以什么模式展现列表
type: {is: 'scroll'}
表示整个列表以scroll-view的模式展现列表type: {is: 'swiper'}
以swiper-view的方式展示列表- 不设置type,以普通列表展示
data
菜单项集合
- tap 会自动生成view的
bind:tap
事件,xquery的封装支持query参数 - id 作为菜单页唯一标识,
scroll-into-view
需要此标识
swiper容器
list有一个footer底部容器,有数据时由item组件生成,基于组件嵌套的原则,在该容器中嵌入使用swiper组件
listConfig.footer = {
"@list": {
type: {
is: 'swiper',
bindchange: 'onSwiperChange',
},
data: [
{title: '内容-1', id: 'sw-1'},
{title: '内容-2', id: 'sw-2'},
{title: '内容-3', id: 'sw-3'},
{title: '内容-4', id: 'sw-4'},
...
]
}
}
}
type
指定list以什么模式展现列表
type: {is: 'swiper'}
以swiper-view的方式展示列表
data
菜单项集合
- id 作为内容页唯一标识,该id与scroll-view的id需要要映射关系
到此我们的容器部分准备好了,接下来要完成对应的事件方法
组件内方法
listConfig.methods = methods: {
__ready(){
// 初始化,组件挂载后自动执行
this.swiperInst = this.find('.swiper-content').data[0] //swiper实例
this.scrollInst = this // 菜单实例
// 设置默认值
this.scrollInst.find({id: 'sc-1'}).addClass('active')
this.activePage.hooks.emit('set-content', {id: 'sw-1'}, this.swiperInst.find({id: 'sw-1'}))
this.hasChangeContent = {'sw-1': true}
},
// 菜单响应方法
onTap(e, param, inst) {
let that = this
let id = param.id
inst.siblings().removeClass('active')
inst.addClass('active')
this.swiperInst.update({"type.current": id-1}, function(){
let hc = that.hasChangeContent
let swId = 'sw-'+id
if (!hc[swId]) {
// 执行外部的钩子
that.hooks.emit('tap-to', {id: swId}, that.swiperInst)
that.hasChangeContent[swId] = true
}
})
},
// swiper切换响应方法
onSwiperChange(e){
let that = this
this.scrollInst.forEach(item => item.removeClass('active'))
let id = e.detail.currentItemId.replace('sw-', '')
id = parseInt(id)
let scrollId = 'sc-'+id
let activeIt = this.scrollInst.find({id: scrollId})
activeIt.addClass('active')
let intoId = id === 1 ? id : id-3
this.update({ "type.scroll-into-view": 'sc-'+intoId }, function() {
let hc = that.hasChangeContent
let swId = 'sw-' + id
if (!hc[swId]) {
// 执行外部挂载的钩子方法
that.hooks.emit('switch-to', {id: swId}, that.swiperInst)
}
})
}
__ready
list组件挂载到页面后自动执行该方法,设置默认值
onTap
响应菜单项的点击事件
onSwiperChange
swiper-view切换时响应方法
this.update({ "type.scroll-into-view": 'sc-'+intoId }
菜单项滚动到指定项
页面响应方法
组件与业务是隔离的,业务中需要调用钩子去修改相关内容
Pager({
onLoad(){
// 在外部中挂载修改内容的方法
this.hooks.once('set-content', function(param){
if (param.id === 'sw-1') {
this.update({
title: '我是选项一',
img: {src: '/images/mk1.jpeg', mode: 'aspectFit'}
})
}
...
})
},
onReady(){
let that = this
let $tab = this.getElementsById('tabselect')
// 组件外挂载钩子方法,对应修改swiper-item中的内容
// 菜单点击响应
$tab.hooks.on('tap-to', function(param) {
let target = this.find({id: param.id})
that.hooks.emit('set-content', param, target)
})
// swiper-view切换响应方法
$tab.hooks.on('switch-to', function (param) {
let target = this.find({id: param.id})
that.hooks.emit('set-content', param, target)
})
}
})