index.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import { VantComponent } from '../common/component';
  2. import { pickerProps } from '../picker/shared';
  3. import { requestAnimationFrame } from '../common/utils';
  4. const EMPTY_CODE = '000000';
  5. VantComponent({
  6. classes: ['active-class', 'toolbar-class', 'column-class'],
  7. props: Object.assign(Object.assign({}, pickerProps), {
  8. value: {
  9. type: String,
  10. observer(value) {
  11. this.code = value;
  12. this.setValues();
  13. },
  14. },
  15. areaList: {
  16. type: Object,
  17. value: {},
  18. observer: 'setValues',
  19. },
  20. columnsNum: {
  21. type: null,
  22. value: 3,
  23. },
  24. columnsPlaceholder: {
  25. type: Array,
  26. observer(val) {
  27. this.setData({
  28. typeToColumnsPlaceholder: {
  29. province: val[0] || '',
  30. city: val[1] || '',
  31. county: val[2] || '',
  32. },
  33. });
  34. },
  35. },
  36. }),
  37. data: {
  38. columns: [{ values: [] }, { values: [] }, { values: [] }],
  39. typeToColumnsPlaceholder: {},
  40. },
  41. mounted() {
  42. requestAnimationFrame(() => {
  43. this.setValues();
  44. });
  45. },
  46. methods: {
  47. getPicker() {
  48. if (this.picker == null) {
  49. this.picker = this.selectComponent('.van-area__picker');
  50. }
  51. return this.picker;
  52. },
  53. onCancel(event) {
  54. this.emit('cancel', event.detail);
  55. },
  56. onConfirm(event) {
  57. const { index } = event.detail;
  58. let { value } = event.detail;
  59. value = this.parseValues(value);
  60. this.emit('confirm', { value, index });
  61. },
  62. emit(type, detail) {
  63. detail.values = detail.value;
  64. delete detail.value;
  65. this.$emit(type, detail);
  66. },
  67. parseValues(values) {
  68. const { columnsPlaceholder } = this.data;
  69. return values.map((value, index) => {
  70. if (
  71. value &&
  72. (!value.code || value.name === columnsPlaceholder[index])
  73. ) {
  74. return Object.assign(Object.assign({}, value), {
  75. code: '',
  76. name: '',
  77. });
  78. }
  79. return value;
  80. });
  81. },
  82. onChange(event) {
  83. const { index, picker, value } = event.detail;
  84. this.code = value[index].code;
  85. this.setValues().then(() => {
  86. this.$emit('change', {
  87. picker,
  88. values: this.parseValues(picker.getValues()),
  89. index,
  90. });
  91. });
  92. },
  93. getConfig(type) {
  94. const { areaList } = this.data;
  95. return (areaList && areaList[`${type}_list`]) || {};
  96. },
  97. getList(type, code) {
  98. if (type !== 'province' && !code) {
  99. return [];
  100. }
  101. const { typeToColumnsPlaceholder } = this.data;
  102. const list = this.getConfig(type);
  103. let result = Object.keys(list).map((code) => ({
  104. code,
  105. name: list[code],
  106. }));
  107. if (code != null) {
  108. // oversea code
  109. if (code[0] === '9' && type === 'city') {
  110. code = '9';
  111. }
  112. result = result.filter((item) => item.code.indexOf(code) === 0);
  113. }
  114. if (typeToColumnsPlaceholder[type] && result.length) {
  115. // set columns placeholder
  116. const codeFill =
  117. type === 'province'
  118. ? ''
  119. : type === 'city'
  120. ? EMPTY_CODE.slice(2, 4)
  121. : EMPTY_CODE.slice(4, 6);
  122. result.unshift({
  123. code: `${code}${codeFill}`,
  124. name: typeToColumnsPlaceholder[type],
  125. });
  126. }
  127. return result;
  128. },
  129. getIndex(type, code) {
  130. let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
  131. const list = this.getList(type, code.slice(0, compareNum - 2));
  132. // oversea code
  133. if (code[0] === '9' && type === 'province') {
  134. compareNum = 1;
  135. }
  136. code = code.slice(0, compareNum);
  137. for (let i = 0; i < list.length; i++) {
  138. if (list[i].code.slice(0, compareNum) === code) {
  139. return i;
  140. }
  141. }
  142. return 0;
  143. },
  144. setValues() {
  145. const picker = this.getPicker();
  146. if (!picker) {
  147. return;
  148. }
  149. let code = this.code || this.getDefaultCode();
  150. const provinceList = this.getList('province');
  151. const cityList = this.getList('city', code.slice(0, 2));
  152. const stack = [];
  153. const indexes = [];
  154. const { columnsNum } = this.data;
  155. if (columnsNum >= 1) {
  156. stack.push(picker.setColumnValues(0, provinceList, false));
  157. indexes.push(this.getIndex('province', code));
  158. }
  159. if (columnsNum >= 2) {
  160. stack.push(picker.setColumnValues(1, cityList, false));
  161. indexes.push(this.getIndex('city', code));
  162. if (cityList.length && code.slice(2, 4) === '00') {
  163. [{ code }] = cityList;
  164. }
  165. }
  166. if (columnsNum === 3) {
  167. stack.push(
  168. picker.setColumnValues(
  169. 2,
  170. this.getList('county', code.slice(0, 4)),
  171. false
  172. )
  173. );
  174. indexes.push(this.getIndex('county', code));
  175. }
  176. return Promise.all(stack)
  177. .catch(() => {})
  178. .then(() => picker.setIndexes(indexes))
  179. .catch(() => {});
  180. },
  181. getDefaultCode() {
  182. const { columnsPlaceholder } = this.data;
  183. if (columnsPlaceholder.length) {
  184. return EMPTY_CODE;
  185. }
  186. const countyCodes = Object.keys(this.getConfig('county'));
  187. if (countyCodes[0]) {
  188. return countyCodes[0];
  189. }
  190. const cityCodes = Object.keys(this.getConfig('city'));
  191. if (cityCodes[0]) {
  192. return cityCodes[0];
  193. }
  194. return '';
  195. },
  196. getValues() {
  197. const picker = this.getPicker();
  198. if (!picker) {
  199. return [];
  200. }
  201. return this.parseValues(picker.getValues().filter((value) => !!value));
  202. },
  203. getDetail() {
  204. const values = this.getValues();
  205. const area = {
  206. code: '',
  207. country: '',
  208. province: '',
  209. city: '',
  210. county: '',
  211. };
  212. if (!values.length) {
  213. return area;
  214. }
  215. const names = values.map((item) => item.name);
  216. area.code = values[values.length - 1].code;
  217. if (area.code[0] === '9') {
  218. area.country = names[1] || '';
  219. area.province = names[2] || '';
  220. } else {
  221. area.province = names[0] || '';
  222. area.city = names[1] || '';
  223. area.county = names[2] || '';
  224. }
  225. return area;
  226. },
  227. reset(code) {
  228. this.code = code || '';
  229. return this.setValues();
  230. },
  231. },
  232. });