Technology Sharing

uniapp uni-combox Data source usage object, select it to get the ID of the corresponding item, and specify a custom balbel, value

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Background: The uni-combox data source in uniApp only supports one-dimensional arrays. It is not possible to specify a specific ID for each option, and it is not possible to return the ID after selecting it. The original source code is modified as follows:

  1. <template>
  2. <view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
  3. <view v-if="label" class="uni-combox__label" :style="labelStyle">
  4. <text>{{label}}</text>
  5. </view>
  6. <view class="uni-combox__input-box">
  7. <input class="uni-combox__input" type="text" :placeholder="placeholder" placeholder-class="uni-combox__input-plac"
  8. v-model="inputVal" @input="onInput" @focus="onFocus" @blur="onBlur" />
  9. <uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
  10. </uni-icons>
  11. </view>
  12. <view class="uni-combox__selector" v-if="showSelector">
  13. <view class="uni-popper__arrow"></view>
  14. <scroll-view scroll-y="true" class="uni-combox__selector-scroll" @scroll="onScroll">
  15. <view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
  16. <text>{{emptyTips}}</text>
  17. </view>
  18. <view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index"
  19. @click="onSelectorClick(index)">
  20. <text>{{item[`${labelKey}`]}}</text>
  21. </view>
  22. </scroll-view>
  23. </view>
  24. <uni-icons style="padding-left:20rpx;" class="content-clear-icon" type="clear" color="#c0c4cc" v-if="inputVal"
  25. @click="onClear"></uni-icons>
  26. <!-- :size="clearSize"
  27. :color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'" -->
  28. <!-- 新增蒙层,点击蒙层时关闭选项显示 -->
  29. <view class="uni-combox__mask" v-show="showSelector" @click="showSelector = false"></view>
  30. </view>
  31. </template>
  32. <script>
  33. import {
  34. nextTick
  35. } from 'vue'
  36. /**
  37. * Combox 组合输入框
  38. * @description 组合输入框一般用于既可以输入也可以选择的场景
  39. * @tutorial https://ext.dcloud.net.cn/plugin?id=1261
  40. * @property {String} label 左侧文字
  41. * @property {String} labelWidth 左侧内容宽度
  42. * @property {String} placeholder 输入框占位符
  43. * @property {Array} candidates 候选项列表
  44. * @property {String} emptyTips 筛选结果为空时显示的文字
  45. * @property {String} value 组合框的值
  46. */
  47. export default {
  48. name: 'uniCombox',
  49. emits: ['input', 'update:modelValue', 'change'],
  50. props: {
  51. border: {
  52. type: Boolean,
  53. default: true
  54. },
  55. label: {
  56. type: String,
  57. default: ''
  58. },
  59. labelWidth: {
  60. type: String,
  61. default: 'auto'
  62. },
  63. placeholder: {
  64. type: String,
  65. default: ''
  66. },
  67. candidates: {
  68. type: Array,
  69. default () {
  70. return []
  71. }
  72. },
  73. emptyTips: {
  74. type: String,
  75. default: '无匹配项'
  76. },
  77. labelKey: {
  78. type: String,
  79. default: 'dictName'
  80. },
  81. valueKey: {
  82. type: String,
  83. default: 'dictId'
  84. },
  85. // #ifndef VUE3
  86. value: {
  87. type: [String, Number],
  88. default: ''
  89. },
  90. // #endif
  91. // #ifdef VUE3
  92. modelValue: {
  93. type: [String, Number],
  94. default: ''
  95. },
  96. // #endif
  97. },
  98. data() {
  99. return {
  100. showSelector: false,
  101. inputVal: '',
  102. blurTimer: null,
  103. dictVal: "",
  104. filterCandidates: []
  105. }
  106. },
  107. computed: {
  108. labelStyle() {
  109. if (this.labelWidth === 'auto') {
  110. return ""
  111. }
  112. return `width: ${this.labelWidth}`
  113. },
  114. filterCandidatesLength() {
  115. console.log(this.filterCandidates)
  116. return this.filterCandidates.length
  117. }
  118. },
  119. watch: {
  120. // #ifndef VUE3
  121. value: {
  122. handler(newVal) {
  123. this.dictVal = newVal
  124. },
  125. immediate: true
  126. },
  127. // #endif
  128. // 因为获取列表是个异步的过程,需要对列表进行监听
  129. candidates: {
  130. handler(arr) {
  131. if (arr.length > 0 && this.dictVal) {
  132. let obj = arr.find((item, index) => {
  133. return this.dictVal == item[`${this.valueKey}`]
  134. })
  135. this.inputVal = obj[`${this.labelKey}`]
  136. this.$forceUpdate(); // 强制更新 DOM
  137. }
  138. this.filterCandidates = arr.filter((item) => {
  139. return item[`${this.labelKey}`].toString().indexOf(this.inputVal) > -1
  140. })
  141. },
  142. immediate: true,
  143. deep: true
  144. },
  145. // #ifdef VUE3
  146. modelValue: {
  147. handler(newVal) {
  148. // this.inputVal = newVal
  149. this.dictVal = newVal
  150. if (this.candidates.length > 0 && newVal) {
  151. let obj = this.candidates.find((item, index) => {
  152. return newVal == item[`${this.valueKey}`]
  153. })
  154. // 兼容当传入错误的id在待选列表找不到时候的错误
  155. if (obj) {
  156. this.inputVal = obj[`${this.labelKey}`]
  157. } else {
  158. this.inputVal = ''
  159. }
  160. } else if (!newVal) { //当传入的是空值时直接将上一次回填数据清空
  161. this.inputVal = ''
  162. }
  163. },
  164. immediate: true,
  165. deep: true,
  166. },
  167. // #endif
  168. },
  169. methods: {
  170. toggleSelector() {
  171. this.showSelector = !this.showSelector
  172. },
  173. onFocus() {
  174. this.filterCandidates = this.candidates
  175. this.showSelector = true
  176. },
  177. onBlur() {
  178. this.blurTimer = setTimeout(() => {
  179. this.showSelector = false
  180. }, 153)
  181. },
  182. onScroll() { // 滚动时将blur的定时器关掉
  183. if (this.blurTimer) {
  184. clearTimeout(this.blurTimer)
  185. this.blurTimer = null
  186. }
  187. },
  188. onSelectorClick(index) {
  189. // this.inputVal = this.filterCandidates[index]
  190. this.dictVal = this.filterCandidates[index][`${this.valueKey}`]
  191. //this.dictVal 的赋值一定要在this.inputVal前执行,
  192. //因为this.filterCandidates会监听this.inputVal的变化被重新赋值
  193. //这样在选择列表中非第一个选项会报错
  194. this.inputVal = this.filterCandidates[index][`${this.labelKey}`]
  195. this.showSelector = false
  196. this.$emit('input', this.dictVal)
  197. this.$emit('change', this.dictVal)
  198. this.$emit('update:modelValue', this.dictVal)
  199. },
  200. onInput() {
  201. this.filterCandidates = this.candidates.filter((item) => {
  202. console.log(item, this.labelKey)
  203. return item[`${this.labelKey}`].toString().indexOf(this.inputVal) > -1
  204. })
  205. setTimeout(() => {
  206. this.$emit('input', this.dictVal)
  207. this.$emit('update:modelValue', this.dictVal)
  208. })
  209. },
  210. /**
  211. * 清理内容
  212. * @param {Object} event
  213. */
  214. onClear(event) {
  215. this.inputVal = '';
  216. },
  217. }
  218. }
  219. </script>
  220. <style lang="scss">
  221. .uni-combox {
  222. font-size: 14px;
  223. border: 1px solid #DCDFE6;
  224. border-radius: 4px;
  225. // padding: 6px 10px;
  226. padding: 10px 6px 10px 0;
  227. position: relative;
  228. /* #ifndef APP-NVUE */
  229. display: flex;
  230. /* #endif */
  231. // height: 40px;
  232. flex-direction: row;
  233. align-items: center;
  234. // border-bottom: solid 1px #DDDDDD;
  235. }
  236. .uni-combox__label {
  237. font-size: 16px;
  238. line-height: 22px;
  239. padding-right: 10px;
  240. color: #999999;
  241. }
  242. .uni-combox__input-box {
  243. padding-left: 10px;
  244. position: relative;
  245. /* #ifndef APP-NVUE */
  246. display: flex;
  247. /* #endif */
  248. flex: 1;
  249. flex-direction: row;
  250. align-items: center;
  251. }
  252. .uni-combox__input {
  253. flex: 1;
  254. font-size: 14px;
  255. height: 22px;
  256. line-height: 22px;
  257. }
  258. .uni-combox__input-plac {
  259. font-size: 14px;
  260. color: #999;
  261. }
  262. .uni-combox__selector {
  263. /* #ifndef APP-NVUE */
  264. box-sizing: border-box;
  265. /* #endif */
  266. position: absolute;
  267. top: calc(100% + 12px);
  268. left: 0;
  269. width: 100%;
  270. background-color: #FFFFFF;
  271. border: 1px solid #EBEEF5;
  272. border-radius: 6px;
  273. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  274. z-index: 3;
  275. padding: 4px 0;
  276. }
  277. .uni-combox__selector-scroll {
  278. /* #ifndef APP-NVUE */
  279. max-height: 200px;
  280. box-sizing: border-box;
  281. /* #endif */
  282. }
  283. .uni-combox__selector-empty,
  284. .uni-combox__selector-item {
  285. /* #ifndef APP-NVUE */
  286. display: flex;
  287. cursor: pointer;
  288. /* #endif */
  289. line-height: 36px;
  290. font-size: 14px;
  291. text-align: center;
  292. // border-bottom: solid 1px #DDDDDD;
  293. padding: 0px 10px;
  294. white-space: nowrap;
  295. overflow: auto;
  296. }
  297. .uni-combox__selector-item::-webkit-scrollbar {
  298. width: 0;
  299. height: 0;
  300. }
  301. .uni-combox__selector-item:hover {
  302. background-color: #f9f9f9;
  303. }
  304. .uni-combox__selector-empty:last-child,
  305. .uni-combox__selector-item:last-child {
  306. /* #ifndef APP-NVUE */
  307. border-bottom: none;
  308. /* #endif */
  309. }
  310. // picker 弹出层通用的指示小三角
  311. .uni-popper__arrow,
  312. .uni-popper__arrow::after {
  313. position: absolute;
  314. display: block;
  315. width: 0;
  316. height: 0;
  317. border-color: transparent;
  318. border-style: solid;
  319. border-width: 6px;
  320. }
  321. .uni-popper__arrow {
  322. filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
  323. top: -6px;
  324. left: 10%;
  325. margin-right: 3px;
  326. border-top-width: 0;
  327. border-bottom-color: #EBEEF5;
  328. }
  329. .uni-popper__arrow::after {
  330. content: " ";
  331. top: 1px;
  332. margin-left: -6px;
  333. border-top-width: 0;
  334. border-bottom-color: #fff;
  335. }
  336. .uni-combox__no-border {
  337. border: none;
  338. }
  339. .uni-combox__mask {
  340. width: 100%;
  341. height: 100%;
  342. position: fixed;
  343. top: 0;
  344. left: 0;
  345. z-index: 1;
  346. }
  347. </style>

use:

  1. <uni-combox :candidates="testList" labelKey="text" valueKey="idx" emptyTips='暂无数据' placeholder="请选择"
  2. v-model="groupId" @change="selectGroupab">
  3. </uni-combox>
  4. // 选择区/
  5. const selectGroupab = (val) => {
  6. console.log(' 选择改变回调', val)
  7. }
  8. const groupId =ref('')
  9. const testList =ref([{idx:1,text:'A区'},{idx:2,text:'B区'}])

 

While learning from others' modifications, we also made compatibility features such as fault tolerance, asynchronous backfilling, and null value tolerance.

You can use the above code to directly replace the file in the project's src/uni_modules/uni-combox/components/uni-combox/uni-combox.vue.

You can also use the above files as a component without installing them.