refactor(Area): refactor with composition api

This commit is contained in:
chenjiahan 2020-08-25 19:50:59 +08:00
parent 9301092f20
commit c54025ce83

View File

@ -1,15 +1,20 @@
import { createNamespace } from '../utils'; import { ref, watch, computed, reactive, nextTick, onMounted } from 'vue';
import { createNamespace, pick } from '../utils';
import { pickerProps } from '../picker/shared'; import { pickerProps } from '../picker/shared';
import Picker from '../picker'; import Picker from '../picker';
const [createComponent, bem] = createNamespace('area'); const [createComponent, bem] = createNamespace('area');
const PLACEHOLDER_CODE = '000000'; const EMPTY_CODE = '000000';
function isOverseaCode(code) { function isOverseaCode(code) {
return code[0] === '9'; return code[0] === '9';
} }
function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
export default createComponent({ export default createComponent({
props: { props: {
...pickerProps, ...pickerProps,
@ -34,79 +39,60 @@ export default createComponent({
emits: ['change', 'confirm'], emits: ['change', 'confirm'],
data() { setup(props, { emit, slots }) {
return { const pickerRef = ref(null);
code: this.value,
columns: [{ values: [] }, { values: [] }, { values: [] }],
};
},
computed: { const state = reactive({
province() { code: ref(props.value),
return this.areaList.province_list || {}; columns: reactive([{ values: [] }, { values: [] }, { values: [] }]),
},
city() {
return this.areaList.city_list || {};
},
county() {
return this.areaList.county_list || {};
},
displayColumns() {
return this.columns.slice(0, +this.columnsNum);
},
placeholderMap() {
return {
province: this.columnsPlaceholder[0] || '',
city: this.columnsPlaceholder[1] || '',
county: this.columnsPlaceholder[2] || '',
};
},
pickerSlots() {
return ['title', 'columns-top', 'columns-bottom'].reduce((slots, key) => {
slots[key] = this.$slots[key];
return slots;
}, {});
},
},
watch: {
value(val) {
this.code = val;
this.setValues();
},
areaList: {
deep: true,
handler() {
this.setValues();
},
},
columnsNum() {
this.$nextTick(() => {
this.setValues();
}); });
},
},
mounted() { const areaList = computed(() => {
this.setValues(); const { areaList } = props;
}, return {
province: areaList.province_list || {},
city: areaList.city_list || {},
county: areaList.county_list || {},
};
});
const placeholderMap = computed(() => {
const { columnsPlaceholder } = props;
return {
province: columnsPlaceholder[0] || '',
city: columnsPlaceholder[1] || '',
county: columnsPlaceholder[2] || '',
};
});
const getDefaultCode = () => {
if (props.columnsPlaceholder.length) {
return EMPTY_CODE;
}
const { county, city } = areaList.value;
const countyCodes = Object.keys(county);
if (countyCodes[0]) {
return countyCodes[0];
}
const cityCodes = Object.keys(city);
if (cityCodes[0]) {
return cityCodes[0];
}
return '';
};
methods: {
// get list by code // get list by code
getList(type, code) { const getList = (type, code) => {
let result = []; let result = [];
if (type !== 'province' && !code) { if (type !== 'province' && !code) {
return result; return result;
} }
const list = this[type]; const list = areaList.value[type];
result = Object.keys(list).map((listCode) => ({ result = Object.keys(list).map((listCode) => ({
code: listCode, code: listCode,
name: list[listCode], name: list[listCode],
@ -114,38 +100,37 @@ export default createComponent({
if (code) { if (code) {
// oversea code // oversea code
if (this.isOverseaCode(code) && type === 'city') { if (type === 'city' && props.isOverseaCode(code)) {
code = '9'; code = '9';
} }
result = result.filter((item) => item.code.indexOf(code) === 0); result = result.filter((item) => item.code.indexOf(code) === 0);
} }
if (this.placeholderMap[type] && result.length) { if (placeholderMap.value[type] && result.length) {
// set columns placeholder // set columns placeholder
let codeFill = ''; let codeFill = '';
if (type === 'city') { if (type === 'city') {
codeFill = PLACEHOLDER_CODE.slice(2, 4); codeFill = EMPTY_CODE.slice(2, 4);
} else if (type === 'county') { } else if (type === 'county') {
codeFill = PLACEHOLDER_CODE.slice(4, 6); codeFill = EMPTY_CODE.slice(4, 6);
} }
result.unshift({ result.unshift({
code: `${code}${codeFill}`, code: code + codeFill,
name: this.placeholderMap[type], name: placeholderMap.value[type],
}); });
} }
return result; return result;
}, };
// get index by code // get index by code
getIndex(type, code) { const getIndex = (type, code) => {
let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6; let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
const list = this.getList(type, code.slice(0, compareNum - 2)); const list = getList(type, code.slice(0, compareNum - 2));
// oversea code // oversea code
if (this.isOverseaCode(code) && type === 'province') { if (props.isOverseaCode(code) && type === 'province') {
compareNum = 1; compareNum = 1;
} }
@ -158,68 +143,17 @@ export default createComponent({
} }
return 0; return 0;
}, };
// parse output columns data
parseOutputValues(values) {
return values.map((value, index) => {
// save undefined value
if (!value) return value;
value = JSON.parse(JSON.stringify(value));
if (!value.code || value.name === this.columnsPlaceholder[index]) {
value.code = '';
value.name = '';
}
return value;
});
},
onChange(values, index) {
const { picker } = this.$refs;
this.code = values[index].code;
this.setValues();
const parsedValues = this.parseOutputValues(picker.getValues());
this.$emit('change', parsedValues, index);
},
onConfirm(values, index) {
values = this.parseOutputValues(values);
this.setValues();
this.$emit('confirm', values, index);
},
getDefaultCode() {
if (this.columnsPlaceholder.length) {
return PLACEHOLDER_CODE;
}
const countyCodes = Object.keys(this.county);
if (countyCodes[0]) {
return countyCodes[0];
}
const cityCodes = Object.keys(this.city);
if (cityCodes[0]) {
return cityCodes[0];
}
return '';
},
setValues() {
let { code } = this;
const setValues = () => {
let { code } = state;
if (!code) { if (!code) {
code = this.getDefaultCode(); code = getDefaultCode();
} }
const { picker } = this.$refs; const picker = pickerRef.value;
const province = this.getList('province'); const province = getList('province');
const city = this.getList('city', code.slice(0, 2)); const city = getList('city', code.slice(0, 2));
if (!picker) { if (!picker) {
return; return;
@ -231,30 +165,45 @@ export default createComponent({
if ( if (
city.length && city.length &&
code.slice(2, 4) === '00' && code.slice(2, 4) === '00' &&
!this.isOverseaCode(code) !props.isOverseaCode(code)
) { ) {
[{ code }] = city; [{ code }] = city;
} }
picker.setColumnValues(2, this.getList('county', code.slice(0, 4))); picker.setColumnValues(2, getList('county', code.slice(0, 4)));
picker.setIndexes([ picker.setIndexes([
this.getIndex('province', code), getIndex('province', code),
this.getIndex('city', code), getIndex('city', code),
this.getIndex('county', code), getIndex('county', code),
]); ]);
}, };
getValues() { // parse output columns data
const { picker } = this.$refs; const parseValues = (values) => {
let getValues = picker return values.map((value, index) => {
? picker.getValues().filter((value) => !!value) if (value) {
: []; value = clone(value);
getValues = this.parseOutputValues(getValues);
return getValues;
},
getArea() { if (!value.code || value.name === props.columnsPlaceholder[index]) {
const values = this.getValues(); value.code = '';
value.name = '';
}
}
return value;
});
};
const getValues = () => {
if (pickerRef.value) {
const values = pickerRef.value.getValues().filter((value) => !!value);
return parseValues(values);
}
return [];
};
const getArea = () => {
const values = getValues();
const area = { const area = {
code: '', code: '',
country: '', country: '',
@ -274,7 +223,7 @@ export default createComponent({
? validValues[validValues.length - 1].code ? validValues[validValues.length - 1].code
: ''; : '';
if (this.isOverseaCode(area.code)) { if (props.isOverseaCode(area.code)) {
area.country = names[1] || ''; area.country = names[1] || '';
area.province = names[2] || ''; area.province = names[2] || '';
} else { } else {
@ -284,33 +233,73 @@ export default createComponent({
} }
return area; return area;
}, };
const reset = (newCode = '') => {
state.code = newCode;
setValues();
};
const onChange = (values, index) => {
state.code = values[index].code;
setValues();
const parsedValues = parseValues(pickerRef.value.getValues());
emit('change', parsedValues, index);
};
const onConfirm = (values, index) => {
values = parseValues(values);
setValues();
emit('confirm', values, index);
};
onMounted(setValues);
watch(
() => props.value,
(value) => {
state.code = value;
setValues();
}
);
watch(() => props.areaList, setValues, { deep: true });
watch(
() => props.columnsNum,
() => {
nextTick(setValues);
}
);
return (vm) => {
// @exposed-api // @exposed-api
reset(code) { vm.reset = reset;
this.code = code || ''; vm.getArea = getArea;
this.setValues();
}, const columns = state.columns.slice(0, +props.columnsNum);
},
render() {
return ( return (
<Picker <Picker
v-slots={this.pickerSlots} v-slots={pick(slots, ['title', 'columns-top', 'columns-bottom'])}
ref="picker" ref={pickerRef}
class={bem()} class={bem()}
columns={columns}
valueKey="name" valueKey="name"
title={this.title} onChange={onChange}
loading={this.loading} onConfirm={onConfirm}
columns={this.displayColumns} {...pick(props, [
itemHeight={this.itemHeight} 'title',
swipeDuration={this.swipeDuration} 'loading',
visibleItemCount={this.visibleItemCount} 'itemHeight',
cancelButtonText={this.cancelButtonText} 'swipeDuration',
confirmButtonText={this.confirmButtonText} 'visibleItemCount',
onChange={this.onChange} 'cancelButtonText',
onConfirm={this.onConfirm} 'confirmButtonText',
])}
/> />
); );
};
}, },
}); });