小程序锚点跳转(例如楼层快捷导航,点击字母滚动到相关城市)

使用场景:楼层之间的快速切换,锚点的跳转,点击字母滚动到相关的城市

原理解析

1.代码

1.1.wxml

<view class='container'>
<view class='left'>
  <scroll-view class='leftScroll' scroll-y>
    <block wx:for="{{list}}" wx:key="list">
      <view bindtap='clickScroll' data-id="{{item}}">{{item}}</view>
    </block>
  </scroll-view>
</view>
<view class='right'>
  <scroll-view class='rightScroll' scroll-y scroll-into-view="{{toView}}" scroll-with-animation="true">
    <block wx:for="{{list}}" wx:key="list">
      <view bindtap='clickScroll' id="{{item}}">{{item}}</view>
    </block>
  </scroll-view>
</view>
</view>

1.2.wxss

page{
  width:100%;
  height:100%;
}
.container{
  flex-direction: row;
  height:100%;
}
.left{
  width:100px;
  height:80%;
}
.left scroll-view{
  height:100%;
}
.left view{
  padding:10px;
  text-align: center;
  background-color:#0f0;
  margin-bottom:10px;
  color:#fff;
}
.right{
  flex:1;
  height:80%;
}
.right scroll-view{
  height:100%;
}
.right view{
  height:150px;
  background-color:#f00;
  color:#fff;
  margin-bottom:10px;
}

/* 隐藏滚动条的 */
::-webkit-scrollbar{
  width:0;
  height:0;
  color:transparent;
}

1.3.js

// pages/maodian/maodian.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    list: ["list0", "list1", "list2", "list3", "list4", "list5", "list11", "list12", "list13", "list14", "list15", "list25", "list26", "list27", "list28", "list29", "list30"],
    toView: ''
  },

  clickScroll: function(e) {
    var id = e.currentTarget.dataset.id
    this.setData({
      toView: id
    })
    console.log(e.currentTarget.dataset);
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {

  },

})

1.4.效果

2.应用举例

2.1wxml

<view class='head flex flexSb'>
  <view class='headL flex'>
    <view class='headL-name'>分类</view>
    <view class='headL-sj'></view>
  </view>
  <view class='headR flex flexC alignC'>
    <view class='headR-ss'></view>
    <view class='headR-name'>我是顶部悬浮</view>
  </view>
</view>
<view class='tab flex flexSb'>
  <view class='tab-li rowAndColCenter {{index==tab_index?"on":""}}' wx:for="{{tab_arr}}" data-index='{{index}}' catchtap='tabClick'>
    <view class='tab-li-wrap flex alignC'>
      <view class='tab-line'></view>
      <view class='tab-name'>{{item}}</view>
    </view>
  </view>
</view>
<view class='main'>
  <scroll-view scroll-y style='height:{{ht}}px;' scroll-with-animation="false" bindscroll="scrollRight" scroll-into-view="{{toViewRt}}">
    <block wx:for="{{tab_arr}}">
      <view class='mainLi'>
        <view class='mainLi-title {{index==tab_index?"on":""}}' id='t{{index}}'>{{item}}</view>
        <view class='mainLi-li'>
          <view class='mainLi-li-title'>我是副标题1</view>
          <view class='flex alignC mt20'>
            <view class='mainLi-li-li'>tip1</view>
            <view class='mainLi-li-li'>tip2</view>
            <view class='mainLi-li-li'>tip3</view>
          </view>
        </view>
        <view class='mainLi-li'>
          <view class='mainLi-li-title'>我是副标题2</view>
          <view class='flex alignC mt20'>
            <view class='mainLi-li-li'>tip1</view>
            <view class='mainLi-li-li'>tip2</view>
          </view>
        </view>
      </view>
      <image wx:if='{{index==0}}' class='ad' src='http://demo.sc.chinaz.com/Files/DownLoad/webjs1/201801/jiaoben5647/img/5.jpg'></image>
    </block>
  </scroll-view>
</view>

2.2wxss

/* 这里是公共样式 */
.flex {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  display: box;
  flex-wrap:wrap;
}

