diff --git a/src/area/README.md b/src/area/README.md index b8432f855..926097abe 100644 --- a/src/area/README.md +++ b/src/area/README.md @@ -92,9 +92,9 @@ To have a selected value,simply pass the `code` of target area to `value` prop Use [ref](https://v3.vuejs.org/guide/component-template-refs.html) to get Area instance and call instance methods. -| Name | Description | Attribute | Return value | -| ----- | ------------------------- | ------------- | ------------ | -| reset | Reset all options by code | code?: string | - | +| Name | Description | Attribute | Return value | +| ----- | ------------------------- | --------------- | ------------ | +| reset | Reset all options by code | _code?: string_ | - | ### areaList Data Structure diff --git a/src/area/README.zh-CN.md b/src/area/README.zh-CN.md index 71630e354..98ce5d20b 100644 --- a/src/area/README.zh-CN.md +++ b/src/area/README.zh-CN.md @@ -94,7 +94,7 @@ app.use(Area); | 方法名 | 说明 | 参数 | 返回值 | | --- | --- | --- | --- | -| reset | 根据 code 重置所有选项,若不传 code,则重置到第一项 | code?: string | - | +| reset | 根据 code 重置所有选项,若不传 code,则重置到第一项 | _code?: string_ | - | ### 省市区列表数据格式 diff --git a/src/area/index.js b/src/area/index.tsx similarity index 75% rename from src/area/index.js rename to src/area/index.tsx index 1777435ab..3a5761075 100644 --- a/src/area/index.js +++ b/src/area/index.tsx @@ -1,27 +1,48 @@ -import { ref, watch, computed, reactive, nextTick, onMounted } from 'vue'; +/* eslint-disable camelcase */ +import { + ref, + watch, + computed, + reactive, + nextTick, + PropType, + onMounted, + ComponentPublicInstance, +} from 'vue'; + +// Utils +import { deepClone } from '../utils/deep-clone'; import { createNamespace, pick } from '../utils'; + +// Composition import { useExpose } from '../composables/use-expose'; + +// Components +import Picker, { PickerObjectOption } from '../picker'; import { pickerProps } from '../picker/shared'; -import Picker from '../picker'; const [createComponent, bem] = createNamespace('area'); const EMPTY_CODE = '000000'; -function isOverseaCode(code) { +function isOverseaCode(code: string) { return code[0] === '9'; } -function clone(obj) { - return JSON.parse(JSON.stringify(obj)); -} +export type AreaList = { + city_list: Record; + county_list: Record; + province_list: Record; +}; + +type ColumnType = 'province' | 'county' | 'city'; export default createComponent({ props: { ...pickerProps, value: String, areaList: { - type: Object, + type: Object as PropType, default: () => ({}), }, columnsNum: { @@ -29,11 +50,11 @@ export default createComponent({ default: 3, }, isOverseaCode: { - type: Function, + type: Function as PropType<(code: string) => boolean>, default: isOverseaCode, }, columnsPlaceholder: { - type: Array, + type: Array as PropType, default: () => [], }, }, @@ -41,7 +62,8 @@ export default createComponent({ emits: ['change', 'confirm'], setup(props, { emit, slots }) { - const pickerRef = ref(); + // eslint-disable-next-line + const pickerRef = ref>(); const state = reactive({ code: props.value, @@ -86,15 +108,14 @@ export default createComponent({ return ''; }; - // get list by code - const getList = (type, code) => { - let result = []; + const getColumnValues = (type: ColumnType, code?: string) => { + let column: PickerObjectOption[] = []; if (type !== 'province' && !code) { - return result; + return column; } const list = areaList.value[type]; - result = Object.keys(list).map((listCode) => ({ + column = Object.keys(list).map((listCode) => ({ code: listCode, name: list[listCode], })); @@ -104,10 +125,10 @@ export default createComponent({ if (type === 'city' && props.isOverseaCode(code)) { code = '9'; } - result = result.filter((item) => item.code.indexOf(code) === 0); + column = column.filter((item) => item.code.indexOf(code!) === 0); } - if (placeholderMap.value[type] && result.length) { + if (placeholderMap.value[type] && column.length) { // set columns placeholder let codeFill = ''; if (type === 'city') { @@ -116,17 +137,17 @@ export default createComponent({ codeFill = EMPTY_CODE.slice(4, 6); } - result.unshift({ + column.unshift({ code: code + codeFill, name: placeholderMap.value[type], }); } - return result; + return column; }; // get index by code - const getIndex = (type, code) => { + const getIndex = (type: ColumnType, code: string) => { let compareNum = code.length; if (type === 'province') { compareNum = props.isOverseaCode(code) ? 1 : 2; @@ -137,7 +158,7 @@ export default createComponent({ code = code.slice(0, compareNum); - const list = getList( + const list = getColumnValues( type, compareNum > 2 ? code.slice(0, compareNum - 2) : '' ); @@ -152,14 +173,10 @@ export default createComponent({ }; const setValues = () => { - let { code } = state; - if (!code) { - code = getDefaultCode(); - } - + let code = state.code || getDefaultCode(); const picker = pickerRef.value; - const province = getList('province'); - const city = getList('city', code.slice(0, 2)); + const province = getColumnValues('province'); + const city = getColumnValues('city', code.slice(0, 2)); if (!picker) { return; @@ -176,7 +193,7 @@ export default createComponent({ [{ code }] = city; } - picker.setColumnValues(2, getList('county', code.slice(0, 4))); + picker.setColumnValues(2, getColumnValues('county', code.slice(0, 4))); picker.setIndexes([ getIndex('province', code), getIndex('city', code), @@ -185,10 +202,10 @@ export default createComponent({ }; // parse output columns data - const parseValues = (values) => { + const parseValues = (values: PickerObjectOption[]) => { return values.map((value, index) => { if (value) { - value = clone(value); + value = deepClone(value); if (!value.code || value.name === props.columnsPlaceholder[index]) { value.code = ''; @@ -202,7 +219,9 @@ export default createComponent({ const getValues = () => { if (pickerRef.value) { - const values = pickerRef.value.getValues().filter((value) => !!value); + const values = pickerRef.value + .getValues() + .filter((value: PickerObjectOption) => !!value); return parseValues(values); } return []; @@ -246,15 +265,15 @@ export default createComponent({ setValues(); }; - const onChange = (values, index) => { + const onChange = (values: PickerObjectOption[], index: number) => { state.code = values[index].code; setValues(); - const parsedValues = parseValues(pickerRef.value.getValues()); + const parsedValues = parseValues(pickerRef.value!.getValues()); emit('change', parsedValues, index); }; - const onConfirm = (values, index) => { + const onConfirm = (values: PickerObjectOption[], index: number) => { setValues(); emit('confirm', parseValues(values), index); }; diff --git a/src/picker/PickerColumn.tsx b/src/picker/PickerColumn.tsx index 3068f45e2..3612d8a6d 100644 --- a/src/picker/PickerColumn.tsx +++ b/src/picker/PickerColumn.tsx @@ -29,14 +29,14 @@ function getElementTranslateY(element: Element) { return Number(translateY); } -export type PickerOption = - | string - | { - text: string; - disabled?: boolean; - // for custom filed names - [key: string]: any; - }; +export type PickerObjectOption = { + text?: string; + disabled?: boolean; + // for custom filed names + [key: string]: any; +}; + +export type PickerOption = string | PickerObjectOption; export type PickerObjectColumn = { values?: PickerOption[]; diff --git a/src/picker/index.tsx b/src/picker/index.tsx index ded83c6cf..109ca64f0 100644 --- a/src/picker/index.tsx +++ b/src/picker/index.tsx @@ -12,9 +12,10 @@ import { useExpose } from '../composables/use-expose'; // Components import Loading from '../loading'; import Column, { - PickerOption, PickerColumn, + PickerOption, PickerObjectColumn, + PickerObjectOption, } from './PickerColumn'; const [createComponent, bem, t] = createNamespace('picker'); @@ -27,6 +28,13 @@ export type PickerFieldNames = { children?: string; }; +export type { + PickerColumn, + PickerOption, + PickerObjectColumn, + PickerObjectOption, +}; + export default createComponent({ props: { ...pickerProps, diff --git a/src/vue-tsx-shim.d.ts b/src/vue-tsx-shim.d.ts index a9268530a..bd0e93017 100644 --- a/src/vue-tsx-shim.d.ts +++ b/src/vue-tsx-shim.d.ts @@ -2,18 +2,22 @@ import 'vue'; type EventHandler = (...args: any[]) => void; -// TODO -// should be removed after Vue supported component events typing -// see: https://github.com/vuejs/vue-next/issues/1553 -// https://github.com/vuejs/vue-next/issues/3029 declare module 'vue' { interface ComponentCustomProps { role?: string; tabindex?: number; + // should be removed after Vue supported component events typing + // see: https://github.com/vuejs/vue-next/issues/1553 + // https://github.com/vuejs/vue-next/issues/3029 + onBlur?: EventHandler; + onFocus?: EventHandler; + onInput?: EventHandler; onClick?: EventHandler; + onCancel?: EventHandler; onClosed?: EventHandler; onChange?: EventHandler; onToggle?: EventHandler; + onConfirm?: EventHandler; onClickStep?: EventHandler; } }