ionic4 多级联动选择器

一、创建service

ionic g service services/picker/picker

二、picker.service.ts内容

import {Injectable} from '@angular/core';
import {PickerController} from '@ionic/angular';
import {PickerColumn} from '@ionic/core';

@Injectable({
    providedIn: 'root'
})
export class PickerService {
    // 存所有数据,格式
    // 0: (2) ["00", "01"]
    // 1: (2) ["10", "11"]
    // 10: (3) ["100", "101", "102"]
    // 11: (3) ["110", "111", "112"]
    // "": (2) ["0", "1"]
    // 00: (3) ["000", "001", "002"]
    // 01: (3) ["010", "011", "012"]
    private options = [];
    // 改变滑动时,当前的数据,格式
    // [
    // ['0','1'],
    // ["00", "01"]
    // ["000", "001", "002"]
    // ]
    private currentOptions = [];
    // 选中的坐标
    private selects = [];
    // 改变滑动时,选中的坐标
    private currentSelects = [];

    constructor(public pickercontroller: PickerController) {
    }

    async openPicker(numColumns = 1, numOptions = 5, multiColumnOptions, callback) {
        if (this.options.length === 0) {
            this.options = multiColumnOptions;

            this.currentOptions[0] = multiColumnOptions[''];
            this.currentSelects[0] = 0;
            for (let pos = 1; pos < numColumns; pos++) {
                this.currentOptions[pos] = this.options[this.currentOptions[pos - 1][this.currentSelects[pos - 1]]];
                this.currentSelects[pos] = 0;
            }
        }

        const picker: HTMLIonPickerElement = await this.pickercontroller.create({
            columns: this.getColumns(numColumns, this.currentOptions),
            buttons: [
                {
                    text: '取消',
                    role: 'cancel'
                },
                {
                    text: '确定',
                    handler: value => {
                        // console.log(`Got Value ${value}`);
                        // tslint:disable-next-line:forin
                        for (const val in value) {
                            this.selects[val] = value[val].value;
                        }
                        callback(JSON.stringify(value));
                    }
                }
            ]
        });

        picker.addEventListener('ionPickerColChange', async (event: any) => {
            const data = event.detail;

            // tslint:disable-next-line:radix
            const currentColumnNum = parseInt(data.name);
            this.currentSelects[data.name] = data.selectedIndex;

            let pickerColumns: PickerColumn[] = [];
            pickerColumns = picker.columns;
            if (currentColumnNum < numColumns - 1) {
                for (let columnPos = 0; columnPos < numColumns; columnPos++) {
                    if (columnPos > currentColumnNum) {
                        this.currentOptions[columnPos] = this.options[this.currentOptions[columnPos - 1][this.currentSelects[columnPos - 1]]];
                        this.currentSelects[columnPos] = 0;

                        pickerColumns[columnPos] = {
                            name: `${columnPos}`,
                            options: this.getColumnOptions(0, this.currentOptions[columnPos].length, [this.currentOptions[columnPos]]),
                            selectedIndex: columnPos > currentColumnNum ? 0 : picker.columns[columnPos].selectedIndex,
                        };
                    }
                }
                picker.columns = pickerColumns;
                picker.forceUpdate();
            }
        });

        await picker.present();
    }

    getColumns(numColumns, columnOptions) {
        const columns = [];
        for (let i = 0; i < numColumns; i++) {
            columns.push({
                name: `${i}`,
                options: this.getColumnOptions(i, columnOptions[i].length, columnOptions),
                selectedIndex: this.selects[i] ? this.selects[i] : 0
            });
        }
        return columns;
    }

    getColumnOptions(columnIndex, numOptions, columnOptions) {
        const options = [];
        for (let i = 0; i < numOptions; i++) {
            options.push({
                text: columnOptions[columnIndex][i % numOptions],
                value: i,
            });
        }
        return options;
    }
}

三、使用方法

1.使用页面的html

  <ion-row no-padding (click)="change()">
    <ion-col size="auto" align-items-center>选择的数据结果<label>*</label></ion-col>
    <ion-col align-self-center text-right>{{selectData}}</ion-col>
  </ion-row>