.flexC {
  -webkit-box-pack: center;
  justify-content: center;
  -webkit-justify-content: center;
  -moz-justify-content: center;
  -ms-justify-content: center;
  -o-justify-content: center;
}

.alignC{
  align-items: center;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -moz-align-items: center;
  -ms-align-items: center;
  -o-align-items: center;
}

.flexSb {
  justify-content: space-between;
  -webkit-justify-content: space-between;
  -moz-justify-content: space-between;
  -ms-justify-content: space-between;
  -o-justify-content: space-between;
}

.rowAndColCenter {
  display: flex;
  display: -webkit-flex;
  display: -moz-flex;
  flex-direction: column;
  -webkit-flex-direction: column;
  -moz-flex-direction: column;
  justify-content: center;
  -webkit-justify-content: center;
  -moz-justify-content: center;
  align-items: center;
  -webkit-align-items: center;
  -moz-align-items: center;
}

/* 页面样式 */
page {
  background-color: #f2f2f2;
}

.head {
  width: 100%;
  padding: 15rpx 24rpx;
  box-sizing: border-box;
  background-color: #fff;
  border-bottom: 1rpx solid #ddd;
  position: fixed;
  top: 0;
  left: 0;
}

.headL {
  width: 102rpx;
}

.headL, .headL-name, .headL-sj, .headR-name, .headR-ss {
  height: 62rpx;
}

.headL-name {
  line-height: 62rpx;
  color: #ff7500;
  font-size: 28rpx;
}

.headL-sj {
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAHCAYAAAA8sqwkAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkE0RTY1QzZCMTE4NDExRUFBNDVEQUFFODJGMkU1NzU4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkE0RTY1QzZDMTE4NDExRUFBNDVEQUFFODJGMkU1NzU4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTRFNjVDNjkxMTg0MTFFQUE0NURBQUU4MkYyRTU3NTgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTRFNjVDNkExMTg0MTFFQUE0NURBQUU4MkYyRTU3NTgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7BouK/AAAAaUlEQVR42mL8X8pwh4GBQYiBOHCPEajBFcjYAsRsBBR/A2IfJiCxG4iTgPg/HsV/gTgSiPczQQWWAnE+DsUgg7KAeBOIw4QkMRmIO7BoqALiWTAOExbJ2fgMYcFifSYQiwDxV2zOBAgwAM8fFaNjssJvAAAAAElFTkSuQmCC);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 12rpx 7rpx;
  width: 12rpx;
  margin-left: 7rpx;
}

.headR {
  width: 600rpx;
  height: 62rpx;
  background-color: #f1f1f1;
  border-radius: 10rpx;
}

.headR-ss {
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkVCREIyMURFMTE4NTExRUFCRUY1RTBDMEY5MzNBMEE4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkVCREIyMURGMTE4NTExRUFCRUY1RTBDMEY5MzNBMEE4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RUJEQjIxREMxMTg1MTFFQUJFRjVFMEMwRjkzM0EwQTgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RUJEQjIxREQxMTg1MTFFQUJFRjVFMEMwRjkzM0EwQTgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6u60W0AAACZklEQVR42qyWXYhNURTHz0XJGCVRoybFvDBz75S8jLo+UhIaiQeR8kBT04RGMxpSShmfoQyRooh5kQchhRruzYOiJkMMEQ8uSl4oX+G36n9qz+mec09z96pfa+19zz3/s85eZ+2dKRQKQQprhMXQBDXwDQZhIJ/Pvw5S2riE3yZBG7RDQ9xFxWLxJe44omcriWViMtsAp2CyM/cMhuEdTIG5kHN+f28PhuitOLExZeYOwWUJfYAOmApZWAOdsAmaoU6Zl2AG3CTTnrRih2Gn4j6YBafhS8z/P5HJGV13XnMHENxdSawVuhXvha3wM83CI/gDNtvaaWo/gvPjxMxfUXwO9gWjMAR34MI1ux4ntgdq9bragupsHfyxdSa7jVExK//tGndWKWTZ2Td4UMOOqFhOpfwPLgV+7KJ8C9nVuGLNiu97ErLsXlmlarggmpnZ08CvvZFvcsVqFf/2LPZLfsRr/Kp4vGexCfLfXbEhxTnPYjPlX7hig4oXwlgfKlTgbNw0DQvRzEoat3vKKrzPI313IzrIsbCJeshqOm6bhifKtauj2n2tMq9WqXdNvkRW/XFdf738WjgyyqysibeowrNJW8wNp9t3wYXITp0k0gC3Cbdo6i/UpzkW7IJe5xvp1XYxVEbHWtEqPVzYGIadrrGUV3k36VhgRbIM3sJE2wjVyuyI8BgewBP4rLjLaXdzuHlW82Z3yLi10oEntG7tT/MSrnkI/Yj0RV7tAG6RhivtIJRJeW6sV0doVBuyyn1uzZabfExYy3u4JRquTiuWtJ1UKh47JiyPWzOvxsOswJ20Q9R/AQYAYUSpQ57DGdAAAAAASUVORK5CYII=);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 27rpx 27rpx;
  width: 27rpx;
  margin-right: 22rpx;
}

