微信小程序的多级选择器(multiSelector模式的Picker)如何设计出各列之间的可选项有关联的逻辑?

在微信小程序中,我们常常会需要使用到选择器(Picker),而选择器有一种模式叫做multiSelector,即多级选择。这个选择器可用于提交多个维度的信息,例如在餐厅里点餐时,需要同时提交要点的蔬菜、荤菜、主食、汤的信息。

关于选择器,使用的方法见picker | 微信开放文档。这里简单说明一下多级选择器的设置。对于多级选择器,其需要在程序中提供的信息有这些:

注:此图转载于微信开放文档

一、多级选择器和普通选择器的区别

相比普通的Picker,多级选择器的属性有这些不同:

array

由于普通选择器只有一列的选项,所以只需提供一个一维的简单array即可。但多级选择器有不止一列的选项,而每一列的选项都需要一个一维的array进行列举。因此,需要提供一个大array,里面有多个一维array。在大array里,第一个一维array代表第一列的选项,以此类推。所以,如果提供给array参数的大array是

[['硬件','软件'], ['电机驱动器','激光','电池','数字IO']]

则选择器的显示是

value

同样,对于value选项,普通选择器的value属性值只是一个数,但对于多级选择器,value是一个array,每一个元素代表一个列的当前选择的索引值。

bindcolumnchange

bindcolumnchange和bindchange的最本质的区别在于:bindchange是在value改变时被触发,而value改变的前提是在选择器里选择的项更改,且点击确定了,才会生效;而bindcolumnchange是只要选择器里选择的项更改了,还未点击确定,就被触发。

用一个例子进行说明

<view>
  <picker mode="multiSelector" bindchange="onSupportChange" bindcolumnchange="onSupportColumnChange" range="{{supportTypeRange}}" value="{{currentSupport}}">
 支持类型: {{supportSelect[0]}},{{supportSelect[1]}}
  </picker>
</view>
onSupportChange: function(e){
    console.info("bindchange is triggered")
    console.info(e.detail)
    this.setData({
      currentSupport: e.detail.value, 
      supportSelect: [Object.keys(supportData)[e.detail.value[0]], supportData[Object.keys(supportData)[e.detail.value[0]]][e.detail.value[1]]]
    })

  },
  onSupportColumnChange: function(e){
    console.info("bindcolumnchange is triggered")
    console.info(e.detail)
    if (e.detail.column == 0){
      this.setData({
        currentSupport: [e.detail.value,0],
        supportTypeRange: getSupportRange(supportData, [e.detail.value,0])
      })
    }
  }

简单看一下这两个函数,其中onSupportChange绑定了bindchange,而onSupportColumnChange绑定了bindcolumnchange。目前,在这两个函数的第一行添加了console.info,用于打印函数的相应信息表明函数已被触发。

下面看一下运行效果

注意bindcolumnchange和bindchange是在什么条件下被触发的。

二、如何设计出多级联动的逻辑

在多级选择器中,各列之间默认情况下是相互独立的。但实际应用中,往往并非如此,而是有关联的。例如,在苹果Apple Store购物,首先要确定需要选择的是Mac,iPad或是iPhone。如果第一级选择了Mac,则下一级的可选项包括Macbook,iMac,Mac mini等;如果第一级选择了iPad,则下一级的可选项包括iPad Pro,iPad Air等。也就是说,在选择器中,在某一级的选择不同时,其它级的可选项也是不同的。因此,需要设计出一种逻辑,而这种逻辑称为多级联动。目前已有一些博客,如微信小程序Picker自定义数据多级联动_小程序picker联动-CSDN博客等给出了多级联动的例子。本文会用更通俗的语言更详细地说明多级联动的逻辑实现的基本思路。

思路简介

在第一章节的最后一小节,提到了bindcolumnchange,这个事件只要选择器里的选项更改了,还没有点确认,就会触发。而我们在用多级选择器进行选择时,确实需要让手指在一个选项上滑动后,即在某一列上的选项更改后,不点确认,其它的列里的选项就应改变。例如,对于Apple Store购物的选择器,小程序刚完成初始化时,点开选择器,第一列显示[Mac, iPad, iPhone]选项,而当前选择的是Mac,而第二列显示[Macbook, iMac, Mac mini]选项。但当在第一列中,当前已经选择了iPad后,不用点确认,第二列就应显示[iPad Pro, iPad Air]选项。

