小程序菜单-锚点 左右滑动定位

HTML:

<!-- menu.wxml -->
<view>

  <!-- mainBox -->
  <view class="mainBox">

    <!-- menuMain -->
    <view class="menuMain">

      <!-- left -->

      <scroll-view style="height:{{height}}px" class="menuTabs" scroll-with-animation="true" scroll-y="true">
        <view>
          <view class="menu-item" wx:for="{{menuTabs}}" wx:key="index" data-id="tab{{index}}" bindtap="clickMenu" class="menu-item {{currentLeftSelect == 'tab'+index ? 'active': ''}}"   >
            <text>{{item.title}}</text>
            <view class="rmdBtn" wx:if="{{item.rmdFlag==1}}">推荐</view>
          </view>
        </view>
      </scroll-view>
      <!-- left end -->

      <!-- right -->
      <scroll-view class="menuScroll" style="height:{{height}}px" scroll-y="true" bindscroll="handleScroll" scroll-into-view="{{toView}}" scroll-with-animation="true">
        <!-- <view wx:for="{{menuList}}" wx:key="index" id="tab{{index}}" class="menuItem {{top>130 ? 'topnav' : ''}}"> -->
        <view class="menu-list" wx:for="{{menuList}}" wx:for-item="list" wx:key="index" id="tab{{index}}" style="{{index == (menuList.length - 1) ? 'margin-bottom: 1000rpx':'' }}">
          <view>
            <!-- menuTitle -->
            <view class="menuTitle">
								<text>{{list.productType}}</text>
								<view class="line"></view>
							</view>
            <!-- menuTitle end -->
          </view>

          <!-- menuList -->
            <view class="list-item" wx:for="{{list.products}}" wx:key="key" data-titel="{{list.productType}}" data-item="{{item}}" bindtap="getMenuDetail">
              <view class="caffeeInfo">
                <!-- 售罄遮罩 -->
                <image class="outOfStock" wx:if="{{item.soldOutFlag=='1'}}" src="https://cofeplus.oss-cn-beijing.aliyuncs.com/applets/images/menu_outOfStock.png"></image>
                <!-- 售罄遮罩 end -->
                <image class="caffeeImg" src="{{item.littleImg}}"></image>
                <view class="infoDetail">
                  <view class="nameBox">
                    <text class="caffeeName">{{item.productName}}</text>
                    <text class="discount" wx:if="{{item.hotFlag==1}}">热销</text>
                  </view>
                  <text class="englishName">{{item.englishName}}</text>
                  <view class="origin specs">规格:<rich-text nodes="{{item.composition}}"></rich-text></view>
                  <!-- <text class="origin">规格:{{item.composition}}</text> -->
                  <view class="priceBox">
                    <text class="price"><text style="{{item.isProduct == 1?'color: #727171':''}}">{{item.sellingPrice}}</text></text>
                    <text class="originPrice" wx:if="{{item.sellingPrice!=item.originalPrice}}">¥{{item.originalPrice}}</text>
                  </view>
                </view>
              </view>

              <!-- 未售罄加号 -->
              <view class="addBtn" wx:if="{{item.soldOutFlag=='0' && item.isProduct == 0}}">
                <image class="addImg" src="https://cofeplus.oss-cn-beijing.aliyuncs.com/applets/images/menu_add2.png"></image>
              </view>
              <!-- 未售罄加号 end -->
              <!-- 已售罄加号 - 非商品 -->
              <view class="addBtn" wx:if="{{item.soldOutFlag=='1' || item.isProduct == 1}}">
                <image class="addImg" src="https://cofeplus.oss-cn-beijing.aliyuncs.com/applets/images/menu_noAdd.png"></image>
              </view>
              <!-- 已售罄加号 - 非商品 end -->

            </view>
            <!-- menuList end -->
        </view>
      </scroll-view>
      <!-- right end -->

    </view>
    <!-- menuMain end -->

  </view>
  <!-- mainBox end -->


</view>

css:

/* pages/menu/menu.wxss */

/*
  mainbox
*/

.mainBox {
  width: 100%;
}

/*
  swiper
*/

swiper {
  width: 100%;
  display: flex;
  height: 138rpx;
}

.slide-image {
  width: 100%;
  height: 100%;
}

/*
  menuMain
*/

.menuMain {
  width: 100%;
  height: 100%;
  display: flex;
  flex-flow: row;
  position: absolute;
  background-color: #fff;
}

.menuTabs {
  width: 25%;
  height: 100%;
  background: #f5f5f5;
  overflow: hidden;
}

.menu-item {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  background: #f5f5f5;
  height: 30rpx;
  font-size: 28rpx;
  color: #666;
  padding: 30rpx 0;
  position: relative;
}