2.使用页面的ts

  // 数据集合
  datas = {};
  // 选中的内容
  selectData = '';
  // 列数
  numColumns = 3;

  constructor(
      public pickerService: PickerService,
  ) {

  }

  change() {
    // 三列测试数据
    this.datas[''] = ['0', '1'];
    this.datas['0'] = ['00'];
    this.datas['1'] = ['10', '11'];
    this.datas['00'] = ['000', '001', '002'];
    this.datas['10'] = ['100', '101', '102'];
    this.datas['11'] = ['110', '111', '112'];


    // 四列测试数据
    // this.datas[''] = ['0', '1'];
    // this.datas['0'] = ['00'];
    // this.datas['1'] = ['10', '11'];
    // this.datas['00'] = ['000', '001'];
    // this.datas['10'] = ['100', '101'];
    // this.datas['11'] = ['110', '111', '112'];
    // this.datas['000'] = ['0000'];
    // this.datas['001'] = ['0010'];
    // this.datas['100'] = ['1000'];
    // this.datas['101'] = ['1010'];
    // this.datas['110'] = ['1100'];
    // this.datas['111'] = ['1110'];
    // this.datas['112'] = ['1120'];

    this.pickerService.openPicker(this.numColumns, this.datas[0].length, this.datas, result => {
          this.selectData = '';
          for (let pos = 0; pos < this.numColumns; pos++) {
            this.selectData = this.selectData + JSON.parse(result)[pos].text + ',';
          }
        }
    );
  }

四、解决选择选项时重叠问题

修改/node_modules/@ionic/core/dist/esm/ion-datetime_3-ios.entry.js、/node_modules/@ionic/core/dist/esm/ion-datetime_3-md.entry.js文件。
注意:@ionic/core会影响到修改内容。可参考https://github.com/zwlccc/ionic4-city-picker
update(y, duration, saveY) {
      if (!this.optsEl) {
          return;
      }
      // ensure we've got a good round number :)
      let translateY = 0;
      let translateZ = 0;
      const { col, rotateFactor } = this;
      const selectedIndex = col.selectedIndex = this.indexForY(-y);
      const durationStr = (duration === 0) ? '' : duration + 'ms';
      const scaleStr = `scale(${this.scaleFactor})`;
      const children = this.optsEl.children;
      const children_length = this.optsEl.children.length;
      const options_length = col.options.length;
      const length = children_length < options_length ? options_length : children_length;
      for (let i = 0; i < length; i++) {
          const button = children[i];
          const opt = col.options[i];
          const optOffset = (i * this.optHeight) + y;
          let transform = '';
          if (rotateFactor !== 0) {
              const rotateX = optOffset * rotateFactor;
              if (Math.abs(rotateX) <= 90) {
                  translateY = 0;
                  translateZ = 90;
                  transform = `rotateX(${rotateX}deg) `;
              }
              else {
                  translateY = -9999;
              }
          }
          else {
              translateZ = 0;
              translateY = optOffset;
          }
          const selected = selectedIndex === i;
          transform += `translate3d(0px,${translateY}px,${translateZ}px) `;
          if (this.scaleFactor !== 1 && !selected) {
              transform += scaleStr;
          }
          // Update transition duration
          if (this.noAnimate) {
              if (opt) {
                  opt.duration = 0;
              }
              if (button) {
                  button.style.transitionDuration = '';
              }
          }
          else if (opt) {
              if (duration !== opt.duration) {
                  opt.duration = duration;
                  if (button) {
                      button.style.transitionDuration = durationStr;
                  }
              }
          }
          // Update transform
          if (opt) {
              if (transform !== opt.transform) {
                  opt.transform = transform;
                  if (button) {
                      button.style.transform = transform;
                  }
              }
          }
          // Update selected item
          if (opt) {
              if (selected !== opt.selected) {
                  opt.selected = selected;
                  if (selected && button) {
                      button.classList.add(PICKER_OPT_SELECTED);
                  }
                  else if (button) {
                      button.classList.remove(PICKER_OPT_SELECTED);
                  }
              }
          }
      }
      this.col.prevSelected = selectedIndex;
      if (saveY) {
          this.y = y;
      }
      if (this.lastIndex !== selectedIndex) {
          // have not set a last index yet
          hapticSelectionChanged();
          this.lastIndex = selectedIndex;
      }
}
render() {
      const col = this.col;
      const Button = 'button';
      const mode = getIonMode(this);
      return (h(Host, { class: {
              [mode]: true,
              'picker-col': true,
              'picker-opts-left': this.col.align === 'left',
              'picker-opts-right': this.col.align === 'right'
          }, style: {
              'max-width': this.col.columnWidth
          } }, col.prefix && (h("div", { class: "picker-prefix", style: { width: col.prefixWidth } }, col.prefix)), h("div", { class: "picker-opts", style: { maxWidth: col.optionsWidth }, ref: el => this.optsEl = el }, col.options.map((o, index) => h(Button, { type: "button", class: { 'picker-opt': true, 'picker-opt-disabled': !!o.disabled, 'picker-opt-selected': o.selected }, style: { transform: o.transform ? o.transform : 'translate3d(0px, -9999px, 90px)', 'transition-duration': o.duration ? o.duration : TRANSITION_DURATION + 'ms' }, "opt-index": index }, o.text))), col.suffix && (h("div", { class: "picker-suffix", style: { width: col.suffixWidth } }, col.suffix))));
  }

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值