• vant实现Select效果--单选和多选


    vue项目无论是用element中的Select选择器,还是使用公司维护的组件,都可以轻松实现单选和多选的需求,但在移动端使用vant时,找了几遍发现居然没有提供Select组件,下面提供对单选和多选组件的封装。

    单选效果:

    多选效果:

     

     1、封装单选组件(VanFieldSelectPicker)

    1. <template>
    2. <div class="dh-field">
    3. <div class=" van-hairline--bottom">
    4. <van-field
    5. v-model="resultLabel"
    6. v-bind="$attrs"
    7. readonly
    8. :is-link="$attrs.disabled === undefined"
    9. input-align="right"
    10. error-message-align='right'
    11. class="dh-cell"
    12. @click="showPopu($attrs.disabled)"
    13. />
    14. <van-popup v-model="show" position="bottom">
    15. <van-field v-if="isSearch" v-model="searchVal" input-align="left" placeholder="搜索" @input="search"/>
    16. <van-picker
    17. v-bind="$attrs"
    18. :columns="columnsData"
    19. show-toolbar
    20. @cancel="cancel"
    21. @confirm="onConfirm"
    22. @change="change"
    23. :value-key="this.option.label"
    24. />
    25. van-popup>
    26. div>
    27. div>
    28. template>
    29. <script>
    30. export default {
    31. name: 'VanFieldSelectPicker',
    32. model: {
    33. prop: 'selectValue'
    34. },
    35. props: {
    36. columns: {
    37. type: Array,
    38. default: function () {
    39. return []
    40. }
    41. },
    42. selectValue: {
    43. type: [String, Number],
    44. default: ''
    45. },
    46. option: {
    47. type: Object,
    48. default: function () {
    49. return { label: 'label', value: 'value' }
    50. }
    51. },
    52. isSearch: {
    53. type: Boolean,
    54. default: false
    55. },
    56. offOption: { // 关闭option配置key-value;当数据是非集合的数组的时候,开启
    57. type: Boolean,
    58. default: false
    59. }
    60. },
    61. computed: {
    62. resultLabel: {
    63. get () {
    64. const res = this.columns.filter(item => {
    65. const data = this.offOption ? item : item[this.option.value]
    66. return data === this.resultValue
    67. })
    68. let label = ''
    69. if (res.length) {
    70. label = this.offOption ? res[0] : res[0][this.option.label]
    71. }
    72. return label
    73. },
    74. set () {
    75. }
    76. }
    77. },
    78. data () {
    79. return {
    80. show: false,
    81. searchVal: '',
    82. resultValue: this.selectValue,
    83. columnsData: []
    84. }
    85. },
    86. methods: {
    87. search (val) {
    88. if (val) {
    89. this.columnsData = this.columnsData.filter(item => {
    90. const data = this.offOption ? item : item[this.option.label]
    91. return data.indexOf(val) > -1
    92. })
    93. } else {
    94. this.columnsData = JSON.parse(JSON.stringify(this.columns))
    95. }
    96. },
    97. onConfirm (value, index) {
    98. const data = this.offOption ? value : value[this.option.value]
    99. this.resultValue = data
    100. this.show = !this.show
    101. this.$emit('confirm', value, index, this.resultValue)
    102. },
    103. change (val, index) {
    104. this.$emit('change', val, index, this.resultValue)
    105. },
    106. cancel (val, index) {
    107. this.show = !this.show
    108. this.$emit('cancel', val, index, this.resultValue)
    109. },
    110. showPopu (disabled) {
    111. this.columnsData = JSON.parse(JSON.stringify(this.columns))
    112. this.resultValue = this.selectValue
    113. if (disabled !== undefined && disabled !== false) {
    114. return false
    115. } else {
    116. this.show = !this.show
    117. }
    118. }
    119. },
    120. watch: {
    121. selectValue: function (newVal) {
    122. this.resultValue = newVal
    123. },
    124. resultValue (val) {
    125. this.searchVal = ''
    126. this.columnsData = JSON.parse(JSON.stringify(this.columns))
    127. this.$emit('input', val)
    128. }
    129. }
    130. }
    131. script>
    132. <style lang="scss" scoped>
    133. .dh-field {
    134. padding: 0;
    135. background:#fff;
    136. .dh-cell.van-cell {
    137. padding: 10px 0;
    138. }
    139. .dh-cell.van-cell--required::before {
    140. left: -8px;
    141. }
    142. .van-popup {
    143. border-radius: 20px 20px 0 0;
    144. }
    145. }
    146. style>

    1.1 单选组件的使用

    ①使用到该组件的页面导入单选组件

     

    ② 在单选地方使用

    1. <van-field-select-picker
    2. v-model="orderType"
    3. placeholder="请选择"
    4. :columns="orderClassify"
    5. :option="{label:'configName', value:'configCode'}"
    6. @confirm="onOrderClassify"
    7. />

    ③orderClassify是后台返回的数据,{label:'configName', value:'configCode'} 对应选项的key-value,可以参考下面后台返回的数据

    ④单选事件 onOrderClassify 对应的方法

    1. onOrderClassify(data1, index, data2) {
    2. // data1 当前这一条的obj数据
    3. // index 当前选择的索引
    4. // data2 当前这一条数据的value
    5. this.orderName = data1.configName
    6. },

     上面便是单选弹框的完整代码,下面开始多选组件的封装

    2、封装多选组件(VanFieldCheckbox)

    1. <template>
    2. <div class="dh-field">
    3. <div class="van-hairline--bottom">
    4. <van-field
    5. v-model="resultLabel"
    6. v-bind="$attrs"
    7. readonly
    8. :is-link="$attrs.disabled === undefined"
    9. error-message-align='right'
    10. input-align="right"
    11. class="dh-cell"
    12. @click="showPopu($attrs.disabled)"
    13. />
    14. <van-popup v-model="show" position="bottom" class="" >
    15. <div class="van-picker__toolbar">
    16. <button type="button" class="van-picker__cancel" @click="cancel">取消button>
    17. <div class="van-ellipsis van-picker__title">{{$attrs.label}}div>
    18. <button type="button" class="van-picker__confirm" @click="onConfirm">确认button>
    19. div>
    20. <div style="max-height:264px; overflow-y:auto;">
    21. <van-field v-if="isSearch" v-model="searchVal" input-align="left" placeholder="搜索" @input="search"/>
    22. <van-cell title="全选">
    23. <template #right-icon>
    24. <van-checkbox v-model="checkedAll" name="all" @click="toggleAll"/>
    25. template>
    26. van-cell>
    27. <van-checkbox-group ref="checkboxGroup" v-model="checkboxValue" @change="change">
    28. <van-cell-group>
    29. <van-cell
    30. v-for="(item, index) in columnsData"
    31. :key="item[option.value]"
    32. :title="item[option.label]"
    33. clickable
    34. @click="toggle(index)"
    35. >
    36. <template #right-icon>
    37. <van-checkbox ref="checkboxes" :name="item[option.value]" />
    38. template>
    39. van-cell>
    40. van-cell-group>
    41. van-checkbox-group>
    42. div>
    43. van-popup>
    44. div>
    45. div>
    46. template>
    47. <script>
    48. export default {
    49. name: 'VanFieldCheckbox',
    50. model: {
    51. prop: 'selectValue'
    52. },
    53. props: {
    54. columns: {
    55. type: Array,
    56. default: function () {
    57. return []
    58. }
    59. },
    60. selectValue: {
    61. type: Array,
    62. default: function () {
    63. return []
    64. }
    65. },
    66. option: {
    67. type: Object,
    68. default: function () {
    69. return { label: 'label', value: 'value' }
    70. }
    71. },
    72. // 是否支持搜索
    73. isSearch: {
    74. type: Boolean,
    75. default: true
    76. }
    77. },
    78. computed: {
    79. resultLabel: {
    80. get () {
    81. const res = this.columns.filter(item => {
    82. return this.resultValue.indexOf(item[this.option.value]) > -1
    83. })
    84. const resLabel = res.map(item => {
    85. return item[this.option.label]
    86. })
    87. return resLabel.join(',')
    88. },
    89. set () {
    90. }
    91. }
    92. },
    93. data () {
    94. return {
    95. show: false,
    96. searchVal: '',
    97. columnsData: JSON.parse(JSON.stringify(this.columns)),
    98. checkboxValue: JSON.parse(JSON.stringify(this.selectValue)),
    99. checkedAll: false,
    100. resultValue: JSON.parse(JSON.stringify(this.selectValue))
    101. }
    102. },
    103. methods: {
    104. // 搜索
    105. search (val) {
    106. if (val) {
    107. this.columnsData = this.columnsData.filter(item => {
    108. return item[this.option.label].indexOf(val) > -1
    109. })
    110. } else {
    111. this.columnsData = JSON.parse(JSON.stringify(this.columns))
    112. }
    113. },
    114. getData (val) {
    115. const res = this.columnsData.filter(item => {
    116. return val.indexOf(item[this.option.value]) > -1
    117. })
    118. return res
    119. },
    120. onConfirm () {
    121. this.resultValue = this.checkboxValue
    122. this.show = !this.show
    123. this.$emit('confirm', this.resultValue, this.getData(this.resultValue))
    124. },
    125. change (val) {
    126. this.$emit('change', val, this.getData(this.resultValue))
    127. },
    128. cancel () {
    129. this.show = !this.show
    130. this.$emit('cancel', this.resultValue)
    131. },
    132. toggle (index) {
    133. this.$refs.checkboxes[index].toggle()
    134. },
    135. toggleAll (all) {
    136. this.$refs.checkboxGroup.toggleAll(this.checkedAll)
    137. },
    138. showPopu (disabled) {
    139. this.columnsData = JSON.parse(JSON.stringify(this.columns))
    140. this.checkboxValue = JSON.parse(JSON.stringify(this.selectValue))
    141. this.resultValue = JSON.parse(JSON.stringify(this.selectValue))
    142. if (disabled !== undefined && disabled !== false) {
    143. return false
    144. } else {
    145. this.show = !this.show
    146. }
    147. }
    148. },
    149. watch: {
    150. selectValue: function (newVal) {
    151. this.resultValue = newVal
    152. },
    153. resultValue (val) {
    154. this.searchVal = ''
    155. this.columnsData = JSON.parse(JSON.stringify(this.columns))
    156. this.$emit('input', val)
    157. },
    158. columnsData: {
    159. handler (val) {
    160. if (val.length && val.length === this.checkboxValue.length) {
    161. this.checkedAll = true
    162. } else {
    163. this.checkedAll = false
    164. }
    165. },
    166. immediate: true
    167. },
    168. checkboxValue: {
    169. handler (val) {
    170. if (val.length && val.length === this.columnsData.length) {
    171. this.checkedAll = true
    172. } else {
    173. this.checkedAll = false
    174. }
    175. },
    176. immediate: true
    177. }
    178. }
    179. }
    180. script>
    181. <style lang="scss" scoped>
    182. .dh-field {
    183. padding: 0;
    184. background:#fff;
    185. .dh-cell.van-cell {
    186. padding: 10px 0;
    187. }
    188. .dh-cell.van-cell--required::before {
    189. left: -8px;
    190. }
    191. .van-popup {
    192. border-radius: 20px 20px 0 0;
    193. }
    194. }
    195. style>

    ①使用到该组件的页面导入多选组件,和单选组件的导入一致,参考上面

    ② 在多选地方使用

    1. <van-field-checkbox
    2. v-model="checkedExecutors"
    3. placeholder="请选择"
    4. :columns="executor"
    5. label-width="100"
    6. :option="{label:'name', value:'userId'}"
    7. />

     ③executor是后台返回的数据,{label:'name', value:'userId'}对应选项的key-value,可以参考下面后台返回的数据

     ④多选事件上面我没用到,我是直接v-model绑定了选中的数据,如果需要在事件中额外处理数据,可以通过@confirm="onConfirm" 来绑定事件(正常获取值用不到,直接v-model即可)

    1. onConfirm (data1, data2) {
    2. // data1 是当前选中数据的value的数组
    3. // data2 是当前选中数据的整个obj集合
    4. },

    以上便是基于popup和cell、field封装的select单选、多选组件的完整代码。

  • 相关阅读:
    「高等数学」雅可比矩阵和黑塞矩阵的异同
    创新趋势 | SaaS增长新趋势:产品驱动增长PLG(上)
    国内表格软件-FineReport Count函数
    转置矩阵的性质
    算法补天系列之——前缀树+贪心算法
    【GoWeb项目-个人Blog】数据库表设计
    C# GraphicsPath 类学习
    第9章:项目实战
    Kamiya丨Kamiya艾美捷人α1-抗糜蛋白酶ELISA说明书
    【亲测有效】3分钟 从零安装高匿名http协议带账号密码的代理服务 步骤超简单 仅限用于学习交流使用 勿用于其他用途
  • 原文地址:https://blog.csdn.net/ljw124213/article/details/126058982