在Picker里,一个列里的选项,以及当前选择的项,是由range和value决定的。所以,改变第二列显示的选项,思路就是在该Picker的range和value绑定的变量做文章。

示例

下面以一个AGV公司申请技术支持的程序为例,说明多级联动逻辑的具体实现方法。

问题分析

对于AGV,如果用户使用出现了问题,需要申请技术支持,需要提供关于问题的信息,选择需要的技术支持的类型。

技术支持的类型分为以下几种:

首先,是硬件问题还是软件问题?

如果是硬件问题,则可能是电机驱动器,激光,电池或数字IO的问题。

如果是软件问题,则可能是定位,线路跟随,车辆行为,交通管理的问题。

因此,需要一个multiSelector模式的Picker。该Picker有两级,即两列选项:第一列有硬件和软件两个选项;第二列的选项要根据第一列的选择来决定,如果第一列选了硬件那么第二列就有4个硬件问题的选项,否则就有4个软件问题的选项。

数据

关于所有的可能选项的数据supportData,这里用一个Javascript的对象来保存。

const supportData = {'硬件':['电机驱动器','激光','电池','数字IO'], '软件':['定位','线路跟随','车辆行为','交通管理']}

Picker显示的选项

而对于Picker中显示的选项,第一列肯定是那两个,但第二列是哪四个,是由第一列选择了哪个决定的。第一章节的array里提到用array的array存放多级选择器目前提供的各列选项。所以,下面附上一个函数,该函数根据所有选项的数据,以及第一列选择的索引,以array的array输出多级选择器应提供的各列的选项。

function getSupportRange(SuppData, currSupp){
  const firstPartRange = Object.keys(SuppData)
  var secondPartRange = SuppData[firstPartRange[currSupp]]
  return [firstPartRange, secondPartRange]
}

这里currSupp是第一列选择的索引。所以函数的第一行firstPartRange已经得出了第一列的选项,而第二列的选项,可在supportData里,通过键值获得,而键值是由第一列的选项和选择的索引获得的。最终返回一个有两个array的大array。

最终程序

这里给出程序的wxml代码

<view>
<text>请选择你需要的技术支持的类型</text>
</view>
<view>
  <picker mode="multiSelector" bindchange="onSupportChange" bindcolumnchange="onSupportColumnChange" range="{{supportTypeRange}}" value="{{currentSupport}}">
 支持类型: {{supportSelect[0]}},{{supportSelect[1]}}
  </picker>
</view>

以及js代码

// index.js

function getSupportRange(SuppData, currSupp){
  const firstPartRange = Object.keys(SuppData)
  var secondPartRange = SuppData[firstPartRange[currSupp]]
  return [firstPartRange, secondPartRange]
}
const supportData = {'硬件':['电机驱动器','激光','电池','数字IO'], '软件':['定位','线路跟随','车辆行为','交通管理']}

Page({
  data:{
    currentSupport:[0,0],
    supportSelect: [Object.keys(supportData)[0], supportData[Object.keys(supportData)[0]][0]],
    supportTypeRange: getSupportRange(supportData, 0)
  },
  onSupportChange: function(e){
    console.info(e.detail)
    this.setData({
      currentSupport: e.detail.value, 
      supportSelect: [Object.keys(supportData)[e.detail.value[0]], supportData[Object.keys(supportData)[e.detail.value[0]]][e.detail.value[1]]]
    })

  },
  onSupportColumnChange: function(e){
    console.info("column change: ",e.detail)
    if (e.detail.column == 0){
      this.setData({
        currentSupport: [e.detail.value,0],
        supportTypeRange: getSupportRange(supportData, e.detail.value)
      })
    }
  },
})

在这里注意onSupportColumnChange里改变了supportTypeRange的值,而这个变量就是Picker里显示的各列选项(range)。currentSupport代表当前各列选择的索引值(value),而supportSelect用于在屏幕上显示目前已选择的具体内容。

重点说明一下onSupportColumnChange,即bindcolumnchange事件传递的内容,即e.detail

从打印的内容可看出,bindcolumnchange事件传递两个信息,其中column指选项变化发生所在的列,而value指变化后,目前所选择的索引值。

三、总结

对于多级选择器,如需实现多级联动,即各列之间的可选项有关联的逻辑,应当使用bindcolumnchange事件,当某列的选择有了变化,无需确认,就对整个多级选择器的可选项进行改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值