# Cube-Cascade-Picker-Popup
# 介绍
通过把基础组件 Popup 及 CascadePicker 相互结合,提供了一种从弹出浮层的形式来使用。
CascadePickerPopup 选择器的部分与 CascadePicker 完全一致,通过 list、selectedIndex 来控制选择数据的显示。其中 list 需要传入的是一个树形结构,第一列数组的每个选项的children属性,对应着切换到该选项时后续列的数据,从而实现对后续列的改变。
CascadePickerPopup 中的弹出层可以分别设置:title 控制标题、subtitle控制子标题、cancelTxt控制顶部取消按钮文案、confirmTxt控制顶部确定按钮文案、maskClosable控制是否点击蒙层隐藏。
# 示例
# 基础用法
可以从下方的例子中看到,通过调用 CascadePickerPopup 实例方法 show 进行显示,同时也可以传入 title、subtitle、cancelText、confirmText 来控制弹层的文案;而 CascadePickerPopup 选择器的数则据通过传入的 list、selectedIndex 来控制。
CascadePickerPopup 保留了 Picker 原有的事件,比如 columnChange、change、maskClick 等,同时还新增 valueChange 事件,此事件在点击确认按钮后且选择的数据发生变化时触发。
<template>
  <view>
    <cube-button bindclick="showPicker">basic-picker</cube-button>
    <cube-cascade-picker-popup
      wx:ref="picker"
      title="请选择你的组合"
      sub-title="副标题"
      cancel-txt="返回"
      confirm-txt="确定"
      list="{{ dataList }}"
      selected-index="{{ selectedIndex }}"
      bindchange="onChange"
      bindcolumnChange="onColumnChange"
      bindtoggle="onToggle"
      bindclose="onClose"
      bindconfirm="onConfirm"
      bindmaskClick="onMaskClick"
      bindvalueChange="onValueChange"
    />
    <view class="demo-data" wx:if="{{ confirmParams.length || valueChangeParams.length }}">
      <view class="key">其他事件可打开控制台查看输出</view>
      <block wx:if="{{ confirmParams.length }}">
        <view class="key">confirmParams 事件参数:</view>
        <view class="value">
          <view class="value-item" wx:for="{{confirmParams}}" wx:key="index">
            <view class="item-key">{{item[0]}}</view>
            <view class="item-value">{{item[1]}}</view>
          </view>
        </view>
      </block>
      <block wx:if="{{ valueChangeParams.length }}">
        <view class="key">valueChange 事件触发次数:{{ valueChangeCount }}</view>
        <view class="key">valueChangeParams 事件参数:</view>
        <view class="value">
          <view class="value-item" wx:for="{{valueChangeParams}}" wx:key="index">
            <view class="item-key">{{item[0]}}</view>
            <view class="item-value">{{item[1]}}</view>
          </view>
        </view>
      </block>
    </view>
  </view>
</template>
<script>
import { createComponent } from '@mpxjs/core'
import { beauty } from '../../common/utils'
createComponent({
  data: {
    selectedIndex: [0, 1, 0],
    dataList: [{
      value: 'Fruit',
      text: 'Fruit',
      children: [{
        value: 'Apple',
        text: 'Apple',
        children: [{ value: 1, text: 'One' }, { value: 2, text: 'Two' }]
      }, {
        value: 'Orange',
        text: 'Orange',
        children: [{ value: 3, text: 'Three'}, { value: 4, text: 'Four' }]
      }]
    }, {
      value: 'Drink',
      text: 'Drink',
      children: [{
        value: 'Coffee',
        text: 'Coffee',
        children: [{ value: 1, text: 'One' }, { value: 2, text: 'Two' }]
      }, {
        value: 'Tea',
        text: 'Tea',
        children: [{ value: 1, text: 'One' }, { value: 3, text: 'Three'}]
      }]
    }],
    confirmParams: '',
    valueChangeParams: '',
    valueChangeCount: 0
  },
  methods: {
    showPicker() {
        this.confirmParams = '',
        this.valueChangeParams = '',
        this.$refs.picker.show()
      },
      onColumnChange(e) {
        console.log('columnChange 事件触发:')
        console.log(beauty(e.detail))
      },
      onChange(e) {
        console.log('change 事件触发:')
        console.log(beauty(e.detail))
      },
      onToggle(e) {
        console.log('toggle 事件触发,当前状态是否显示:', e.detail.value)
      },
      onClose() {
        console.log('close 事件触发')
      },
      onMaskClick() {
        console.log('maskClick 事件触发')
      },
      onConfirm(e) {
        this.confirmParams = Object.entries(e.detail)
        console.log('confirm 事件触发:')
        console.log(beauty(e.detail))
      },
      onValueChange(e) {
        this.valueChangeCount = this.valueChangeCount + 1
        this.valueChangeParams = Object.entries(e.detail)
        console.log('valueChange 事件触发:')
        console.log(beauty(e.detail))
      }
  }
  })
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 异步加载数据
当数据量太大时,可能难以在最开始就生成完整的级联数据树。这时,你可以配置 async 属性开启异步加载级联数据,在 columnChange 事件时去更新数据,并且在你更新完数据之前,用户点击确认会是无效的。
数据的更新可以使用实例方法 updateData,传入你需要更新的属性。同时因 async 属性,例子有以下表现:
- 分别有两组数据 Fruit 和 Drink,同时只有一组和子数据。
- 切换一级选项后,有对数据进行更新,所以在更新后 cascade-picker 派发 change 事件,此时可以关闭弹层。
- 切换二级选项后,没有对数据进行更新,所以二级选项变化后 change 事件不会触发,此时无法关闭弹层。
- 切换最后一级后,因不涉及到子数据的变化,所以会触发 change 事件,此时可以关闭弹层。
<template>
  <view>
    <cube-button bindclick="showPicker">async-cascade-picker</cube-button>
    <cube-cascade-picker-popup
      wx:ref="asyncPicker"
      title="{{'标题'}}"
      list="{{ dataList }}"
      selectedIndex="{{ selectedIndex }}"
      async="{{ true }}"
      bindchange="onChange"
      bindcolumnChange="onColumnChange"
    />
    <view class="event-params m-t-10"  wx:if="{{ changeParams || introduce }}">
      <view class="key-introduce">{{introduce}}</view>
      <view class="desc-text m-t-10 m-b-10">
        因设置 async 为true,change 事件会在用户更新数据后才相应;例子里第二例滚动时没有更新数据,所以无 change 事件。
      </view>
      <block wx:if="{{ changeParams }}">
        <view class="m-b-10">change 事件参数:</view>
        <view class="value m-b-10">
          <view view class="value-item" wx:for="{{changeParams}}" wx:key="index">
            <view class="item-key">{{item[0]}}</view>
            <view class="item-value">{{item[1]}}</view>
          </view>
        </view>
      </block>
    </view>
  </view>
