我们先来看看京东的效果

分析

  1. 上端导航栏可以放置多个分类,可滑动
  2. 点击导航栏最右端按钮可以查看所有分类,同时背景模糊
  3. 内容部分右拉跳转到另外的分类
  4. 点击分类时导航栏的滑动部分自动滑动到合适的位置

我的实现

代码展示:

js

  1. /**
  2. * categoryView.js - 分类页面
  3. */
  4. var fakeData = require('../../common/fakeData.js')
  5. Page(
  6. {
  7. data: {
  8. categories: ['全部'],
  9. currentTab: 0,
  10. scrollLeftValue: 0,
  11. isPickerShow: false,
  12. isBgNeed: false,
  13. commodities: []
  14. },
  15. navbarTap: function (e) {
  16. //将顶部导航栏自动移动到合适的位置
  17. var idx = e.currentTarget.dataset.idx;
  18. this.autoScrollTopNav(idx);
  19. //自动收回
  20. if (this.data.isPickerShow) {
  21. this.navbarBtnClick();
  22. }
  23. this.setData({
  24. currentTab: idx
  25. })
  26. },
  27. /**
  28. * 导航栏右侧箭头按钮点击事件 - 切换模糊背景开闭状态以及展开栏开闭状态
  29. */
  30. navbarBtnClick: function(e) {
  31. this.data.isBgNeed = !this.data.isPickerShow
  32. this.setData({
  33. isBgNeed: this.data.isBgNeed
  34. })
  35. this.data.isPickerShow = !this.data.isPickerShow
  36. this.setData({
  37. isPickerShow: this.data.isPickerShow,
  38. })
  39. },
  40. /**
  41. * 页面左右滑动事件 - 构造滑动动画,若当前页面无数据,自动加载,需要完善加载函数
  42. */
  43. swiperChange: function (e) {
  44. var idx = e.detail.current;
  45. this.autoScrollTopNav(idx);
  46. this.setData({
  47. currentTab: e.detail.current,
  48. })
  49. //若无数据,自动加载
  50. if (this.data.commodities[idx].length == 0) {
  51. this.downloadMoreItem();
  52. }
  53. },
  54. /**
  55. * 上拉刷新
  56. */
  57. updateItem: function(e) {
  58. var idx = this.data.currentTab;
  59. this.data.commodities[idx] = [];
  60. this.downloadMoreItem();
  61. },
  62. /**
  63. * 下载更多数据 - 涉及后台拉取数据,需完善
  64. */
  65. downloadMoreItem: function(e) {
  66. var idx = this.data.currentTab;
  67. var commodities = this.data.commodities;
  68. //获取更多数据
  69. commodities[idx] = commodities[idx].concat(
  70. fakeData.requestForItemsOfType(commodities[idx].length, 10, this.data.categories[idx])
  71. );
  72. this.setData({
  73. commodities: this.data.commodities
  74. })
  75. console.log(this.data.commodities);
  76. },
  77. /**
  78. * 用于自动调整顶部类别滑动栏滑动距离,使滑动到用户可接受的合适位置,但自适应上还未考虑太周到
  79. * @param {number} idx - The index of currentTap.
  80. */
  81. autoScrollTopNav: function (idx) {
  82. if (idx <= 2) {
  83. this.data.scrollLeftValue = 0;
  84. } else {
  85. this.data.scrollLeftValue = (idx - 2) * 60;
  86. }
  87. this.setData({
  88. scrollLeftValue: this.data.scrollLeftValue
  89. })
  90. },
  91. /**
  92. * 模糊背景点击事件 - 点击模糊背景取消选择
  93. */
  94. bgTap: function(e) {
  95. if (this.data.isPickerShow) {
  96. this.navbarBtnClick();
  97. } else {
  98. return;
  99. }
  100. },
  101. /**
  102. * 商品点击事件 - 待完善
  103. */
  104. itemTap: function(e) {
  105. console.log("you selsct type " + this.data.currentTab + " item " + e.currentTarget.dataset.idx);
  106. },
  107. /**
  108. * 生命周期函数--监听页面加载,在加载的时候抓取数据
  109. */
  110. onLoad: function (options) {
  111. //首先获取类别项
  112. this.data.categories = fakeData.requestForCategories();
  113. this.setData({
  114. categories: this.data.categories
  115. })
  116. //然后默认请求 全部 分类
  117. for (var i in this.data.categories) {
  118. this.data.commodities.push([]);
  119. }
  120. this.data.commodities[0] = fakeData.requestForItemsOfType(0, 10);
  121. console.log(this.data.commodities);
  122. this.setData({
  123. commodities: this.data.commodities
  124. })
  125. }
  126. })

json

  1. {
  2. "navigationBarTitleText": "商城"
  3. }

