wd-checkbox.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <template>
  2. <view
  3. :class="`wd-checkbox ${innerCell ? 'is-cell-box' : ''} ${innerShape === 'button' ? 'is-button-box' : ''} ${isChecked ? 'is-checked' : ''} ${
  4. isFirst ? 'is-first-child' : ''
  5. } ${isLast ? 'is-last-child' : ''} ${innerInline ? 'is-inline' : ''} ${innerShape === 'button' ? 'is-button' : ''} ${
  6. innerDisabled ? 'is-disabled' : ''
  7. } ${innerSize ? 'is-' + innerSize : ''} ${customClass}`"
  8. :style="customStyle"
  9. @click="toggle"
  10. >
  11. <!--shape为button时,移除wd-checkbox__shape,只保留wd-checkbox__label-->
  12. <view
  13. v-if="innerShape !== 'button'"
  14. :class="`wd-checkbox__shape ${innerShape === 'square' ? 'is-square' : ''} ${customShapeClass}`"
  15. :style="isChecked && !innerDisabled && innerCheckedColor ? 'color :' + innerCheckedColor : ''"
  16. >
  17. <wd-icon custom-class="wd-checkbox__check" name="check-bold" />
  18. </view>
  19. <!--shape为button时只保留wd-checkbox__label-->
  20. <view
  21. :class="`wd-checkbox__label ${customLabelClass}`"
  22. :style="isChecked && innerShape === 'button' && !innerDisabled && innerCheckedColor ? 'color:' + innerCheckedColor : ''"
  23. >
  24. <!--button选中时展示的icon-->
  25. <wd-icon v-if="innerShape === 'button' && isChecked" custom-class="wd-checkbox__btn-check" name="check-bold" />
  26. <!--文案-->
  27. <view class="wd-checkbox__txt" :style="maxWidth ? 'max-width:' + maxWidth : ''">
  28. <slot></slot>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script lang="ts">
  34. export default {
  35. name: 'wd-checkbox',
  36. options: {
  37. addGlobalClass: true,
  38. virtualHost: true,
  39. styleIsolation: 'shared'
  40. }
  41. }
  42. </script>
  43. <script lang="ts" setup>
  44. import wdIcon from '../wd-icon/wd-icon.vue'
  45. import { computed, getCurrentInstance, onBeforeMount, watch } from 'vue'
  46. import { useParent } from '../composables/useParent'
  47. import { CHECKBOX_GROUP_KEY } from '../wd-checkbox-group/types'
  48. import { getPropByPath, isDef } from '../common/util'
  49. import { checkboxProps, type CheckboxExpose } from './types'
  50. const props = defineProps(checkboxProps)
  51. const emit = defineEmits(['change', 'update:modelValue'])
  52. defineExpose<CheckboxExpose>({
  53. toggle
  54. })
  55. const { parent: checkboxGroup, index } = useParent(CHECKBOX_GROUP_KEY)
  56. const isChecked = computed(() => {
  57. if (checkboxGroup) {
  58. return checkboxGroup.props.modelValue.indexOf(props.modelValue) > -1
  59. } else {
  60. return props.modelValue === props.trueValue
  61. }
  62. }) // 是否被选中
  63. const isFirst = computed(() => {
  64. return index.value === 0
  65. })
  66. const isLast = computed(() => {
  67. const children = isDef(checkboxGroup) ? checkboxGroup.children : []
  68. return index.value === children.length - 1
  69. })
  70. const { proxy } = getCurrentInstance() as any
  71. watch(
  72. () => props.modelValue,
  73. () => {
  74. // 组合使用走这个逻辑
  75. if (checkboxGroup) {
  76. checkName()
  77. }
  78. }
  79. )
  80. watch(
  81. () => props.shape,
  82. (newValue) => {
  83. const type = ['circle', 'square', 'button']
  84. if (isDef(newValue) && type.indexOf(newValue) === -1) console.error(`shape must be one of ${type.toString()}`)
  85. }
  86. )
  87. const innerShape = computed(() => {
  88. return props.shape || getPropByPath(checkboxGroup, 'props.shape') || 'circle'
  89. })
  90. const innerCheckedColor = computed(() => {
  91. return props.checkedColor || getPropByPath(checkboxGroup, 'props.checkedColor')
  92. })
  93. const innerDisabled = computed(() => {
  94. if (!checkboxGroup) {
  95. return props.disabled
  96. }
  97. const { max, min, modelValue, disabled } = checkboxGroup.props
  98. if (
  99. (max && modelValue.length >= max && !isChecked.value) ||
  100. (min && modelValue.length <= min && isChecked.value) ||
  101. props.disabled === true ||
  102. (disabled && props.disabled === null)
  103. ) {
  104. return true
  105. }
  106. return props.disabled
  107. })
  108. const innerInline = computed(() => {
  109. return getPropByPath(checkboxGroup, 'props.inline') || false
  110. })
  111. const innerCell = computed(() => {
  112. return getPropByPath(checkboxGroup, 'props.cell') || false
  113. })
  114. const innerSize = computed(() => {
  115. return props.size || getPropByPath(checkboxGroup, 'props.size')
  116. })
  117. onBeforeMount(() => {
  118. // eslint-disable-next-line quotes
  119. if (props.modelValue === null) console.error("checkbox's value must be set")
  120. })
  121. /**
  122. * @description 检测checkbox绑定的value是否和其它checkbox的value冲突
  123. * @param {Object} self 自身
  124. * @param myName 自己的标识符
  125. */
  126. function checkName() {
  127. checkboxGroup &&
  128. checkboxGroup.children &&
  129. checkboxGroup.children.forEach((child: any) => {
  130. if (child.$.uid !== proxy.$.uid && child.modelValue === props.modelValue) {
  131. console.error(`The checkbox's bound value: ${props.modelValue} has been used`)
  132. }
  133. })
  134. }
  135. /**
  136. * @description 点击checkbox的Event handle
  137. */
  138. function toggle() {
  139. if (innerDisabled.value) return
  140. // 复选框单独使用时点击反选,并且在checkbox上触发change事件
  141. if (checkboxGroup) {
  142. emit('change', {
  143. value: !isChecked.value
  144. })
  145. checkboxGroup.changeSelectState(props.modelValue)
  146. } else {
  147. const newVal = props.modelValue === props.trueValue ? props.falseValue : props.trueValue
  148. emit('update:modelValue', newVal)
  149. emit('change', {
  150. value: newVal
  151. })
  152. }
  153. }
  154. </script>
  155. <style lang="scss" scoped>
  156. @import './index.scss';
  157. </style>