.menu-item text{
  text-align: center;
}

.active {
  background: #fff;
  /* font-weight: bold; */
  color: #00c8c8;
  /* border-left: 2px solid #27b8b8; */
  /* border-bottom-right-radius: 30rpx; */
}
.active+.menu-item{
  border-top-right-radius: 24rpx;
}

.menuList {
  width: 75%;
  background: #fff;
  padding: 20rpx 0;
}

.menuList:last-child {
  margin-bottom: 380rpx;
}

.menuScroll {
  width: 100%;
  height: 100%;
  padding: 10rpx 0 0;
}

.menuItem:last-child{
  margin-bottom: 40rpx;
}

.menuTitle {
  width: 100%;
  font-size: 22rpx;
  color: #666;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-left: 20rpx;
  margin-bottom: 40rpx;
  /* margin-top: 20rpx; */
}

.line {
  width: 82%;
  height: 1rpx;
  border-bottom: 1rpx solid #eee;
}

.list-item {
  margin-left: 20rpx;
  margin-top: 20rpx;
  margin-right: 20rpx;
  display: flex;
  justify-content: space-between;
  border-bottom: 1rpx solid #b9f0f0;
  padding-bottom: 20rpx;
}
.menu-list .list-item:last-child{
  border-bottom: 0;
}
/* .list-item:last-child {
  border: none;
} */

.caffeeImg {
  width: 140rpx;
  height: 140rpx;
}

.addBtn {
  position: relative;
  min-width: 60rpx;
}

.addImg {
  width: 45rpx;
  height: 45rpx;
  position: absolute;
  bottom: 0;
  right: 10rpx;
}

.caffeeName {
  /* font-size: 26rpx; */
  color: #00c8c8;
  /* font-weight: bold; */
  vertical-align: middle;
}

.englishName, .origin {
  font-size: 24rpx;
  color: #898989;
}
.origin{
  margin: 4rpx 0 25rpx;
}

.price {
  /* font-size: 28rpx; */
  color: #727171;
  /* font-weight: bold; */
}
.price text{
  font-size: 40rpx;
  color: #00c8c8;
}

.discount {
  font-size: 16rpx;
  color: #fff;
  background: #f5a622;
  border-radius: 6rpx;
  padding: 6rpx;
  margin-left: 10rpx;
  vertical-align: middle;
}

.nameBox {
  line-height: 30rpx;
  margin-bottom: 12rpx;
}

.caffeeInfo {
  display: flex;
  flex-flow: row;
}

.infoDetail {
  display: flex;
  flex:1;
  flex-flow: column;
  margin-left: 16rpx;
  justify-content: center;
}

.infoDetail text:first-child {
  margin-bottom: 6rpx;
}

.infoDetail text:last-child {
  margin-top: 12rpx;
}

.outOfStock {
  position: absolute;
  width: 140rpx;
  height: 140rpx;
}

.originPrice{
  color: #999;
  font-size: 24rpx;
  text-decoration: line-through;
  margin-left: 8rpx;
}

.rmdBtn{
  position: absolute;
  top:0;
  right:0;
  background: #f5a622;
  color: #fff;
  font-size: 18rpx;
  padding:0 10rpx;
}