.headR-name {
  line-height: 62rpx;
  color: #b5b5b5;
  font-size: 26rpx;
}

.tab {
  width: 180rpx;
  padding-top: 30rpx;
  background-color: #fff;
  position: fixed;
  left: 0;
  top: 93rpx;
}

.tab-li {
  width: 180rpx;
  height: 104rpx;
}

.tab-line {
  width: 8rpx;
  height: 18rpx;
  margin-right: 14rpx;
}

.tab-li.on {
  background-color: #f2f2f2;
  color: #ff7500;
  border-radius: 10rpx;
}

.tab-li.on .tab-line {
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAASCAYAAABmQp92AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkNEREJBODUxMTE4NzExRUE5NkUyOEUxMUQ2MUUyRUU2IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkNEREJBODUyMTE4NzExRUE5NkUyOEUxMUQ2MUUyRUU2Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Q0REQkE4NEYxMTg3MTFFQTk2RTI4RTExRDYxRTJFRTYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Q0REQkE4NTAxMTg3MTFFQTk2RTI4RTExRDYxRTJFRTYiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7ciuujAAAAcUlEQVR42mL8X8oAAqpA3AHELgwQsAeIK4D4NiNQgTqQcQKIBRhQwQcgtmACEm1YJBmgYm1MSMZiA24gBXx4FPAwMRAAowoQCj7hkf/CBI1aXGAXSEE1NGoZsER3NUjBDVC8A/E6IP4MxeugYjcAAgwAn/0VlirT1WUAAAAASUVORK5CYII=);
  background-size: 8rpx 18rpx;
  background-position: center;
  background-repeat: no-repeat;
  width: 8rpx;
  height: 18rpx;
}

.main {
  position: fixed;
  top: 123rpx;
  right: 15rpx;
}

.mainLi {
  background-color: #fff;
  border-radius: 10rpx;
  padding: 16rpx 32rpx 10rpx;
  width: 528rpx;
  box-sizing: border-box;
  margin-bottom: 24rpx;
}

.mainLi-title {
  font-size: 34rpx;
  color: #212121;
  height: 60rpx;
  line-height: 60rpx;
}

.mainLi-title.on{
  color: #ff7500;
  font-weight: bold;
}

.mainLi-li {
  padding: 25rpx 0;
  border-bottom: 1rpx solid #ddd;
}

.mainLi-li:last-child {
  border-bottom: 0;
}

.mainLi-li-title {
  font-size: 26rpx;
  color: #404040;
}

.mainLi-li-li {
  font-size: 24rpx;
  color: #606266;
  height: 53rpx;
  line-height: 53rpx;
  padding: 0 20rpx;
  background-color: #f6f7f9;
  border-radius: 5rpx;
  margin-right: 13rpx;
}

.mainLi-li-li:last-child {
  margin-right: 0;
}

.mt20 {
  margin-top: 20rpx;
}

.ad {
  display: block;
  width: 100%;
  height: 134rpx;
  margin-bottom: 24rpx;
}

/* 去除滚动条 */
::-webkit-scrollbar{
width: 0;
height: 0;
color: transparent;
}

