这个tab pro,是高级一点的小程序tab选项卡
发布于 5 年前 作者 lixiulan 4397 次浏览 来自 分享

选项卡页面

类似于腾讯新闻的标签选项卡

  • 点击菜单栏的选项开,切换内容页
  • 滑动内容页,切换菜单栏的分类项
  • 保持被激活的分类选项卡始终在页面显示区内

思路

  • 需要一个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)
    })
  }
})
回到顶部