上一篇讲解了左=>右联动,那个还比较简单,本篇写剩下比较核心的部分,也是本次开发过程中遇到最难的部分,右=>左联动,先简单看一下演示

 
右左联动.gif

一、关键技术:
(1) 小程序 wxss 中使用 rpx,而 js 中 scrollTop 获取到的值是 px,所以存在rpx 转 px 的问题。以 iPhone6 为基准,转换公式:

// percent 为当前设备1rpx对应的px值
var percent = res.windowWidth / 750;

详情参考:WXSS尺寸单位

(2) 微信自带scroll-view UI组件,通过 bindscroll="scroll" 绑定滚动事件;通过 scroll-top="{{scrollTop}}" 动态控制 左侧滑栏的被动滚动。
二、实现思路:
通过计算整个右侧滑栏滚动上去的高度 与 右侧滑栏中每一个分类距顶部的距离做比对,获取到该滚动置顶的分类的 index 。然后用获取到的 index 乘以左侧滑栏中某一项的高度,动态赋值给左侧滑栏内的 scrollTop ,控制左侧滑栏的联动。

 
 

以下是代码,考虑到部分新手同学,几乎为每一行代码添加了注释。
wxml代码:标签中属性如有不懂,请自行查看小程序API,内有详细讲解!

<view class="container">
<!--左侧栏-->
<scroll-view class='scroll_left' scroll-y="true" style="height:{{winHeight}}px;" scroll-with-animation="true" scroll-top="{{scrollTop}}">
<view class="nav_left">
<block wx:for="{{list}}" wx:for-index="idx" wx:for-item="itemName" wx:key="*this">
<!--当前项的id等于item项的id,那个就是当前状态-->
<!--用data-index记录这个数据在数组的下标位置,使用data-id设置每个item的id值,供打开2级页面使用-->
<view class="nav_left_items {{curNav == idx ? 'active' : ''}}" bindtap="switchRightTab" data-index="{{index}}" data-id="{{item.id}}" id="{{idx}}">{{itemName[0].title}}</view>
</block>
</view>
</scroll-view> <!--右侧栏-->
<scroll-view scroll-y="true" class="scroll_right" style="height:{{winHeight}}px;" scroll-into-view="{{scrollTopId}}" scroll-with-animation="true" bindscroll="scroll">
<view class="nav_right">
<view class='mink' wx:for="{{list}}" wx:for-index="idx" wx:for-item="itemName" wx:key="*this">
<view class='minl' id='{{idx}}'>{{itemName[0].title}}</view>
<block wx:for="{{itemName}}" wx:key="*this" wx:for-index="idex">
<view class="nav_right_items" wx:if="{{idex>0}}">
<navigator url="../detail/detail" hover-class="other-navigator-hover">
<view>
<image src="{{item.picture}}"></image>
<view >
<text>{{item.desc}}</text>
</view>
</view>
</navigator>
</view>
</block>
</view>
<view style="width:100%;height:30rpx;background:#f0f4f7"></view>
</view>
</scroll-view>
</view>

js代码:

