• uniapp uni-combox 数据源使用对象,选择后获取对应项的ID,可指定自定义的balbel,value


    背景:uniApp中uni-combox数据源只支持接受一维数组,无法对每个选项指定具体的id,更无法实现选中后返回id,对原有的源码进行改造后如下:

    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>

    使用:

    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区'}])

     

    有借鉴他人的修改的同时进行了容错,异步回填,传入空值容错等兼容。

    可以用以上代码可以在项目的src/uni_modules/uni-combox/components/uni-combox/uni-combox.vue直接替换该文件,

    也可以不进行安装,直接将以上文件当做一个组件使用

  • 相关阅读:
    关于RSA常见的错误理解
    osgEarth示例分析——osgearth_graticule
    【C语言】C语言中执行命令
    使用 jQuery 来动态地设置 HTML 按钮的显示和隐藏
    前端播放m3u8格式视频
    Pytorch Pytorch+深度学习神经网络相关学习收获
    软件全过程,全周期,各阶段资料获取(2024整理原件)
    css-vxe-form-item中输入框加自定义按钮(校验位置错误)
    构建直接序列扩频系统模型(Matlab代码实现)
    卷积神经网络(CNN):乳腺癌识别
  • 原文地址:https://blog.csdn.net/qq_34645412/article/details/140346421