import type { Area } from '../../../../utils/area' Component({ //@ts-ignore codeList: [], options: { multipleSlots: true, }, properties: { show: { type: Boolean, observer(show) { if (!show) return this.setData({ pickerValue: [] }, () => { this.codeList = this.splitCode(this.data.value) this.updateDivisions() }) }, }, title: { type: String, value: '选择地区', }, value: { type: String, value: '', }, areaData: { type: Array, value: [], observer() { if (!this.data.show) return this.updateDivisions() }, }, columns: { type: Number, value: 3, }, columnsName: { type: Array, value: ['省市/地区', '城市', '区'], }, useLoadingSlot: Boolean, }, data: { pickerValue: [] as Area[], pickerColumnData: [] as Area[], hightLightIndex: [] as number[], loading: false, scrollTop: 0, }, methods: { splitCode(value: string) { const codeList = [] for (let i = 1; i <= this.data.columns; i++) { let code = value.slice(0, i * 2) if (code.length < i * 2) { code = `${value.slice(0, (i - 1) * 2)}00` } while (code.length < this.data.value.length) { code += '0' } codeList.push(code) } return codeList }, updateDivisions() { const { pickerValue } = this.data const area = pickerValue[pickerValue.length - 1] let currentAreaData = [] if (pickerValue.length === 0) { currentAreaData = this.data.areaData } else { if (area && area.children && area.children.length > 0) { currentAreaData = [...area.children] } else if (area && !area.children) { const newArea = this.getNewAreaByPickerValue(pickerValue).area if (newArea && newArea.children) { area.children = newArea.children currentAreaData = [...(area.children || [])] } } } if (currentAreaData.length > 0) { const pickerColumnData = currentAreaData[0].code ? [{ name: '', children: currentAreaData }] : currentAreaData let oldPickedIndexes = [-1, -1] if (this.codeList.length > pickerValue.length) { for (const gi in pickerColumnData) { for (const ai in pickerColumnData[gi].children) { //@ts-ignore if (pickerColumnData[gi].children[ai].code === this.codeList[pickerValue.length]) { oldPickedIndexes = [+gi, +ai] break } } if (oldPickedIndexes[0] > -1) break } } this.setData({ loading: false, pickerColumnData }, () => { return new Promise((resolve) => { if (oldPickedIndexes[0] > -1) { this.createSelectorQuery() .select('#area-item-0-0') .boundingClientRect() .select(`#area-item-${oldPickedIndexes.join('-')}`) .boundingClientRect() .exec((res) => { if (res[0] && res[1]) { const offsetTop = res[1].top - res[0].top const diff = res[1].height resolve(offsetTop > diff ? offsetTop - diff : 0) } else { resolve(0) } }) } else resolve(0) }).then((scrollTop) => { this.setData({ hightLightIndex: oldPickedIndexes, scrollTop, }) }) }) } else { this.setData({ loading: true, pickerColumnData: [] }, () => { if (area && area.code) { this.triggerEvent('pullchildren', { parentCode: area.code }) } else { this.triggerEvent('pullchildren', {}) } }) } }, getNewAreaByPickerValue(pickerValue: Area[]) { let { areaData } = this.data as any const areas = [] for (const pickedArea of pickerValue) { const _areaData = areaData.length > 0 && areaData[0].code ? [{ name: '', children: areaData }] : areaData let newArea for (const gi in _areaData) { for (const ai in _areaData[gi].children) { if (_areaData[gi].children[ai].code === pickedArea.code) { newArea = _areaData[gi].children[ai] break } } if (newArea) break } if (!newArea) break areaData = newArea.children || [] areas.push(newArea) } return { area: areas[areas.length - 1], areas } }, onChange(e: WechatMiniprogram.CustomEvent<{}, {}, { gi: number; ai: number }>) { const { gi, ai } = e.currentTarget.dataset const area = this.data.pickerColumnData[gi].children![ai] const pickerValue = this.data.pickerValue.concat(area) if (pickerValue.length < this.data.columns) { this.setData({ pickerValue }, () => { this.updateDivisions() }) this.triggerEvent('change', { value: area.code, areas: pickerValue }) } else { this.setData({ show: false }) this.triggerEvent('confirm', { value: area.code, areas: pickerValue }) } }, onPickerClick(e: WechatMiniprogram.CustomEvent<{}, {}, { index: number }>) { const { index } = e.currentTarget.dataset if (index > this.data.pickerValue.length - 1) return const pickerValue = this.data.pickerValue.slice(0, index) this.setData({ pickerValue }, () => { this.updateDivisions() }) this.triggerEvent('change', { value: pickerValue[pickerValue.length - 1]?.code, areas: pickerValue, }) }, onClose() { this.setData({ show: false }) this.triggerEvent('close') }, }, })