// pages/list-1/list-1.js
var list = require('../../utils/list.js')
Page({
data: {
// 左侧点击类样式
curNav: 'A',
scrollTop: 0,
// 定义一个空数组,用来存放右侧滑栏中每一个商品分类的 Height
listHeight:''
},
// 生命周期函数--监听页面初次渲染完成
onReady: function () {
var that = this;
// 定义右侧标题的 rpx 高度 和 px 高度
var right_titleRpxHeight = 60;
var right_titleHeight;
// 定义右侧单个商品的 rpx 高度 和 px 高度
var right_contentRpxHeight = 180;
var right_contentHeight;
// 定义左侧单个tab的 rpx 高度 和 px 高度
var left_titleRpxHeight = 140;
var left_titleHeight;
// 获取可视区屏幕高度
wx.getSystemInfo({
success: function (res) {
// percent 为当前设备1rpx对应的px值
var percent = res.windowWidth / 750;
that.setData({
winHeight: res.windowHeight,
right_titleHeight: Number(right_titleRpxHeight * percent),
right_contentHeight: Number(right_contentRpxHeight * percent),
left_titleHeight: Number(left_titleRpxHeight * percent)
})
}
})
// 把请求到的 list 中的数据赋值给 listChild1
var listChild1 = list.List[0];
// 定义一个 names ,用于存放 scroll-into-view 使用的 id
var names = '';
// 循环 listChild1 中的每一项
for (var item in listChild1) {
// 把 listChild1 中每一项的键值用“:”(便于后期处理)分隔开,存入 names 中,数据格式见图‘names中的数据’
names+= ":"+item;
// 计算右侧每一个分类的 Height 。
// listChild1 下的每一个 item 中包含该分类的 title,所以 listChild1[item].length 需要减一
// 右侧每一个分类中每一行放两个商品,所以 this.data.right_contentHeight 除二
// 最后加上 right_titleHeight,此时 height 为右侧一个完整分类的高度
var height = (listChild1[item].length - 1) * this.data.right_contentHeight / 2 + this.data.right_titleHeight;
// 同上面 names 的道理,把每一个 height 用“:”隔开放入 listHeight 中
this.data.listHeight += ":" + height;
this.setData({
// 把 listChild1 赋值给 list ,供 wxml 中循环使用
list: listChild1,
listHeight:this.data.listHeight
})
}
// 把 names 的数据切成数组
var names = names.substring(1).split(':');
this.setData({
names:names
})
},
// 右侧滑栏的 bindscroll 事件函数(ES6写法)
scroll(event){
// 把 listHeight 切割成数组
var height = this.data.listHeight.substring(1).split(':');
// 定义一个 index 供左侧边栏联动使用
var index = 1;
var num = 0;
for(var i = 0;i<height.length;i++){
// 累计右侧滑栏滚动上去的每一个分类的 Height
num+=parseInt(height[i]);
// 循环判断 num 是否大于右侧滑栏滚动上去的 Height ,然后 get 到 i 值赋给 index
if (num > event.detail.scrollTop){
index = i+1;
// 如果右侧滑栏滚动高度小于单个类别高度的 1/2 时,index 为 0
if (event.detail.scrollTop < height[0]/2) {
index = 0;
}
break;
}
}
// 定义并设置左侧边栏的滚动高度
var left_scrollTop = this.data.left_titleHeight*index
this.setData({
scrollTop: left_scrollTop,
// 动态给左侧滑栏传递对应该项的 id,用于高亮效果显示
curNav: this.data.names[index]
})
},
//点击左侧 tab ,右侧列表相应位置联动 置顶
switchRightTab: function (e) {
var id = e.target.id;
this.setData({
scrollTopId: id,
// 左侧点击类样式
curNav:id,
})
}
})

样式表 和 list 数据请翻看上一篇:《微信小程序,左右联动》