2.3j

Page({

  /**
   * 页面的初始数据
   */
  data: {
    // 左侧楼层数据
    tab_arr: ['我是tab1', '我是tab2', '我是tab3', '我是tab4', '我是tab5', '我是tab6', '我是tab7'],
    // 记录当前点击到第几个了
    tab_index: 0,
    // 初始值
    toViewRt: 't0',
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var that = this;
    // 滚动的高度
    that.data.scrolltop = 0;
    // 监听各个种类的距离顶部的高度
    that.data.element = [];
    // 控制是否使用scroll标签的滚动事件(防止点击后同时出发滚动事件而引起的回弹效果)
    that.data.scrollFlag = true;

    // 获取当前设备的宽高,设置scroll标签的高度
    wx.getSystemInfo({
      success: (res) => {
        var windowHeight = res.windowHeight;
        that.setData({
          ht: (windowHeight - 70)
        });
      },
    });

    // 渲染完成后。计算各个元素的距离顶部的高度
    that.getTitleTop();
  },

  // 点击tab
  tabClick(e) {
    var that = this;
    var index = e.currentTarget.dataset.index;
    that.data.scrollFlag = false;
    if (that.data.tab_index == index) {
      return false
    } else {
      that.setData({
        tab_index: index,
        toViewRt: 't' + index
      }, () => {
        setTimeout(() => {
          that.data.scrollFlag = true;
        }, 1000);
      });
    }
  },

  // 滚动右侧菜单
  scrollRight(e) {
    var that = this;
    if (that.data.scrollFlag) {
      that.data.scrolltop = e.detail.scrollTop;
      var element = that.data.element;
      var elementIndex = that.getTimeIndex(element, that.data.scrolltop);
      that.setData({
        tab_index: elementIndex
      });
    }
  },

  // 获取位置
  getTitleTop(scrolltop = 0, cb = '') {
    var that = this;
    //获取导航的初始位置
    const query = wx.createSelectorQuery()
    query.selectAll('.mainLi-title').boundingClientRect();
    query.exec(function (res) {
      res = res[0];
      var arr = [];
      for (var i = 0; i < res.length; i++) {
        arr.push(res[i].top + scrolltop - 70);
      }
      that.data.element = arr;
    });
    if (typeof cb == "function") {
      cb(scrolltop);
    }
  },
  // 判断在数组哪两项之间
  getTimeIndex(timeArr, time) {
    var timeIndex = -1;
    for (var i = 0; i < timeArr.length; i++) {
      if (timeArr[i] > time) {
        timeIndex = i - 1;
        break;
      }
    }
    return timeIndex;
  }
});

2.4效果

3.说明

3.1实现思路解析: 其实就是通过,scroll-view标签绑定scroll-into-view,给scroll-view标签内需要跳转的标签绑定一个id名字,点击时把scroll-into-view里的内容替换为对应的跳转的锚点名字即可;

3.2 当中有一些小的细节,例如滚动条的隐藏  ::-webkit-scrollbar{width: 0;height: 0;color: transparent;} ;
3.3 实例思路:首先请求数据当页面渲染完成后,获取页面各个元素距离顶部的高度。监听页面滚动距离页面顶部的高度,通过滚动高度和各个元素距离顶部的高度做一个比较,如果滚动距离在两个值之间就取小的。
3.4 在实例中会遇到这种情况,点击左侧快捷导航时,右侧的scroll标签会同时执行滚动事件,如果页面位于最顶部,点击最后一个快捷导航按钮,当页面滚动到最底部时页面会有回弹现象(表现感觉有点怪异,但逻辑是说得通的,点击执行滚动到最底部的动作,但在滚动时会执行滚动事件监听,到达最底部不满足滚动的条件,滚动事件将index重新设置为满足滚动的条件值)
3.5 针对3.4中的问题,我就想干脆来个优先级吧,点击我就不让你滚了,用一个变量控制一下,在2.3的代码中通过scrollFlag有体现,用户体验效果会好点。

猜你喜欢

转载自blog.csdn.net/hangGe0111/article/details/96478653
今日推荐