移动端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

191 lines
4.8 KiB

  1. <!-- 下拉列表表单组件 zhao -->
  2. <template>
  3. <div>
  4. <van-field
  5. :readonly="true"
  6. :clickable="!readonly"
  7. :name="name"
  8. :value="visibleValue"
  9. :label="label"
  10. :placeholder="placeholder"
  11. @click="openPopup"
  12. input-align="right"
  13. right-icon="arrow-down"
  14. :rules="rules"
  15. :required="required"
  16. :label-width="labelWidth || 'auto'"
  17. :size="size || ''"
  18. >
  19. </van-field>
  20. <van-popup v-model="popupVisible" position="bottom">
  21. <van-picker
  22. ref="picker"
  23. :title="label"
  24. show-toolbar
  25. :columns="columns ? columns : remoteColumns"
  26. :readonly="readonly"
  27. :value-key="valueKey"
  28. :loading="loading"
  29. @confirm="onConfirm"
  30. @cancel="onCancel"
  31. @change="onChanged"
  32. />
  33. </van-popup>
  34. </div>
  35. </template>
  36. <script>
  37. import request from "@/utils/request";
  38. export default {
  39. name: "fieldSelect",
  40. props: [
  41. 'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
  42. 'columns', // 列表数据 Array
  43. 'valueKey', // 名称键名 String
  44. 'dataKey', // 值键名 String
  45. 'remoteUrl', // 远程列表加载地址 String
  46. 'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
  47. 'clearable', // 点击取消时清空绑定值
  48. 'size',
  49. ],
  50. watch: {
  51. value: function (newVal, oldVal) {
  52. this.internalValue = newVal;
  53. this.visibleValue = newVal;
  54. this.syncIndex();
  55. },
  56. columns: function (newVal, oldVal) {
  57. this.syncIndex();
  58. },
  59. remoteUrl: function (newVal, oldVal) {
  60. this.requestRemote();
  61. },
  62. onRemoteResponse: function (newVal, oldVal) {
  63. this.parseRemote();
  64. }
  65. },
  66. created() {
  67. if(this.remoteUrl)
  68. this.requestRemote();
  69. },
  70. data() {
  71. return {
  72. popupVisible: false,
  73. internalValue: this.value,
  74. visibleValue: '',
  75. defaultIndex: 0,
  76. remoteColumns: null,
  77. loading: false,
  78. remoteResponse: null,
  79. };
  80. },
  81. methods: {
  82. openPopup() {
  83. if(!this.readonly)
  84. {
  85. this.popupVisible = true;
  86. this.$nextTick(() => {
  87. this.$refs.picker.setIndexes([this.defaultIndex]);
  88. })
  89. }
  90. },
  91. closePopup() {
  92. this.popupVisible = false;
  93. },
  94. onChanged(data) {
  95. this.$emit('change', data);
  96. },
  97. onConfirm(data) {
  98. this.syncValue(data);
  99. this.$emit('input', this.internalValue);
  100. this.$emit('confirm', this.internalValue);
  101. this.closePopup();
  102. },
  103. onCancel() {
  104. this.closePopup();
  105. this.$emit('cancel');
  106. if(this.clearable)
  107. {
  108. this.visibleValue = '';
  109. this.internalValue = null;
  110. this.$emit('input', this.internalValue);
  111. }
  112. },
  113. getValue(data) {
  114. return typeof(data) === 'object' && this.dataKey ? data[this.dataKey] : data;
  115. },
  116. getLabel(data) {
  117. return typeof(data) === 'object' && this.valueKey ? data[this.valueKey] : data;
  118. },
  119. syncValue(data) {
  120. this.internalValue = this.getValue(data);
  121. this.visibleValue = this.getLabel(data);
  122. },
  123. syncIndex() {
  124. let columns = this.getColumns();
  125. if(!columns)
  126. return -1;
  127. for(let i in columns)
  128. {
  129. if(this.getValue(columns[i]) == this.internalValue) {
  130. this.defaultIndex = i;
  131. this.visibleValue = this.getLabel(columns[i]);
  132. this.onChanged(columns[i]);
  133. return i;
  134. }
  135. }
  136. if(1) // 不存在
  137. {
  138. this.defaultIndex = -1;
  139. this.visibleValue = this.internalValue;
  140. this.onChanged(null);
  141. }
  142. return -1;
  143. },
  144. getColumns() {
  145. return this.columns ? this.columns : this.remoteColumns;
  146. },
  147. requestRemote() {
  148. if(!this.remoteUrl)
  149. return;
  150. this.loading = true;
  151. this.remoteColumns = [];
  152. let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl));
  153. promise.then((resp) => {
  154. this.remoteResponse = resp;
  155. this.parseRemote();
  156. this.syncIndex();
  157. }).catch((e) => {
  158. console.error(e);
  159. }).finally(() => {
  160. this.loading = false;
  161. })
  162. },
  163. parseRemote() {
  164. if(!this.remoteResponse)
  165. return;
  166. let type = typeof(this.onRemoteResponse);
  167. if(type === 'function')
  168. this.remoteColumns = this.onRemoteResponse(this.remoteResponse);
  169. else if(type === 'string')
  170. {
  171. let arr = this.onRemoteResponse.split('.');
  172. let ptr = this.remoteResponse;
  173. for(let i in arr)
  174. {
  175. ptr = this.remoteResponse[arr[i]];
  176. }
  177. this.remoteColumns = ptr;
  178. }
  179. else
  180. this.remoteColumns = this.remoteResponse;
  181. },
  182. },
  183. }
  184. </script>
  185. <style scoped>
  186. </style>