</template>
<script>
import { createComponent } from '@mpxjs/core'
import { beauty } from '../../common/utils'
const Fruit = [{
  value: 'Fruit',
  text: 'Fruit',
  children: [{
    value: 'Apple',
    text: 'Apple',
    children: [{ value: 1, text: 'One' }, { value: 2, text: 'Two' }]
  }, {
    value: 'Orange',
    text: 'Orange',
    children: [{ value: 3, text: 'Three'}, { value: 4, text: 'Four' }]
  }]
}, {
  value: 'Drink',
  text: 'Drink'
}]
const Drink = [{
  value: 'Fruit',
  text: 'Fruit'
}, {
  value: 'Drink',
  text: 'Drink',
  children: [{
    value: 'Coffee',
    text: 'Coffee',
    children: [{ value: 1, text: 'One' }, { value: 2, text: 'Two' }]
  }, {
    value: 'Tea',
    text: 'Tea',
    children: [{ value: 1, text: 'One' }, { value: 3, text: 'Three'}]
  }]
}]
createComponent({
  data: {
    dataList: Fruit,
    selectedIndex: [0, 1, 1],
    changeParams: '',
    introduce: '',
    load: false
  },
  methods: {
    showPicker() {
      this.$refs.asyncPicker.show()
    },
    onColumnChange(e) {
      this.changeParams = ''
      this.introduce = 'change 事件未触发'
      const { column, index, value } = e.detail
      if (column === 0) {
        this.introduce = '数据更新中...'
        this.load = true
        // 模拟1.5秒后返回数据
        setTimeout(() => {
          this.$refs.asyncPicker.updateData(index === 0 ? Fruit : Drink, [index, 0, 0])
          this.load = false
        }, 1500)
      }
    },
    onChange(e) {
      this.introduce = ''
      this.changeParams = Object.entries(e.detail)
    }
  }
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 
|---|---|---|---|---|
| themeType | 用于生成最外层类名 如原类名为 cube-component,添加 themeType = demo 后,类名变为 cube-component cube-component-demo | String | - | - | 
| visible | 遮盖层初始状态是否可见 | Boolean | - | false | 
| indicatorStyle | 设置选择器中间选中框的样式 | String | - | - | 
| immediateChange | Boolean | - | false | |
| title | 标题 | String | - | - | 
| subtitle | 子标题 | String | - | - | 
| cancelTxt | 顶部取消按钮文案 | String | - | 取消 | 
| confirmTxt | 顶部确定按钮文案 | String | - | 确认 | 
| maskClosable | 是否点击蒙层隐藏 | Boolean | - | true | 
| selectedIndex | 被选中的索引值,拉起 picker 后显示这个索引值对应的内容 | Array | - | number[] | 
| fullyStop | 点击确认时,是否需要滚动选项完全停止 | Boolean | - | false | 
| async | 是否异步加载数据 | Boolean | - | false | 
| list | Array | - | CascadePickerSubTree[] | 
# TsType
| Name | Type | 
|---|---|
| PickerColumn |  | 
| CascadePickerSubTree |  | 
# Events
| 事件名 | 说明 | 参数 | 
|---|---|---|
| toggle | 显示/隐藏时触发 | event.detail = { value }, 表当前状态是显示还是隐藏 | 
| maskClick | 点击遮盖层触发事件 | - | 
| pickstart | 当滚动选择开始时候触发事件 | - | 
| pickend | 当滚动选择结束时候触发事件 | - | 
| columnChange | 列变化事件,某列选中的 value 及 index 任意一个变化后触发事件 | event.detail = { column, index, text, value } column 是发生变化的列;index, text, value 分别是变化后的索引、文案、值 | 
| change | 滚动后触发 | event.detail = { selectedIndex, selectedText, selectedVal } 每个属性都是数组,是当前所有列的选中信息; 分别表示被选中的索引、文案、值 | 
| valueChange | 所确认的值变化时触发此事件 | 同上 | 
| confirm | 点击确认按钮触发此事件 | 同上 | 
| cancel | 点击取消按钮时触发 | - | 
# Slots
| 插槽名 | 说明 | 
|---|---|
| pickerHeader | picker选择器头部位置插槽 | 
# Methods
| 组件实例方法 | 说明 | 参数 | 返回值 | 
|---|---|---|---|
| show | 显示 | - | - | 
| hide | 隐藏 | - | - |