NO--14 微信小程序,左右联动二的更多相关文章

  1. 微信小程序条码、二维码生成模块

    代码地址如下:http://www.demodashi.com/demo/13994.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...

  2. 微信小程序把玩(二十八)image组件

    原文:微信小程序把玩(二十八)image组件 image组件也是一个程序不可缺少的,可以这样说一个app中image组件随处可以看到,一般 image有两种加载方式第一种是网络图片第二种是本地图片资源 ...

  3. 微信小程序把玩(二十九)video组件

    原文:微信小程序把玩(二十九)video组件 视频播放组件与图片加载组件也没啥差别,使用起来也没啥注意的 重要属性: wxml <!--监听button点击事件--> <button ...

  4. 微信小程序把玩(二十七)audio组件

    原文:微信小程序把玩(二十七)audio组件 音频播放已经封装的很好!只需配合属性设置即可! (method和data配合使用) 主要属性: wxml <audio action="{ ...

  5. 微信小程序把玩(二十四)toast组件

    原文:微信小程序把玩(二十四)toast组件 toast消息提示框,可用在提示一些信息,比如清楚缓存给用户一个友好的提示!或操作一些请求不想让用户有什么操作,toast也可以做到因为toast显示时其 ...

  6. 微信小程序把玩(二十五)loading组件

    原文:微信小程序把玩(二十五)loading组件 loading通常使用在请求网络数据时的一种方式,通过hidden属性设置显示与否 主要属性: wxml <!----> <butt ...

  7. 微信小程序把玩(二十六)navigator组件

    原文:微信小程序把玩(二十六)navigator组件 navigator跳转分为两个状态一种是关闭当前页面一种是不关闭当前页面.用redirect属性指定. 主要属性: wxml <naviga ...

  8. 微信小程序把玩(二十二)action-sheet组件

    原文:微信小程序把玩(二十二)action-sheet组件 action-sheet组件是从底部弹出可选菜单项,估计也是借鉴IOS的设计添加的,action-sheet有两个子组件, action-s ...

  9. 微信小程序把玩(二十三)modal组件

    原文:微信小程序把玩(二十三)modal组件 modal弹出框常用在提示一些信息比如:退出应用,清楚缓存,修改资料提交时一些提示等等. 常用属性: wxml <!--监听button点击事件-- ...

  10. 微信小程序把玩(二十)slider组件

    原文:微信小程序把玩(二十)slider组件 slider滑动组件用的不太多,在其他平台反正我是用的不多 主要属性: wxml <slider max="100" step= ...

随机推荐

  1. 2.1 The Python Interpreter(python解释器)

    2.1 The Python Interpreter(Python解释器) Python是一门解释性语言.Python的解释器一次只能运行一个命令.标准的Python解释器环境可以用通过输入pytho ...

  2. AOP的核心:代理与织入

    分为两步: 1.动态生成代理类: 2.织入: 2.6 织入(Weaving) 织入是将增强添加到目标的具体连接点上的过程 . AOP 织入方式: 方式 实现 应用编译期织入 特殊的 Java 编译器. ...

  3. 安卓预览报错 Failed to load AppCompat ActionBar with unknown error

    报错信息 : Render ProblemFailed to load AppCompat ActionBar with unknown error. Failed to instantiate on ...

  4. centos下mysqlreport安装和使用

    首先查看你的机器是否安装了perl: #perl -v 显示版本号即表示已安装 然后: #yum install perl-DBD-mysql perl-DBI #yum install mysqlr ...

  5. 利用Zookeeper实现分布式锁及服务注册中心

    对于Zookeeper的定义以及原理,网上已经有很多的优秀文章对其进行了详细的介绍,所以本文不再进行这方面的阐述. 本文主要介绍一些基本的准备工作以及zookeeper.net的使用. 本文源代码gi ...

  6. python基础整理6——爬虫基础知识点

    爬虫基础 什么是爬虫: 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用的名字还有蚂蚁. ...

  7. C语言程序设计I—第一周教学

    这是在修改人才培养方案后第一次上C语言程序设计课程,本课程由原来的1学期80课时(周学时6)修改为2学期48(周学时4)+32(周学时2)课时的模式,开课学期也由一年二期改为大一整学年,当时修改的主要 ...

  8. MySQL学习之备份

    MySQL数据库备份与还原 数据库备份也叫SQL数据备份,备份的结果都是SQL指令. 在MySQL中专门提供了一个用于数据库备份的SQL客户端:mysqldump.exe(MySql document ...

  9. 改用固定IP后zabbix无法发送邮件的问题解决

    虚拟机之前一直用随机IP,然后发送邮件也正常. 改成固定IP以后,发送邮件失败. 用mail命令发送邮件成功. 查看zabbix_server的log,显示 cannot connect to SMT ...

  10. 各类分布----二项分布,泊松分布,负二项分布,gamma 分布,高斯分布,学生分布,Z分布

    伯努利实验: 如果无穷随机变量序列  是独立同分布(i.i.d.)的,而且每个随机变量  都服从参数为p的伯努利分布,那么随机变量  就形成参数为p的一系列伯努利试验.同样,如果n个随机变量  独立同 ...