wxml

  1. <!--categoryView.wxml-->
  2. <import src="../../common/wxmlTemplate.wxml" />
  3. <!--顶部分类导航条-->
  4. <view class="">
  5. <view class="navbar">
  6. <view class="nav-1">
  7. <scroll-view scroll-x="true" class="nav-1-left" scroll-left="{{scrollLeftValue}}" wx:if="{{!isPickerShow}}">
  8. <view wx:for="{{categories}}" data-idx="{{index}}" class="item {{currentTab==index ? 'active' : ''}}"
  9. wx:key="unique" bindtap="navbarTap">{{item}}</view>
  10. </scroll-view>
  11. <view class="nav-1-left" wx:if="{{isPickerShow}}">
  12. <view class="item left2Font">{{categories[currentTab]}}</view>
  13. </view>
  14. <!-- <view class="blankblock"></view> -->
  15. <button class="navbarBtn" bindtap="navbarBtnClick">
  16. <image src="../../resources/返回.png" class="navbarBtn icon {{isPickerShow ? 'active' : ''}}"></image>
  17. </button>
  18. </view>
  19. <view class="picker" wx:if="{{isPickerShow}}">
  20. <view class="spitLine"></view>
  21. <view class="picker-contain">
  22. <view wx:for="{{categories}}" data-idx="{{index}}" class="item {{currentTab==index ? 'active' : ''}}"
  23. wx:key="unique" bindtap="navbarTap">{{item}}</view>
  24. </view>
  25. </view>
  26. </view>
  27. <swiper class="itemContainer" bindchange="swiperChange" current="{{currentTab}}">
  28. <block wx:for="{{categories}}" wx:for-item="cItem" wx:key="unique">
  29. <swiper-item>
  30. <scroll-view scroll-y="true" bindscrolltolower="downloadMoreItem" bindscrolltoupper="updateItem">
  31. <view class="child" bindtap="itemTap" wx:for="{{commodities[currentTab]}}"
  32. data-idx="{{index}}" wx:key="unique" wx:if="{{item.category == cItem || cItem == '全部'}}">
  33. <template is="itemInfoTemplate" data="{{item}}"/>
  34. </view>
  35. </scroll-view>
  36. </swiper-item>
  37. </block>
  38. </swiper>
  39. <!-- 透明遮盖层 -->
  40. <view class="picker-contain-bg {{isPickerShow? 'show' : ''}}" wx:if="{{isBgNeed}}" bindtap="bgTap"></view>
  41. </view>

wxss

  1. @import "../../common/flexGridStyle.wxss";
  2. @import "../../common/itemShowStyle.wxss";
  3. page {
  4. display: flex;
  5. flex-direction: column;
  6. height: 100%;
  7. }
  8. .navbar {
  9. position: fixed;
  10. z-index: 2;
  11. background-color: RGB(247, 247, 247);
  12. width: 100%
  13. }
  14. .nav-1{
  15. flex: none;
  16. display: flex;
  17. background: #fff;
  18. background-color: RGB(247, 247, 247);
  19. height: 80rpx;
  20. }
  21. .nav-1 .wrapBar {
  22. display: flex;
  23. }
  24. .nav-1 .item{
  25. position: relative;
  26. text-align: center;
  27. font-size: 30rpx;
  28. line-height: 80rpx;
  29. color: gray;
  30. display: inline-block;
  31. padding-left: 20rpx;
  32. padding-right: 20rpx;
  33. }
  34. .nav-1 .item.active{
  35. color: black;
  36. }
  37. .nav-1 .item.active:after{
  38. content: "";
  39. display: block;
  40. position: absolute;
  41. bottom: 0;
  42. left: 0;
  43. right: 0;
  44. height: 4rpx;
  45. background: black;
  46. }
  47. button {
  48. background: transparent;
  49. }
  50. button::after {
  51. border: 0;
  52. }
  53. .navbarBtn {
  54. flex: 0 0 15%;
  55. }
  56. .navbarBtn.icon {
  57. transform: rotate(90deg);
  58. width: 20rpx;
  59. height: 40rpx;
  60. }
  61. .navbarBtn.icon.active{
  62. transform: rotate(-90deg);
  63. }
  64. .blankblock {
  65. flex: 0 0 10%;
  66. }
  67. .nav-1-left {
  68. white-space: nowrap;
  69. overflow: hidden;
  70. flex: 0 0 85%;
  71. }
  72. .picker {
  73. }
  74. .item.left2Font {
  75. color: black;
  76. }
  77. .spitLine {
  78. margin: 0;
  79. height: 2rpx;
  80. background-color: gray;
  81. }
  82. .picker-contain {
  83. display: flex;
  84. flex-wrap: wrap;
  85. justify-content: center;
  86. }
  87. .picker-contain-bg {
  88. position: fixed;
  89. background-color: black;
  90. transition: all 1s;
  91. width: 100%;
  92. height: 100%;
  93. z-index: 1;
  94. top: 0;
  95. opacity: 0
  96. }
  97. .picker-contain-bg.show {
  98. opacity: 0.5;
  99. }
  100. .picker-contain .item {
  101. background-color: RGB(215, 215, 215);
  102. border-radius:20px;
  103. margin: 20rpx;
  104. padding: 50rpx;
  105. padding-top: 10rpx;
  106. padding-bottom: 10rpx;
  107. font-size: 30rpx;
  108. color: RGB(161, 161, 161);
  109. }
  110. .picker-contain .item.active{
  111. color: black;
  112. background-color: RGB(153, 153, 153);
  113. }
  114. swiper-item scroll-view {
  115. display: inline;
  116. }
  117. swiper.itemContainer{
  118. margin-top: 80rpx;
  119. height: 1136rpx;
  120. }

本文转载:CSDN博客