.specs{
  display: flex;
  /* align-items: center; */
  flex-wrap: wrap;
}
.specs rich-text{
  display: inline-block;
  flex: 1;
  padding: 0;
}```

js:
// pages/menu/menu.js
const lang = require("../../utils/language.js");
const app = getApp();
const c_url = getApp().globalData.c_apiRoot;

// 右侧每一类的 bar 的高度(固定)
const RIGHT_BAR_HEIGHT = 23;

// 右侧每个子类的高度(固定)
const RIGHT_ITEM_HEIGHT = 70;

// 左侧每个类的高度(固定)
const LEFT_ITEM_HEIGHT = 45

Page({

  /**
   * 页面的初始数据
   */
  data: {

    // menuTabs
    current: "tab1",
    menuTabs: [],

    // menuList
    menuList: [
    	{
	    	productType: "经典咖啡",
	    	products:[
	    		{
	    			composition: "浓缩咖啡,水",
					epId: 163,
					hotFlag: 1,
					isProduct: 0,
					littleImg: "https://cofeplus.oss-cn-beijing.aliyuncs.com/product/meishikafei.jpg",
					originalPrice: 10.9,
					productCode: "test0116100003",
					productName: "美式咖啡",
					sellingPrice: 10.9,
					soldOutFlag: 0,
	    		},
	    			{
	    			composition: "浓缩咖啡,牛奶",
					epId: 168,
					hotFlag: 0,
					isProduct: 0,
					littleImg: "https://cofeplus.oss-cn-beijing.aliyuncs.com/product/natiekafei.jpg",
					originalPrice: 14.9,
					productCode: "test0116100001",
					productName: "美式拿铁",
					sellingPrice: 14.9,
					soldOutFlag: 0,
	    		},
	    	],
	    	rmdFlag: 0
    	},
    	{
	    	productType: "各国特色",
	    	products:[
	    		{
	    			composition: "浓缩咖啡,水",
					epId: 163,
					hotFlag: 1,
					isProduct: 0,
					littleImg: "https://cofeplus.oss-cn-beijing.aliyuncs.com/product/meishikafei.jpg",
					originalPrice: 10.9,
					productCode: "test0116100003",
					productName: "美式咖啡",
					sellingPrice: 10.9,
					soldOutFlag: 0,
	    		},
	    			{
	    			composition: "浓缩咖啡,牛奶",
					epId: 168,
					hotFlag: 0,
					isProduct: 0,
					littleImg: "https://cofeplus.oss-cn-beijing.aliyuncs.com/product/natiekafei.jpg",
					originalPrice: 14.9,
					productCode: "test0116100001",
					productName: "美式拿铁",
					sellingPrice: 14.9,
					soldOutFlag: 0,
	    		},
	    	],
	    	rmdFlag: 0
    	}
	],
    currentLeftSelect:'tab0',
    // 锚点
    toView: 'tab0',
    curId: 'tab0',
    //记录scroll-view滚动过程中距离顶部的高度
    distance: 0,
    currentLeft: 0, //左侧选中的下标

    // 屏幕高度
    height: "",

    // 当前页
    curPage: 1,

    heightArr:[],
    lastActive:'',
    eachRightItemToTop: [],
  },

  onLoad: function () {
    var that = this;
    wx.getSystemInfo({
      success: function (res) {
        that.setData({
          height: res.windowHeight-69
        })
      },
    })

    
  },

  onShow: function () {
    this.getMenus();
  },

  /**
   * 获取每个右侧的 bar 到顶部的距离,
   * 用来做后面的计算。
  */
  getEachRightItemToTop: function (data) {
    var obj = {};
    var totop = 0;
    // 循环来计算每个子类到顶部的高度
    obj['tab0'] = totop
    for (let i = 1; i < data.length+1; i++) {
      var elemId = 'tab' + i
      // obj[elemId] = totop
      if (i != 0) {
        totop += (RIGHT_BAR_HEIGHT + data[i - 1].products.length * RIGHT_ITEM_HEIGHT)
      }
      // 这个的目的是 例如有两类,最后需要 0-1 1-2 2-3 的数据,所以需要一个不存在的 'last' 项,此项即为第一类加上第二类的高度。
      var lastIndex = data.length;
      console.log(lastIndex, totop)
      obj[lastIndex == i ? 'last' : elemId] = totop
    }
    console.log(obj)
    return obj
  },

  // 锚点
  clickMenu: function (e) {
    this.setData({
      toView: e.currentTarget.dataset.id,
      currentLeftSelect: e.currentTarget.dataset.id
    })
  },

  // scroll
  handleScroll: function (e) {
    // console.log(this.data.eachRightItemToTop)
    for (let i = 0; i < this.data.menuList.length; i++) {
      var elemId = 'tab' + i
      let left = this.data.eachRightItemToTop[elemId]
      // console.log(left)
      let right = this.data.eachRightItemToTop[this.data.menuList[i + 1] ? ('tab' + (i+1)) : 'last']
      if (e.detail.scrollTop < right && e.detail.scrollTop >= left) {
        this.setData({
          currentLeftSelect: elemId,
          leftToTop: LEFT_ITEM_HEIGHT * i
        })
      }
    }
    // console.log(this.data.constants)
    // console.log(this.data.eachRightItemToTop)
  },

  // 菜单详情
  getMenuDetail: function (e) {
    console.log(e)
  },

  // 获取商品列表
  getMenus: function () {
    var that = this;
    var data = {
      eqNumber: wx.getStorageSync('eqNumber'),
      language: wx.getStorageSync('lan'),
      pageNum: this.data.curPage,
      pageSize: 500
    };
    app.httpPost(c_url + 'v1/get_products', data, (res) => {
      var tempTabs = [];
      res.data.forEach(function (item, index) {
        tempTabs.push({
          'title': item.productType,
          'rmdFlag': item.rmdFlag
        });
      });
      that.setData({
        menuList: res.data,
        menuTabs: tempTabs,
        eachRightItemToTop: that.getEachRightItemToTop(res.data)
      });
      // this.getHeight()
    }, (errRes) => {
      app.errorMsg(errRes.data.msg);
    });
    
  },


})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值