fs-checkbox-group.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <template>
  2. <view class="fs-checkbox-group" :class="{ inline }"><slot></slot></view>
  3. </template>
  4. <script>
  5. /**
  6. * 多选框组组件
  7. * @description 多选框组组件
  8. * @property {Number} max 最多选中几个
  9. * @property {String} justify 图标对齐方式
  10. * @property {Boolean} reverse 是否反转
  11. * @property {Boolean} inline 单行显示
  12. * @property {Boolean} radius 是否圆角(仅对按钮样式有效)
  13. * @property {Boolean} round 是否半圆(仅对按钮样式有效)
  14. * @property {String} checkedColor 选中颜色
  15. * @property {String} checkedColorType = [primary | danger | warning | info | success] 选中颜色类型
  16. * @property {String} size = [mini | small | medium] 按钮大小(仅对按钮样式有效)
  17. * @event {Function} change change事件
  18. */
  19. export default {
  20. name: 'fs-checkbox-group'
  21. }
  22. </script>
  23. <script setup>
  24. import { provide, reactive, watch, toRefs } from 'vue'
  25. const props = defineProps({
  26. max: {
  27. type: Number,
  28. default: -1
  29. },
  30. justify: String,
  31. reverse: Boolean,
  32. inline: Boolean,
  33. checkedColor: String,
  34. checkedColorType: {
  35. type: String,
  36. default: 'primary',
  37. validator(value) {
  38. return ['primary', 'success', 'info', 'warning', 'danger'].includes(value)
  39. }
  40. },
  41. radius: Boolean,
  42. round: Boolean,
  43. size: {
  44. type: String,
  45. validator(value) {
  46. return ['mini', 'small', 'medium'].includes(value)
  47. }
  48. },
  49. modelValue: {
  50. type: Array,
  51. default() {
  52. return []
  53. }
  54. }
  55. })
  56. const emits = defineEmits(['update:modelValue', 'change'])
  57. const state = reactive({
  58. selectedValue: props.modelValue,
  59. children: []
  60. })
  61. watch(
  62. () => props.modelValue,
  63. val => {
  64. state.selectedValue = val
  65. }
  66. )
  67. const checkStrategy = value => {
  68. state.children.forEach(item => {
  69. if (typeof item.value === 'object') {
  70. item.selected = state.selectedValue.filter(selected => selected.id === item.value.id).length > 0
  71. } else {
  72. item.selected = state.selectedValue.indexOf(item.value) > -1
  73. }
  74. })
  75. }
  76. const updateChildren = child => {
  77. state.children.push(child)
  78. checkStrategy()
  79. }
  80. const updateValue = value => {
  81. let index = -1
  82. if (typeof value === 'object') {
  83. state.selectedValue.forEach((item, key) => {
  84. if (item.id === value.id) {
  85. index = key
  86. }
  87. })
  88. } else {
  89. index = state.selectedValue.indexOf(value)
  90. }
  91. if (state.selectedValue.length < props.max || props.max === -1) {
  92. if (index === -1) {
  93. state.selectedValue.push(value)
  94. } else {
  95. state.selectedValue.splice(index, 1)
  96. }
  97. } else {
  98. index > -1 && state.selectedValue.splice(index, 1)
  99. }
  100. }
  101. watch(
  102. () => state.selectedValue,
  103. val => {
  104. checkStrategy()
  105. emits('update:modelValue', val)
  106. emits('change', val)
  107. },
  108. { deep: true }
  109. )
  110. provide('checkboxGroup', {
  111. ...toRefs(props),
  112. updateChildren,
  113. updateValue
  114. })
  115. </script>
  116. <style lang="scss" scoped>
  117. .fs-checkbox-group {
  118. &.inline {
  119. display: flex;
  120. flex-wrap: wrap;
  121. }
  122. }
  123. </style>