CheckBox.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <template>
  2. <FlexRow
  3. :touchable="!disabled"
  4. :activeOpacity="activeOpacity"
  5. :innerStyle="{
  6. ...(block ? themeStyles.checkBoxFull.value : themeStyles.checkBox.value),
  7. ...innerStyle
  8. }"
  9. innerClass="nana-check"
  10. center
  11. @click.stop="switchOn"
  12. >
  13. <slot name="check" v-if="checkPosition === 'left'" icon="check" :on="value" :disabled="disabled" :shape="shape">
  14. <CheckBoxDefaultButton
  15. :on="value"
  16. :disabled="disabled"
  17. :shape="shape"
  18. :size="checkSize"
  19. :checkedBackgroundColor="themeContext.resolveThemeColor(color)"
  20. :checkedBorderColor="themeContext.resolveThemeColor(color)"
  21. :borderColor="themeContext.resolveThemeColor(borderColor)"
  22. :checkColor="themeContext.resolveThemeColor(checkColor)"
  23. :icon="props.icon"
  24. />
  25. </slot>
  26. <slot>
  27. <Text
  28. :innerStyle="{
  29. ...themeStyles.checkText.value,
  30. ...textStyle,
  31. color: themeContext.resolveThemeColor(props.disabled === true ? disabledTextColor : textColor),
  32. display: StringUtils.isNullOrEmpty(text) ? 'none' : 'flex',
  33. }"
  34. :text="text"
  35. />
  36. </slot>
  37. <slot name="check" v-if="checkPosition === 'right'" icon="check" :on="value" :disabled="disabled" :shape="shape">
  38. <CheckBoxDefaultButton
  39. :on="value"
  40. :disabled="disabled"
  41. :shape="shape"
  42. :size="checkSize"
  43. :checkedBackgroundColor="themeContext.resolveThemeColor(color)"
  44. :checkedBorderColor="themeContext.resolveThemeColor(color)"
  45. :borderColor="themeContext.resolveThemeColor(borderColor)"
  46. :checkColor="themeContext.resolveThemeColor(checkColor)"
  47. :icon="props.icon"
  48. />
  49. </slot>
  50. </FlexRow>
  51. </template>
  52. <script setup lang="ts">
  53. import { computed, inject, onMounted, toRef, watch } from 'vue';
  54. import { propGetThemeVar, useTheme, type TextStyle, type ViewStyle } from '../theme/ThemeDefine';
  55. import { useFieldChildValueInjector } from './FormContext';
  56. import { StringUtils } from '@imengyu/imengyu-utils';
  57. import type { CheckBoxGroupContextInfo } from './CheckBoxGroup.vue';
  58. import FlexRow from '../layout/FlexRow.vue';
  59. import CheckBoxDefaultButton from './CheckBoxDefaultButton.vue';
  60. import Text from '../basic/Text.vue';
  61. import { DynamicSize } from '../theme/ThemeTools';
  62. import { useCellContext } from '../basic/CellContext';
  63. export interface CheckBoxProps {
  64. /**
  65. * 是否选中复选框
  66. * @default false
  67. */
  68. modelValue?: boolean;
  69. /**
  70. * 当前复选框在复选框组中的value,不能与其他重复
  71. */
  72. name?: string;
  73. /**
  74. * 复选框的文字
  75. */
  76. text?: string;
  77. /**
  78. * 复选框的形状
  79. * @default 'square'
  80. */
  81. shape?: "square"|"round";
  82. /**
  83. * 复选框占满整个父元素,默认否
  84. * @default false
  85. */
  86. block?: boolean,
  87. /**
  88. * 复选框按钮位置,默认在左
  89. * @default 'left'
  90. */
  91. checkPosition?: "left"|"right";
  92. /**
  93. * 复选框未选择时的边框颜色
  94. * @default border.input
  95. */
  96. borderColor?: string|undefined;
  97. /**
  98. * 复选框选中时勾的颜色
  99. * @default white
  100. */
  101. checkColor?: string|undefined;
  102. /**
  103. * 复选框按钮大小,默认是 36
  104. * @default 36
  105. */
  106. checkSize?: number|undefined;
  107. /**
  108. * 按下时透明度
  109. * @default 0.75
  110. */
  111. activeOpacity?: number,
  112. /**
  113. * 复选框的颜色,默认是 primary
  114. * @default primary
  115. */
  116. color?: string;
  117. /**
  118. * 是否禁用复选框
  119. * @default false
  120. */
  121. disabled?: boolean;
  122. /**
  123. * 选择勾的图标
  124. * @default 'check-mark'
  125. */
  126. icon?: string;
  127. /**
  128. * 文字颜色
  129. * @default text.content
  130. */
  131. textColor?: string;
  132. /**
  133. * 禁用状态下文字颜色
  134. * @default text.second
  135. */
  136. disabledTextColor?: string;
  137. /**
  138. * 自定义文字样式
  139. */
  140. textStyle?: TextStyle;
  141. /**
  142. * 自定义样式
  143. */
  144. innerStyle?: ViewStyle;
  145. }
  146. const props = withDefaults(defineProps<CheckBoxProps>(), {
  147. modelValue: false,
  148. shape: () => propGetThemeVar('CheckBoxShape', 'square'),
  149. block: false,
  150. checkPosition: () => propGetThemeVar('CheckBoxCheckPosition', 'left'),
  151. borderColor: () => propGetThemeVar('CheckBoxBorderColor', 'border.input'),
  152. checkColor: () => propGetThemeVar('CheckBoxCheckColor', 'white'),
  153. textColor: () => propGetThemeVar('CheckBoxTextColor', 'text.content'),
  154. disabledTextColor: () => propGetThemeVar('CheckBoxDisabledTextColor', 'text.second'),
  155. color: () => propGetThemeVar('CheckBoxColor', 'primary'),
  156. checkSize: () => propGetThemeVar('CheckBoxCheckSize', 36),
  157. activeOpacity: () => propGetThemeVar('CheckBoxActiveOpacity', 0.75),
  158. disabled: false,
  159. icon: 'check-mark',
  160. });
  161. const emit = defineEmits<{
  162. (e: 'update:modelValue', value: boolean): void;
  163. }>();
  164. const themeContext = useTheme();
  165. const themeStyles = themeContext.useThemeStyles({
  166. checkBox: {
  167. alignSelf: 'flex-start',
  168. marginHorizontal: DynamicSize('CheckBoxMarginHorizontal', 4),
  169. },
  170. checkBoxFull: {
  171. alignSelf: 'stretch',
  172. width: '100%',
  173. justifyContent: 'space-between',
  174. marginHorizontal: DynamicSize('CheckBoxMarginHorizontal', 4),
  175. },
  176. check: {
  177. alignSelf: 'flex-start',
  178. alignItems: 'center',
  179. justifyContent: 'center',
  180. },
  181. checkText: {
  182. fontSize: DynamicSize('CheckBoxTextFontSize', 28),
  183. },
  184. });
  185. const groupContext = inject<CheckBoxGroupContextInfo>('checkBoxGroupContext', null as any);
  186. const cellContext = useCellContext();
  187. const disabled = computed(() => props.disabled === true || groupContext?.disabled.value);
  188. watch(() => [ props.name, props.disabled ], () => {
  189. if (props.name)
  190. groupContext?.onAddItem(props.name, props.disabled);
  191. }, { immediate: true })
  192. const {
  193. value,
  194. updateValue,
  195. } = useFieldChildValueInjector(
  196. toRef(props, 'modelValue'),
  197. (v) => emit('update:modelValue', v),
  198. groupContext ? {
  199. getValue: () => groupContext!.value.value && groupContext.value.value.indexOf(props.name ?? '') >= 0,
  200. updateValue: (v) => groupContext!.onValueChange(props.name, !value.value),
  201. } : undefined,
  202. );
  203. function switchOn() {
  204. if (props.disabled)
  205. return;
  206. updateValue(!value.value);
  207. }
  208. onMounted(() => {
  209. if (cellContext)
  210. cellContext.setOnClickListener(() => switchOn());
  211. })
  212. defineOptions({
  213. options: {
  214. styleIsolation: "shared",
  215. virtualHost: true,
  216. }
  217. })
  218. </script>