19 changed files with 378 additions and 597 deletions
@ -1,10 +1,12 @@ |
|||||
{ |
{ |
||||
"component": true, |
"component": true, |
||||
"usingComponents": { |
"usingComponents": { |
||||
"wux-popup": "../dist/popup/index", |
"van-cascader": "@vant/weapp/cascader/index", |
||||
"wux-checkbox-group": "../dist/checkbox-group/index", |
"van-popup": "@vant/weapp/popup/index", |
||||
"wux-checkbox": "../dist/checkbox/index", |
"van-field": "@vant/weapp/field/index", |
||||
"wux-calendar": "../dist/calendar/index", |
"van-checkbox": "@vant/weapp/checkbox/index", |
||||
"wux-cascader": "../dist/cascader/index" |
"van-checkbox-group": "@vant/weapp/checkbox-group/index", |
||||
|
"van-calendar": "@vant/weapp/calendar/index", |
||||
|
"van-icon": "@vant/weapp/icon/index" |
||||
} |
} |
||||
} |
} |
@ -1,12 +1,13 @@ |
|||||
{ |
{ |
||||
"component": true, |
"component": true, |
||||
"usingComponents": { |
"usingComponents": { |
||||
"wux-popup": "../dist/popup/index", |
"van-cascader": "@vant/weapp/cascader/index", |
||||
"wux-selectable": "../dist/selectable/index", |
"van-popup": "@vant/weapp/popup/index", |
||||
"wux-textarea": "../dist/textarea/index", |
"van-field": "@vant/weapp/field/index", |
||||
"wux-upload": "../dist/upload/index", |
"van-radio": "@vant/weapp/checkbox/index", |
||||
"wux-cell": "../dist/cell/index", |
"van-radio-group": "@vant/weapp/checkbox-group/index", |
||||
"wux-calendar": "../dist/calendar/index", |
"van-calendar": "@vant/weapp/calendar/index", |
||||
"wux-cascader": "../dist/cascader/index" |
"van-icon": "@vant/weapp/icon/index", |
||||
|
"van-uploader": "@vant/weapp/uploader/index" |
||||
} |
} |
||||
} |
} |
@ -1,320 +0,0 @@ |
|||||
import baseComponent from '../helpers/baseComponent' |
|
||||
import classNames from '../helpers/classNames' |
|
||||
import styleToCssString from '../helpers/styleToCssString' |
|
||||
import arrayTreeFilter from '../helpers/arrayTreeFilter' |
|
||||
|
|
||||
const WUX_CASCADER_VIEW = 'wux-cascader-view' |
|
||||
const defaultFieldNames = { |
|
||||
label: 'label', |
|
||||
value: 'value', |
|
||||
children: 'children', |
|
||||
disabled: 'disabled', |
|
||||
} |
|
||||
|
|
||||
baseComponent({ |
|
||||
externalClasses: ['wux-scroll-view-class'], |
|
||||
properties: { |
|
||||
prefixCls: { |
|
||||
type: String, |
|
||||
value: 'wux-cascader-view', |
|
||||
}, |
|
||||
defaultValue: { |
|
||||
type: Array, |
|
||||
value: [], |
|
||||
}, |
|
||||
value: { |
|
||||
type: Array, |
|
||||
value: [], |
|
||||
}, |
|
||||
controlled: { |
|
||||
type: Boolean, |
|
||||
value: false, |
|
||||
}, |
|
||||
options: { |
|
||||
type: Array, |
|
||||
value: [], |
|
||||
}, |
|
||||
full: { |
|
||||
type: Boolean, |
|
||||
value: false, |
|
||||
}, |
|
||||
placeholder: { |
|
||||
type: String, |
|
||||
value: '请选择', |
|
||||
}, |
|
||||
height: { |
|
||||
type: [String, Number], |
|
||||
value: 'auto', |
|
||||
}, |
|
||||
defaultFieldNames: { |
|
||||
type: Object, |
|
||||
value: defaultFieldNames, |
|
||||
}, |
|
||||
skipAnimation: { |
|
||||
type: Boolean, |
|
||||
value: false, |
|
||||
}, |
|
||||
}, |
|
||||
data: { |
|
||||
activeOptions: [], |
|
||||
activeIndex: 0, |
|
||||
bodyStyle: '', |
|
||||
activeValue: [], |
|
||||
showOptions: [], |
|
||||
fieldNames: undefined, |
|
||||
scrollViewStyle: '', |
|
||||
}, |
|
||||
computed: { |
|
||||
classes: ['prefixCls, full', function(prefixCls, full) { |
|
||||
const wrap = classNames(prefixCls) |
|
||||
const hd = `${prefixCls}__hd` |
|
||||
const bd = `${prefixCls}__bd` |
|
||||
const innerScroll = classNames(`${prefixCls}__inner-scroll`, { |
|
||||
[`${prefixCls}__inner-scroll--full`]: full, |
|
||||
}) |
|
||||
const scrollView = `${prefixCls}__scroll-view` |
|
||||
const ft = `${prefixCls}__ft` |
|
||||
|
|
||||
return { |
|
||||
wrap, |
|
||||
hd, |
|
||||
bd, |
|
||||
innerScroll, |
|
||||
scrollView, |
|
||||
ft, |
|
||||
} |
|
||||
}], |
|
||||
}, |
|
||||
observers: { |
|
||||
value(newVal) { |
|
||||
if (this.data.controlled) { |
|
||||
this.setData({ activeValue: newVal }) |
|
||||
this.getCurrentOptions(newVal) |
|
||||
} |
|
||||
}, |
|
||||
options() { |
|
||||
this.getCurrentOptions(this.data.activeValue) |
|
||||
}, |
|
||||
height(newVal) { |
|
||||
this.updateStyle(newVal) |
|
||||
}, |
|
||||
}, |
|
||||
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 { placeholder } = this.data |
|
||||
const activeOptions = this.getActiveOptions(activeValue) |
|
||||
|
|
||||
if (hasChildren) { |
|
||||
const value = this.getFieldName('value') |
|
||||
const label = this.getFieldName('label') |
|
||||
|
|
||||
activeOptions.push({ |
|
||||
[value]: WUX_CASCADER_VIEW, |
|
||||
[label]: placeholder, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
return activeOptions |
|
||||
}, |
|
||||
getNextActiveValue(value, optionIndex) { |
|
||||
let { activeValue } = this.data |
|
||||
|
|
||||
activeValue = activeValue.slice(0, optionIndex + 1) |
|
||||
activeValue[optionIndex] = value |
|
||||
|
|
||||
return activeValue |
|
||||
}, |
|
||||
updated(currentOptions, optionIndex, condition, callback) { |
|
||||
const value = this.getFieldName('value') |
|
||||
const children = this.getFieldName('children') |
|
||||
const hasChildren = currentOptions && 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 props = { |
|
||||
activeValue, |
|
||||
activeOptions, |
|
||||
activeIndex, |
|
||||
showOptions, |
|
||||
} |
|
||||
|
|
||||
// 判断 hasChildren 计算需要更新的数据
|
|
||||
if (hasChildren || (activeValue.length === showOptions.length && (optionIndex = Math.max(0, optionIndex - 1)))) { |
|
||||
props.bodyStyle = this.getTransform(optionIndex + 1) |
|
||||
props.showOptions = showOptions |
|
||||
} |
|
||||
|
|
||||
// 判断是否需要 setData 更新数据
|
|
||||
if (condition) { |
|
||||
this.setCascaderView(props) |
|
||||
} |
|
||||
|
|
||||
// 回调函数
|
|
||||
if (typeof callback === 'function') { |
|
||||
callback.call(this, currentOptions, activeValue) |
|
||||
} |
|
||||
}, |
|
||||
/** |
|
||||
* 更新级联数据 |
|
||||
* @param {Array} activeValue 当前选中值 |
|
||||
*/ |
|
||||
getCurrentOptions(activeValue = this.data.activeValue) { |
|
||||
const optionIndex = Math.max(0, activeValue.length - 1) |
|
||||
const activeOptions = this.getActiveOptions(activeValue) |
|
||||
const currentOptions = activeOptions[optionIndex] |
|
||||
|
|
||||
if (currentOptions) { |
|
||||
this.updated(currentOptions, optionIndex, true) |
|
||||
} else { |
|
||||
const value = this.getFieldName('value') |
|
||||
const label = this.getFieldName('label') |
|
||||
|
|
||||
activeOptions.push({ |
|
||||
[value]: WUX_CASCADER_VIEW, |
|
||||
[label]: this.data.placeholder, |
|
||||
}) |
|
||||
|
|
||||
const showOptions = this.getShowOptions(activeValue) |
|
||||
const activeIndex = activeOptions.length - 1 |
|
||||
const props = { |
|
||||
showOptions, |
|
||||
activeOptions, |
|
||||
activeIndex, |
|
||||
bodyStyle: '', |
|
||||
} |
|
||||
|
|
||||
this.setCascaderView(props) |
|
||||
} |
|
||||
}, |
|
||||
setCascaderView(props) { |
|
||||
const { activeOptions, ...restProps } = props |
|
||||
this.setData({ activeOptions }, () => { |
|
||||
if (this.data.activeIndex !== restProps.activeIndex) { |
|
||||
this.triggerEvent('tabsChange', { index: restProps.activeIndex }) |
|
||||
} |
|
||||
this.setData(restProps) |
|
||||
}) |
|
||||
}, |
|
||||
getTransform(index, animating = !this.data.skipAnimation) { |
|
||||
const pt = this.data.full ? 2 : 1 |
|
||||
const i = this.data.full ? index : index - 1 |
|
||||
const bodyStyle = styleToCssString({ |
|
||||
transition: animating ? 'transform .3s' : 'none', |
|
||||
transform: `translate(${-50 * pt * Math.max(0, i)}%)`, |
|
||||
}) |
|
||||
return bodyStyle |
|
||||
}, |
|
||||
/** |
|
||||
* 点击菜单时的回调函数 |
|
||||
*/ |
|
||||
onTabsChange(e) { |
|
||||
const activeIndex = parseInt(e.detail.key) |
|
||||
const bodyStyle = this.getTransform(activeIndex) |
|
||||
|
|
||||
if ( |
|
||||
this.data.bodyStyle !== bodyStyle || |
|
||||
this.data.activeIndex !== activeIndex |
|
||||
) { |
|
||||
this.setData({ |
|
||||
bodyStyle, |
|
||||
activeIndex, |
|
||||
}) |
|
||||
|
|
||||
this.triggerEvent('tabsChange', { index: activeIndex }) |
|
||||
} |
|
||||
}, |
|
||||
/** |
|
||||
* 点击选项时的回调函数 |
|
||||
*/ |
|
||||
onItemSelect(e) { |
|
||||
const { optionIndex } = e.currentTarget.dataset |
|
||||
const { index } = e.detail |
|
||||
const { showOptions } = this.data |
|
||||
const item = showOptions[optionIndex][index] |
|
||||
|
|
||||
// updated
|
|
||||
this.updated(item, optionIndex, !this.data.controlled, this.onChange) |
|
||||
}, |
|
||||
/** |
|
||||
* 选择完成时的回调函数 |
|
||||
*/ |
|
||||
onChange(currentOptions = {}, activeValue = []) { |
|
||||
const values = this.getValue(activeValue) |
|
||||
|
|
||||
// 判断是否异步加载
|
|
||||
if (currentOptions && currentOptions.isLeaf === false && !currentOptions.children) { |
|
||||
this.triggerEvent('change', { ...values }) |
|
||||
this.triggerEvent('load', { value: values.value, options: values.options }) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
// 正常加载
|
|
||||
this.triggerEvent('change', { ...values }) |
|
||||
}, |
|
||||
getValue(activeValue = this.data.activeValue) { |
|
||||
const optionIndex = Math.max(0, activeValue.length - 1) |
|
||||
const activeOptions = this.getActiveOptions(activeValue) |
|
||||
const currentOptions = activeOptions[optionIndex] |
|
||||
const valueKeyName = this.getFieldName('value') |
|
||||
const childrenKeyName = this.getFieldName('children') |
|
||||
const hasChildren = currentOptions && currentOptions[childrenKeyName] && currentOptions[childrenKeyName].length > 0 |
|
||||
const options = activeOptions.filter((n) => n[valueKeyName] !== WUX_CASCADER_VIEW) |
|
||||
const value = options.map((n) => n[valueKeyName]) |
|
||||
|
|
||||
if (currentOptions && currentOptions.isLeaf === false && !currentOptions.children) { |
|
||||
return { |
|
||||
value, |
|
||||
options, |
|
||||
done: false, |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return { |
|
||||
value, |
|
||||
options, |
|
||||
done: !hasChildren, |
|
||||
} |
|
||||
}, |
|
||||
getFieldName(name) { |
|
||||
const { defaultFieldNames, fieldNames } = this.data |
|
||||
return typeof fieldNames !== 'undefined' |
|
||||
? fieldNames[name] |
|
||||
: defaultFieldNames[name] |
|
||||
}, |
|
||||
updateStyle(height) { |
|
||||
const scrollViewStyle = styleToCssString({ |
|
||||
height, |
|
||||
minHeight: height, |
|
||||
}) |
|
||||
if (this.data.scrollViewStyle !== scrollViewStyle) { |
|
||||
this.setData({ |
|
||||
scrollViewStyle, |
|
||||
}) |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
attached() { |
|
||||
const { defaultValue, value, controlled, height } = this.data |
|
||||
const activeValue = controlled ? value : defaultValue |
|
||||
const fieldNames = Object.assign({}, defaultFieldNames, this.data.defaultFieldNames) |
|
||||
|
|
||||
this.setData({ activeValue, fieldNames }) |
|
||||
this.getCurrentOptions(activeValue) |
|
||||
this.updateStyle(height) |
|
||||
}, |
|
||||
}) |
|
@ -1,5 +0,0 @@ |
|||||
{ |
|
||||
"component": true, |
|
||||
"usingComponents": { |
|
||||
} |
|
||||
} |
|
Loading…
Reference in new issue