import baseComponent from '../helpers/baseComponent' import classNames from '../helpers/classNames' import arrayTreeFilter from '../helpers/arrayTreeFilter' const WUX_CASCADER = 'wux-cascader' const defaultFieldNames = { label: 'label', value: 'value', children: 'children', } baseComponent({ externalClasses: ['wux-scroll-view-class'], properties: { prefixCls: { type: String, value: 'wux-cascader', }, value: { type: Array, value: [] }, title: { type: String, value: '', }, options: { type: Array, value: [] }, chooseTitle: { type: String, value: '请选择', }, visible: { type: Boolean, value: false, }, defaultFieldNames: { type: Object, value: defaultFieldNames, }, }, data: { activeOptions: [], activeIndex: 0, bodyStyle: '', activeValue: [], intoValue: ['ViewId_00000', 'ViewId_00000', 'ViewId_00000'], // 新增的用于scroll-view的指示修改 showOptions: [], fieldNames: {} }, computed: { classes: ['prefixCls', function(prefixCls) { const wrap = classNames(prefixCls) const hd = `${prefixCls}__hd` const title = `${prefixCls}__title` const menus = `${prefixCls}__menus` const menu = `${prefixCls}__menu` const bd = `${prefixCls}__bd` const inner = `${prefixCls}__inner` const scrollView = `${prefixCls}__scroll-view` const option = `${prefixCls}__option` const item = `${prefixCls}__item` const icon = `${prefixCls}__icon` const ft = `${prefixCls}__ft` return { wrap, hd, title, menus, menu, bd, inner, scrollView, option, item, icon, ft, } }], }, observers: { options() { this.getCurrentOptions(this.data.activeValue, false) } }, methods: { getActiveOptions(activeValue) { const { options } = this.data const value = this.getFieldName('value') const childrenKeyName = this.getFieldName('children') return arrayTreeFilter(options, (option, level) => option[value] === activeValue[level], { childrenKeyName }) }, getShowOptions(activeValue) { const { options } = this.data const children = this.getFieldName('children') const result = this.getActiveOptions(activeValue).map((activeOption) => activeOption[children]).filter((activeOption) => !!activeOption) return [options, ...result] }, getMenus(activeValue = [], hasChildren) { const { options, chooseTitle } = this.data const activeOptions = this.getActiveOptions(activeValue) if (hasChildren) { const value = this.getFieldName('value') const label = this.getFieldName('label') activeOptions.push({ [value]: WUX_CASCADER, [label]: chooseTitle }) } return activeOptions }, getNextActiveValue(value, optionIndex) { let { activeValue } = this.data activeValue = activeValue.slice(0, optionIndex + 1) activeValue[optionIndex] = value return activeValue }, updated: function(currentOptions, optionIndex, condition, callback, flag) { const value = this.getFieldName('value') const children = this.getFieldName('children') const hasChildren = currentOptions[children] && currentOptions[children].length > 0 const activeValue = this.getNextActiveValue(currentOptions[value], optionIndex) const activeOptions = this.getMenus(activeValue, hasChildren) const activeIndex = activeOptions.length - 1 const showOptions = this.getShowOptions(activeValue) const params = { activeValue, activeOptions, activeIndex, showOptions } // 判断 hasChildren 计算需要更新的数据 if (hasChildren || (activeValue.length === showOptions.length && (optionIndex = Math.max(0, optionIndex - 1)))) { params.bodyStyle = `transform: translate(${-50 * optionIndex}%)` params.showOptions = showOptions } // 判断是否需要 setData 更新数据 if (condition) { if(flag){ this.triggerEvent('init', activeOptions) } this.setData(params) } // 回调函数 if (typeof callback === 'function') { callback.call(this, currentOptions, activeOptions, !hasChildren) } }, /** * 更新级联数据 * @param {Array} activeValue 当前选中值 */ getCurrentOptions(activeValue = this.data.activeValue, flag) { const optionIndex = Math.max(0, activeValue.length - 1) const activeOptions = this.getActiveOptions(activeValue) const currentOptions = activeOptions[optionIndex] if (currentOptions) { this.updated(currentOptions, optionIndex, true, null, flag) } else { const value = this.getFieldName('value') const label = this.getFieldName('label') activeOptions.push({ [value]: WUX_CASCADER, [label]: this.data.chooseTitle }) const showOptions = this.getShowOptions(activeValue) const activeIndex = activeOptions.length - 1 const params = { showOptions, activeOptions, activeIndex, bodyStyle: ''} this.setData(params) } }, /** * 点击菜单时的回调函数 */ onMenuClick(e) { const { menuIndex } = e.currentTarget.dataset const index = menuIndex > 1 ? menuIndex - 1 : 0 const bodyStyle = `transform: translate(${-50 * index}%)` this.setData({ bodyStyle, activeIndex: menuIndex}) }, /** * 点击选项时的回调函数 */ onItemSelect(e) { const { item, optionIndex } = e.currentTarget.dataset // 判断是否禁用 if (!item || item.disabled) return this.setData({ intoValue: ['ViewId_00000', 'ViewId_00000', 'ViewId_00000']}) // 更新新数据 this.updated(item, optionIndex, true, this.onChange, false) const activeLength = this.data.activeValue.length // 更新intoValue的下一级数据,选择项的下一级列表scroll-top if(activeLength < this.data.intoValue.length && activeLength < this.data.showOptions.length){ if(this.data.showOptions[activeLength][0]){ this.setData({ ['intoValue[' + activeLength + ']']: 'ViewId_' + this.data.showOptions[activeLength][0].value }) } } }, /** * 组件关闭时的回调函数 */ onPopupClose(val) { this.setData({ visible: false }) this.triggerEvent('close', val) }, onPopupShow(){ let { intoValue } = this.data for (let i = 0; i < this.data.activeValue.length; i++) { intoValue[i] = 'ViewId_' + this.data.activeValue[i] } this.setData({ intoValue }) }, /** * 选择完成时的回调函数 */ onChange(currentOptions = {}, activeOptions = [], done = false) { const options = activeOptions.filter((n) => n[this.getFieldName('value')] !== WUX_CASCADER) const value = options.map((n) => n[this.getFieldName('value')]) // 判断是否异步加载 if (currentOptions.isLeaf === false && !currentOptions.children) { this.emitEvent({ value, options, done: false }) this.triggerEvent('load', { value, options }) return } // 正常加载 this.emitEvent({ value, options, done }) }, emitEvent(params = {}) { this.triggerEvent('change', params) // 当选择完成时关闭组件 if (params.done) { this.setData({ value: params.value }) this.onPopupClose(params) } }, getFieldName(name) { return this.data.fieldNames[name] }, showPicker(region){ this.setData({ activeValue: region, visible: true }) this.getCurrentOptions(region, false) } }, attached() { const { value } = this.data var activeValue = value if (!activeValue || activeValue.length == 0){ activeValue = ["440000", "", ""] } const fieldNames = Object.assign({}, defaultFieldNames, this.data.defaultFieldNames) this.setData({ activeValue, fieldNames }, () => this.getCurrentOptions(activeValue, false)) } })