sard-uniapp 1.22.2 → 1.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/components/cascader/README.md +22 -15
  3. package/components/cascader/cascader.d.ts +4 -4
  4. package/components/cascader/cascader.vue +81 -70
  5. package/components/cascader/common.d.ts +6 -5
  6. package/components/cascader/common.js +23 -7
  7. package/components/cascader-input/cascader-input.vue +4 -2
  8. package/components/cascader-popout/cascader-popout.vue +5 -3
  9. package/components/config/index.d.ts +1 -1
  10. package/components/crop-image/README.md +15 -14
  11. package/components/crop-image/common.d.ts +1 -0
  12. package/components/crop-image/crop-image.vue +4 -1
  13. package/components/crop-image-agent/crop-image-agent.vue +1 -0
  14. package/components/form/README.md +58 -0
  15. package/components/form/form.d.ts +5 -5
  16. package/components/form/form.vue +6 -115
  17. package/components/form/index.d.ts +1 -0
  18. package/components/form/index.js +1 -0
  19. package/components/form/useForm.d.ts +9 -0
  20. package/components/form/useForm.js +97 -0
  21. package/components/form-item/form-item.d.ts +2 -2
  22. package/components/form-item/form-item.vue +21 -236
  23. package/components/form-item/useFormItem.d.ts +21 -0
  24. package/components/form-item/useFormItem.js +206 -0
  25. package/components/form-item-plain/form-item-plain.d.ts +20 -0
  26. package/components/form-item-plain/form-item-plain.vue +87 -0
  27. package/components/form-plain/common.d.ts +27 -0
  28. package/components/form-plain/common.js +1 -0
  29. package/components/form-plain/form-plain.d.ts +23 -0
  30. package/components/form-plain/form-plain.vue +67 -0
  31. package/components/form-plain/index.d.ts +1 -0
  32. package/components/form-plain/index.js +1 -0
  33. package/components/rate/README.md +21 -21
  34. package/components/rate/rate.vue +4 -1
  35. package/components/status-bar/README.md +1 -1
  36. package/global.d.ts +2 -0
  37. package/index.d.ts +1 -0
  38. package/index.js +1 -0
  39. package/package.json +2 -2
  40. package/utils/dom.d.ts +1 -1
  41. package/utils/dom.js +8 -5
  42. package/utils/is.d.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## [1.23.1](https://github.com/sutras/sard-uniapp/compare/v1.23.0...v1.23.1) (2025-07-28)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * 修复 rate 清空问题 ([ac43638](https://github.com/sutras/sard-uniapp/commit/ac43638b3802d759221df5b65cb36c71c21a50ef))
7
+
8
+
9
+
10
+ # [1.23.0](https://github.com/sutras/sard-uniapp/compare/v1.22.2...v1.23.0) (2025-07-26)
11
+
12
+
13
+ ### Features
14
+
15
+ * cascader 新增 allLevels 属性 ([d40fc98](https://github.com/sutras/sard-uniapp/commit/d40fc98100553b8ffdbd035640107062433dc33e))
16
+ * crop-image 组件新增 cancel 回调 ([572991f](https://github.com/sutras/sard-uniapp/commit/572991f199c2c10b0a8b50c63356297fad33d715))
17
+ * 新增 FormPlain, FormItemPlain 组件 ([95c6721](https://github.com/sutras/sard-uniapp/commit/95c67215f69c5f5a8f3aec370e53a3b99031232e))
18
+
19
+
20
+
1
21
  ## [1.22.2](https://github.com/sutras/sard-uniapp/compare/v1.22.1...v1.22.2) (2025-07-24)
2
22
 
3
23
 
@@ -47,20 +47,27 @@ import { Cascader } from 'sard'
47
47
 
48
48
  @code('${DEMO_PATH}/cascader/demo/Disabled.vue')
49
49
 
50
+ ### 绑定所有级别的值 <sup>1.23+</sup>
51
+
52
+ 如果要绑定所有级别的值,即绑定数组值,而不单单是最后一级,可以使用 `all-levels` 属性。
53
+
54
+ @code('${DEMO_PATH}/cascader/demo/AllLevels.vue')
55
+
50
56
  ## API
51
57
 
52
58
  ### CascaderProps
53
59
 
54
- | 属性 | 描述 | 类型 | 默认值 |
55
- | --------------------------------- | ------------------------- | ---------------------------------- | ---------------- |
56
- | root-class | 组件根元素类名 | string | - |
57
- | root-style | 组件根元素样式 | StyleValue | - |
58
- | model-value (v-model) | 选中项的值 | string \| number | - |
59
- | options | 可选项数据源 | CascaderOption[] | [] |
60
- | field-keys | 自定义 `options` 中的字段 | CascaderFieldKeys | defaultFieldKeys |
61
- | hint-text | 未选中时的提示文案 | string | '请选择' |
62
- | label-render | 自定义可选项渲染 | (option: CascaderOption) => string | - |
63
- | change-on-select <sup>1.14+</sup> | 点击每级选项都会触发变化 | boolean | false |
60
+ | 属性 | 描述 | 类型 | 默认值 |
61
+ | --------------------------------- | ---------------------------------------- | ---------------------------------------- | ---------------- |
62
+ | root-class | 组件根元素类名 | string | - |
63
+ | root-style | 组件根元素样式 | StyleValue | - |
64
+ | model-value (v-model) | 选中项的值 | string \| number \| (string \| number)[] | - |
65
+ | options | 可选项数据源 | CascaderOption[] | [] |
66
+ | field-keys | 自定义 `options` 中的字段 | CascaderFieldKeys | defaultFieldKeys |
67
+ | hint-text | 未选中时的提示文案 | string | '请选择' |
68
+ | label-render | 自定义可选项渲染 | (option: CascaderOption) => string | - |
69
+ | change-on-select <sup>1.14+</sup> | 点击每级选项都会触发变化 | boolean | false |
70
+ | all-levels <sup>1.23+</sup> | 是否绑定所有级别的值,而不单单是最后一级 | boolean | false |
64
71
 
65
72
  ### CascaderSlots
66
73
 
@@ -70,11 +77,11 @@ import { Cascader } from 'sard'
70
77
 
71
78
  ### CascaderEmits
72
79
 
73
- | 事件 | 描述 | 类型 |
74
- | ------------------------ | ---------------------- | -------------------------------------------------------------------- |
75
- | update:model-value | 全部选项选择完成后触发 | (value: string \| number, selectedOptions: CascaderOption[]) => void |
76
- | change <sup>1.9.2+</sup> | 全部选项选择完成后触发 | (value: string \| number, selectedOptions: CascaderOption[]) => void |
77
- | select | 选中某一项时触发 | (option: CascaderOption, tabIndex: number) => void |
80
+ | 事件 | 描述 | 类型 |
81
+ | ------------------------ | ---------------------- | -------------------------------------------------------------------------------------------- |
82
+ | update:model-value | 全部选项选择完成后触发 | (value: string \| number \| (string \| number)[], selectedOptions: CascaderOption[]) => void |
83
+ | change <sup>1.9.2+</sup> | 全部选项选择完成后触发 | (value: string \| number \| (string \| number)[], selectedOptions: CascaderOption[]) => void |
84
+ | select | 选中某一项时触发 | (option: CascaderOption, tabIndex: number) => void |
78
85
 
79
86
  ### CascaderOption
80
87
 
@@ -1,12 +1,12 @@
1
1
  import { type CascaderProps, type CascaderSlots, type CascaderOption } from './common';
2
2
  declare function __VLS_template(): Readonly<CascaderSlots> & CascaderSlots;
3
3
  declare const __VLS_component: import("vue").DefineComponent<CascaderProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
4
- "update:model-value": (value: string | number, selectedOptions: any[]) => any;
5
- change: (value: string | number, selectedOptions: any[]) => any;
4
+ "update:model-value": (value: string | number | (string | number)[], selectedOptions: any[]) => any;
5
+ change: (value: string | number | (string | number)[], selectedOptions: any[]) => any;
6
6
  select: (option: any, tabIndex: number) => any;
7
7
  }, string, import("vue").PublicProps, Readonly<CascaderProps> & Readonly<{
8
- "onUpdate:model-value"?: ((value: string | number, selectedOptions: any[]) => any) | undefined;
9
- onChange?: ((value: string | number, selectedOptions: any[]) => any) | undefined;
8
+ "onUpdate:model-value"?: ((value: string | number | (string | number)[], selectedOptions: any[]) => any) | undefined;
9
+ onChange?: ((value: string | number | (string | number)[], selectedOptions: any[]) => any) | undefined;
10
10
  onSelect?: ((option: any, tabIndex: number) => any) | undefined;
11
11
  }>, {
12
12
  options: CascaderOption[];
@@ -1,28 +1,28 @@
1
1
  <template>
2
2
  <view :class="cascaderClass" :style="cascaderStyle">
3
- <sar-tabs scrollable v-model:current="tabsCurrent" :list="tabsList" />
3
+ <sar-tabs scrollable v-model:current="currentTab" :list="tabList" />
4
4
 
5
- <slot name="top" :tab-index="tabsCurrent"></slot>
5
+ <slot name="top" :tab-index="currentTab"></slot>
6
6
 
7
7
  <view :class="bem.e('container')">
8
8
  <view
9
9
  :class="bem.e('wrapper')"
10
10
  :style="
11
11
  stringifyStyle({
12
- transform: `translateX(${-Number(tabsCurrent) * 100}%)`,
12
+ transform: `translateX(${-Number(currentTab) * 100}%)`,
13
13
  transitionDuration: renderedPane ? null : '0s',
14
14
  })
15
15
  "
16
16
  >
17
17
  <view
18
- v-for="(tab, tabIndex) in tabs"
19
- :key="tabIndex"
18
+ v-for="(panel, panelIndex) in panels"
19
+ :key="panelIndex"
20
20
  :class="bem.e('pane')"
21
21
  >
22
22
  <view :class="bem.e('options')">
23
23
  <scroll-view scroll-y trap-scroll :class="bem.e('scroll')">
24
24
  <view
25
- v-for="(option, optionIndex) in tab.options"
25
+ v-for="(option, optionIndex) in panel.options"
26
26
  :key="optionIndex"
27
27
  :class="
28
28
  classNames(
@@ -30,8 +30,8 @@
30
30
  bem.em(
31
31
  'option',
32
32
  'selected',
33
- tab.selected &&
34
- tab.selected[mergedFieldKeys.value] ===
33
+ panel.selected &&
34
+ panel.selected[mergedFieldKeys.value] ===
35
35
  option[mergedFieldKeys.value],
36
36
  ),
37
37
  bem.em(
@@ -41,7 +41,7 @@
41
41
  ),
42
42
  )
43
43
  "
44
- @click="onOptionClick(option, tabIndex)"
44
+ @click="onOptionClick(option, panelIndex)"
45
45
  >
46
46
  <view :class="bem.e('option-label')">
47
47
  {{
@@ -59,7 +59,7 @@
59
59
  :class="
60
60
  classNames(
61
61
  bem.e('loading-wrapper'),
62
- bem.em('loading-wrapper', 'show', tab.options.length === 0),
62
+ bem.em('loading-wrapper', 'show', panel.options.length === 0),
63
63
  )
64
64
  "
65
65
  >
@@ -81,7 +81,8 @@ import {
81
81
  classNames,
82
82
  stringifyStyle,
83
83
  createBem,
84
- isEmptyBinding
84
+ isEmptyBinding,
85
+ isEmptyArray
85
86
  } from "../../utils";
86
87
  import { useTranslate } from "../locale";
87
88
  import SarTabs from "../tabs/tabs.vue";
@@ -95,14 +96,15 @@ import {
95
96
  /**
96
97
  * @property {string} rootClass 组件根元素类名,默认值:-。
97
98
  * @property {StyleValue} rootStyle 组件根元素样式,默认值:-。
98
- * @property {string | number} modelValue 选中项的值,默认值:-。
99
+ * @property {string | number | (string | number)[]} modelValue 选中项的值,默认值:-。
99
100
  * @property {CascaderOption[]} options 可选项数据源,默认值:[]。
100
101
  * @property {CascaderFieldKeys} fieldKeys 自定义 `options` 中的字段,默认值:defaultFieldKeys。
101
102
  * @property {string} hintText 未选中时的提示文案,默认值:'请选择'。
102
103
  * @property {(option: CascaderOption) => string} labelRender 自定义可选项渲染,默认值:-。
103
104
  * @property {boolean} changeOnSelect 点击每级选项都会触发变化,默认值:false。
104
- * @event {(value: string | number, selectedOptions: CascaderOption[]) => void} update 全部选项选择完成后触发
105
- * @event {(value: string | number, selectedOptions: CascaderOption[]) => void} change 全部选项选择完成后触发
105
+ * @property {boolean} allLevels 是否绑定所有级别的值,而不单单是最后一级,默认值:false。
106
+ * @event {(value: string | number | (string | number)[], selectedOptions: CascaderOption[]) => void} update 全部选项选择完成后触发
107
+ * @event {(value: string | number | (string | number)[], selectedOptions: CascaderOption[]) => void} change 全部选项选择完成后触发
106
108
  * @event {(option: CascaderOption, tabIndex: number) => void} select 选中某一项时触发
107
109
  */
108
110
  export default _defineComponent({
@@ -121,12 +123,13 @@ export default _defineComponent({
121
123
  props: _mergeDefaults({
122
124
  rootStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
123
125
  rootClass: { type: String, required: false },
124
- modelValue: { type: [String, Number], required: false },
126
+ modelValue: { type: [String, Number, Array], required: false },
125
127
  options: { type: Array, required: false },
126
128
  fieldKeys: { type: Object, required: false },
127
129
  hintText: { type: String, required: false },
128
130
  labelRender: { type: Function, required: false },
129
- changeOnSelect: { type: Boolean, required: false }
131
+ changeOnSelect: { type: Boolean, required: false },
132
+ allLevels: { type: Boolean, required: false }
130
133
  }, defaultCascaderProps),
131
134
  emits: ["update:model-value", "change", "select"],
132
135
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -135,10 +138,10 @@ export default _defineComponent({
135
138
  const emit = __emit;
136
139
  const bem = createBem("cascader");
137
140
  const { t } = useTranslate("cascader");
138
- const updateTabs = () => {
139
- let nextTabs;
140
- if (isEmptyBinding(tempValue)) {
141
- nextTabs = [
141
+ const updatePanels = () => {
142
+ let nextPanels;
143
+ if (isEmptyBinding(tempValue) || isEmptyArray(tempValue)) {
144
+ nextPanels = [
142
145
  {
143
146
  options: props.options || [],
144
147
  selected: null
@@ -150,24 +153,24 @@ export default _defineComponent({
150
153
  tempValue,
151
154
  mergedFieldKeys.value
152
155
  );
153
- if (selectedOptions) {
156
+ if (selectedOptions && selectedOptions.length > 0) {
154
157
  let nextOptions = props.options;
155
- nextTabs = selectedOptions.map((option) => {
156
- const tab = {
157
- options: nextOptions,
158
+ nextPanels = selectedOptions.map((option) => {
159
+ const panel = {
160
+ options: nextOptions || [],
158
161
  selected: option
159
162
  };
160
163
  nextOptions = option[mergedFieldKeys.value.children];
161
- return tab;
164
+ return panel;
162
165
  });
163
166
  if (nextOptions) {
164
- nextTabs.push({
167
+ nextPanels.push({
165
168
  options: nextOptions,
166
169
  selected: null
167
170
  });
168
171
  }
169
172
  } else {
170
- nextTabs = [
173
+ nextPanels = [
171
174
  {
172
175
  options: props.options || [],
173
176
  selected: null
@@ -175,47 +178,47 @@ export default _defineComponent({
175
178
  ];
176
179
  }
177
180
  }
178
- if (nextTabs) {
179
- tabs.value = nextTabs;
180
- tabsCurrent.value = nextTabs.length - 1;
181
- if (!renderedPane.value) {
182
- setTimeout(() => {
183
- renderedPane.value = true;
184
- }, 30);
185
- }
181
+ panels.value = nextPanels;
182
+ currentTab.value = nextPanels.length - 1;
183
+ if (!renderedPane.value) {
184
+ setTimeout(() => {
185
+ renderedPane.value = true;
186
+ }, 30);
186
187
  }
187
188
  };
188
189
  const isLastOption = (option) => {
189
190
  return !Array.isArray(option[mergedFieldKeys.value.children]);
190
191
  };
191
- const onOptionClick = (option, tabIndex) => {
192
+ const onOptionClick = (option, panelIndex) => {
192
193
  if (option.disabled) {
193
194
  return;
194
195
  }
195
- let nextTabs = tabs.value.slice();
196
- nextTabs[tabIndex].selected = option;
197
- const selectBack = tabIndex < nextTabs.length - 1;
196
+ let nextPanels = panels.value.slice();
197
+ nextPanels[panelIndex].selected = option;
198
+ const selectBack = panelIndex < nextPanels.length - 1;
198
199
  if (selectBack) {
199
- nextTabs = nextTabs.slice(0, tabIndex + 1);
200
+ nextPanels = nextPanels.slice(0, panelIndex + 1);
200
201
  }
201
202
  const isLast = isLastOption(option);
202
203
  if (!isLast) {
203
- const nextTab = {
204
+ const nextPanel = {
204
205
  options: option[mergedFieldKeys.value.children],
205
206
  selected: null
206
207
  };
207
- nextTabs.push(nextTab);
208
+ nextPanels.push(nextPanel);
209
+ }
210
+ currentTab.value = isLast ? panelIndex : nextPanels.length - 1;
211
+ if (props.allLevels) {
212
+ tempValue = nextPanels.map((panel) => panel.selected).filter(Boolean).map((option2) => option2[mergedFieldKeys.value.value]);
213
+ } else {
214
+ tempValue = option[mergedFieldKeys.value.value];
208
215
  }
209
- tabsCurrent.value = isLast ? tabIndex : nextTabs.length - 1;
210
- tempValue = option[mergedFieldKeys.value.value];
211
- tabs.value = nextTabs;
212
- emit("select", option, tabIndex);
216
+ panels.value = nextPanels;
217
+ emit("select", option, panelIndex);
213
218
  if (isLast || props.changeOnSelect) {
214
- const nextValue = option[mergedFieldKeys.value.value];
215
- innerValue.value = nextValue;
216
- const selectedOptions = nextTabs.map((tab) => tab.selected).filter(Boolean);
217
- emit("update:model-value", nextValue, selectedOptions);
218
- emit("change", nextValue, selectedOptions);
219
+ const selectedOptions = nextPanels.map((panel) => panel.selected).filter(Boolean);
220
+ emit("update:model-value", tempValue, selectedOptions);
221
+ emit("change", tempValue, selectedOptions);
219
222
  }
220
223
  };
221
224
  const innerPaceholder = computed(() => {
@@ -228,39 +231,47 @@ export default _defineComponent({
228
231
  props.fieldKeys
229
232
  );
230
233
  });
231
- const innerValue = ref(props.modelValue);
232
- let tempValue = innerValue.value;
233
- const tabsCurrent = ref(0);
234
+ let tempValue = props.modelValue;
235
+ const currentTab = ref(0);
234
236
  const renderedPane = ref(false);
235
- const tabs = ref([]);
236
- const tabsList = computed(() => {
237
- return tabs.value.map((tab) => {
238
- const { selected } = tab;
239
- const tabLabel = selected ? selected[mergedFieldKeys.value.label] : innerPaceholder.value;
237
+ const panels = ref([]);
238
+ const tabList = computed(() => {
239
+ return panels.value.map((panel) => {
240
+ const { selected } = panel;
241
+ const label = selected ? selected[mergedFieldKeys.value.label] : innerPaceholder.value;
240
242
  return {
241
- title: tabLabel
243
+ title: label
242
244
  };
243
245
  });
244
246
  });
245
247
  watch(
246
248
  () => props.modelValue,
247
249
  () => {
248
- innerValue.value = props.modelValue;
249
- if (!isEmptyBinding(props.modelValue)) {
250
- if (tabs.value.some(
251
- (tab) => tab.selected?.[mergedFieldKeys.value.value] === props.modelValue
252
- )) {
253
- return;
250
+ if (Array.isArray(props.modelValue)) {
251
+ if (props.modelValue.length > 0) {
252
+ if (props.modelValue.every(
253
+ (item, index) => panels.value[index].selected?.[mergedFieldKeys.value.value] === item
254
+ )) {
255
+ return;
256
+ }
257
+ }
258
+ } else {
259
+ if (!isEmptyBinding(props.modelValue)) {
260
+ if (panels.value.some(
261
+ (panel) => panel.selected?.[mergedFieldKeys.value.value] === props.modelValue
262
+ )) {
263
+ return;
264
+ }
254
265
  }
255
266
  }
256
267
  tempValue = props.modelValue;
257
- updateTabs();
268
+ updatePanels();
258
269
  }
259
270
  );
260
271
  watch(
261
272
  () => props.options,
262
273
  () => {
263
- updateTabs();
274
+ updatePanels();
264
275
  },
265
276
  {
266
277
  immediate: true
@@ -272,11 +283,11 @@ export default _defineComponent({
272
283
  const cascaderStyle = computed(() => {
273
284
  return stringifyStyle(props.rootStyle);
274
285
  });
275
- const __returned__ = { props, emit, bem, t, updateTabs, isLastOption, onOptionClick, innerPaceholder, mergedFieldKeys, innerValue, get tempValue() {
286
+ const __returned__ = { props, emit, bem, t, updatePanels, isLastOption, onOptionClick, innerPaceholder, mergedFieldKeys, get tempValue() {
276
287
  return tempValue;
277
288
  }, set tempValue(v) {
278
289
  tempValue = v;
279
- }, tabsCurrent, renderedPane, tabs, tabsList, cascaderClass, cascaderStyle, get classNames() {
290
+ }, currentTab, renderedPane, panels, tabList, cascaderClass, cascaderStyle, get classNames() {
280
291
  return classNames;
281
292
  }, get stringifyStyle() {
282
293
  return stringifyStyle;
@@ -15,12 +15,13 @@ export interface CascaderOption {
15
15
  export interface CascaderProps {
16
16
  rootStyle?: StyleValue;
17
17
  rootClass?: string;
18
- modelValue?: string | number;
18
+ modelValue?: string | number | (string | number)[];
19
19
  options?: CascaderOption[];
20
20
  fieldKeys?: CascaderFieldKeys;
21
21
  hintText?: string;
22
22
  labelRender?: (option: CascaderOption) => string;
23
23
  changeOnSelect?: boolean;
24
+ allLevels?: boolean;
24
25
  }
25
26
  export declare const defaultCascaderProps: {
26
27
  options: () => never[];
@@ -31,13 +32,13 @@ export interface CascaderSlots {
31
32
  }): any;
32
33
  }
33
34
  export interface CascaderEmits {
34
- (e: 'update:model-value', value: string | number, selectedOptions: any[]): void;
35
- (e: 'change', value: string | number, selectedOptions: any[]): void;
35
+ (e: 'update:model-value', value: string | number | (string | number)[], selectedOptions: any[]): void;
36
+ (e: 'change', value: string | number | (string | number)[], selectedOptions: any[]): void;
36
37
  (e: 'select', option: any, tabIndex: number): void;
37
38
  }
38
- export interface CascaderTab {
39
+ export interface CascaderPanel {
39
40
  options: CascaderOption[];
40
41
  selected: CascaderOption | null;
41
42
  }
42
43
  export declare const defaultFieldKeys: CascaderFieldKeys;
43
- export declare function getSelectedOptionsByValue(options: CascaderOption[], value: string | number, fieldKeys: Required<CascaderFieldKeys>): CascaderOption[] | undefined;
44
+ export declare function getSelectedOptionsByValue(options: CascaderOption[], value: string | number | (string | number)[], fieldKeys: Required<CascaderFieldKeys>): CascaderOption[] | undefined;
@@ -8,14 +8,30 @@ export const defaultFieldKeys = {
8
8
  children: 'children',
9
9
  };
10
10
  export function getSelectedOptionsByValue(options, value, fieldKeys) {
11
- for (const option of options) {
12
- if (option[fieldKeys.value] === value) {
13
- return [option];
11
+ if (Array.isArray(value)) {
12
+ const selectedOptions = [];
13
+ let list = options;
14
+ for (const item of value) {
15
+ const option = list.find((option) => option[fieldKeys.value] === item);
16
+ if (!option)
17
+ break;
18
+ selectedOptions.push(option);
19
+ list = option[fieldKeys.children];
20
+ if (!Array.isArray(list))
21
+ break;
14
22
  }
15
- if (Array.isArray(option[fieldKeys.children])) {
16
- const selectedOptions = getSelectedOptionsByValue(option[fieldKeys.children], value, fieldKeys);
17
- if (selectedOptions) {
18
- return [option, ...selectedOptions];
23
+ return selectedOptions;
24
+ }
25
+ else {
26
+ for (const option of options) {
27
+ if (option[fieldKeys.value] === value) {
28
+ return [option];
29
+ }
30
+ if (Array.isArray(option[fieldKeys.children])) {
31
+ const selectedOptions = getSelectedOptionsByValue(option[fieldKeys.children], value, fieldKeys);
32
+ if (selectedOptions) {
33
+ return [option, ...selectedOptions];
34
+ }
19
35
  }
20
36
  }
21
37
  }
@@ -58,12 +58,13 @@ import {
58
58
  /**
59
59
  * @property {string} rootClass 弹出式输入框根元素类名,默认值:-。
60
60
  * @property {StyleValue} rootStyle 弹出式输入框根元素样式,默认值:-。
61
- * @property {string | number} modelValue 选中项的值,默认值:-。
61
+ * @property {string | number | (string | number)[]} modelValue 选中项的值,默认值:-。
62
62
  * @property {CascaderOption[]} options 可选项数据源,默认值:[]。
63
63
  * @property {CascaderFieldKeys} fieldKeys 自定义 `options` 中的字段,默认值:defaultFieldKeys。
64
64
  * @property {string} hintText 未选中时的提示文案,默认值:'请选择'。
65
65
  * @property {(option: CascaderOption) => string} labelRender 自定义可选项渲染,默认值:-。
66
66
  * @property {boolean} changeOnSelect 点击每级选项都会触发变化,默认值:false。
67
+ * @property {boolean} allLevels 是否绑定所有级别的值,而不单单是最后一级,默认值:false。
67
68
  * @property {string} popoutClass 弹窗框根元素类名,默认值:-。
68
69
  * @property {StyleValue} popoutStyle 弹窗框根元素样式,默认值:-。
69
70
  * @property {boolean} visible 是否显示弹出框,默认值:-。
@@ -115,12 +116,13 @@ export default _defineComponent({
115
116
  popoutStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
116
117
  rootStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
117
118
  rootClass: { type: String, required: false },
118
- modelValue: { type: [String, Number], required: false },
119
+ modelValue: { type: [String, Number, Array], required: false },
119
120
  options: { type: Array, required: false },
120
121
  fieldKeys: { type: Object, required: false },
121
122
  hintText: { type: String, required: false },
122
123
  labelRender: { type: Function, required: false },
123
124
  changeOnSelect: { type: Boolean, required: false },
125
+ allLevels: { type: Boolean, required: false },
124
126
  placeholder: { type: String, required: false },
125
127
  readonly: { type: Boolean, required: false },
126
128
  disabled: { type: Boolean, required: false },
@@ -40,12 +40,13 @@ import { useFormPopout } from "../../use";
40
40
  /**
41
41
  * @property {string} rootClass 组件根元素类名,默认值:-。
42
42
  * @property {StyleValue} rootStyle 组件根元素样式,默认值:-。
43
- * @property {string | number} modelValue 选中项的值,默认值:-。
43
+ * @property {string | number | (string | number)[]} modelValue 选中项的值,默认值:-。
44
44
  * @property {CascaderOption[]} options 可选项数据源,默认值:[]。
45
45
  * @property {CascaderFieldKeys} fieldKeys 自定义 `options` 中的字段,默认值:defaultFieldKeys。
46
46
  * @property {string} hintText 未选中时的提示文案,默认值:'请选择'。
47
47
  * @property {(option: CascaderOption) => string} labelRender 自定义可选项渲染,默认值:-。
48
48
  * @property {boolean} changeOnSelect 点击每级选项都会触发变化,默认值:false。
49
+ * @property {boolean} allLevels 是否绑定所有级别的值,而不单单是最后一级,默认值:false。
49
50
  * @property {string} popoutClass 弹窗框根元素类名,默认值:-。
50
51
  * @property {StyleValue} popoutStyle 弹窗框根元素样式,默认值:-。
51
52
  * @property {boolean} visible 是否显示弹出框,默认值:-。
@@ -87,12 +88,13 @@ export default _defineComponent({
87
88
  popoutStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
88
89
  rootStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
89
90
  rootClass: { type: String, required: false },
90
- modelValue: { type: [String, Number], required: false },
91
+ modelValue: { type: [String, Number, Array], required: false },
91
92
  options: { type: Array, required: false },
92
93
  fieldKeys: { type: Object, required: false },
93
94
  hintText: { type: String, required: false },
94
95
  labelRender: { type: Function, required: false },
95
- changeOnSelect: { type: Boolean, required: false }
96
+ changeOnSelect: { type: Boolean, required: false },
97
+ allLevels: { type: Boolean, required: false }
96
98
  }, defaultCascaderPopoutProps),
97
99
  emits: ["update:visible", "update:model-value", "change", "select", "confirm", "before-enter", "enter", "after-enter", "enter-cancelled", "before-leave", "leave", "after-leave", "leave-cancelled", "visible-hook"],
98
100
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -9,6 +9,7 @@ import { type CheckboxInputProps } from '../checkbox-input';
9
9
  import { type DatetimePickerInputProps } from '../datetime-picker-input';
10
10
  import { type DatetimeRangePickerInputProps } from '../datetime-range-picker-input';
11
11
  import { type DialogProps } from '../dialog';
12
+ import { type DividerProps } from '../divider';
12
13
  import { type DropdownProps } from '../dropdown';
13
14
  import { type FloatingBubbleProps } from '../floating-bubble';
14
15
  import { type FormProps } from '../form';
@@ -42,7 +43,6 @@ import { type TagProps } from '../tag';
42
43
  import { type ToastProps } from '../toast';
43
44
  import { type TreeProps } from '../tree';
44
45
  import { type UploadPreviewProps, type UploadProps } from '../upload';
45
- import { type DividerProps } from '../divider';
46
46
  type DeepPartial<T> = {
47
47
  [P in keyof T]?: T[P] extends Record<any, any> ? DeepPartial<T[P]> : T[P];
48
48
  };
@@ -50,20 +50,21 @@ import { cropImage } from 'sard-uniapp'
50
50
 
51
51
  ### CropImageProps
52
52
 
53
- | 属性 | 描述 | 类型 | 默认值 |
54
- | ----------- | ------------------------------------------------------ | ----------------------------------------- | ------ |
55
- | root-class | 组件根元素类名 | string | - |
56
- | root-style | 组件根元素样式 | StyleValue | - |
57
- | visible | 是否显示裁剪弹框 | boolean | false |
58
- | src | 要裁剪的图片 | string | false |
59
- | crop-scale | 裁剪的比例 | string | '1:1' |
60
- | type | 导出图片类型 | 'png' \| 'jpg' | 'png' |
61
- | quality | 导出图片的质量 | number | 0.92 |
62
- | duration | 弹窗显隐过渡时间(单位 ms) | number | 150 |
63
- | success | 裁剪成功回调 | (filePath: string) => void | - |
64
- | fail | 裁剪成功回调 | (err: any) => void | - |
65
- | complete | 裁剪成功或失败回调 | () => void | - |
66
- | before-crop | 裁剪前回调,可以修改裁剪的尺寸;接收宽高,返回缩放比例 | (width: number, height: number) => number | - |
53
+ | 属性 | 描述 | 类型 | 默认值 |
54
+ | ----------------------- | ------------------------------------------------------ | ----------------------------------------- | ------ |
55
+ | root-class | 组件根元素类名 | string | - |
56
+ | root-style | 组件根元素样式 | StyleValue | - |
57
+ | visible | 是否显示裁剪弹框 | boolean | false |
58
+ | src | 要裁剪的图片 | string | false |
59
+ | crop-scale | 裁剪的比例 | string | '1:1' |
60
+ | type | 导出图片类型 | 'png' \| 'jpg' | 'png' |
61
+ | quality | 导出图片的质量 | number | 0.92 |
62
+ | duration | 弹窗显隐过渡时间(单位 ms) | number | 150 |
63
+ | success | 裁剪成功回调 | (filePath: string) => void | - |
64
+ | fail | 裁剪失败回调 | (err: any) => void | - |
65
+ | complete | 裁剪成功或失败回调 | () => void | - |
66
+ | cancel <sup>1.23+</sup> | 点击取消按钮时触发 | () => void | - |
67
+ | before-crop | 裁剪前回调,可以修改裁剪的尺寸;接收宽高,返回缩放比例 | (width: number, height: number) => number | - |
67
68
 
68
69
  ### CropImageEmits
69
70
 
@@ -12,6 +12,7 @@ export interface CropImageProps {
12
12
  success?: (filePath: string) => void;
13
13
  fail?: (err: any) => void;
14
14
  complete?: () => void;
15
+ cancel?: () => void;
15
16
  id?: string;
16
17
  beforeCrop?: (width: number, height: number) => number;
17
18
  cancelText?: string;
@@ -129,8 +129,9 @@ const maxScale = 5;
129
129
  * @property {number} quality 导出图片的质量,默认值:0.92。
130
130
  * @property {number} duration 弹窗显隐过渡时间(单位 ms),默认值:150。
131
131
  * @property {(filePath: string) => void} success 裁剪成功回调,默认值:-。
132
- * @property {(err: any) => void} fail 裁剪成功回调,默认值:-。
132
+ * @property {(err: any) => void} fail 裁剪失败回调,默认值:-。
133
133
  * @property {() => void} complete 裁剪成功或失败回调,默认值:-。
134
+ * @property {() => void} cancel 点击取消按钮时触发,默认值:-。
134
135
  * @property {(width: number, height: number) => number} beforeCrop 裁剪前回调,可以修改裁剪的尺寸;接收宽高,返回缩放比例,默认值:-。
135
136
  * @event {(visible: boolean) => void} update 弹出框显隐时触发
136
137
  * @event {(name: TransitionHookName) => void} visible-hook 入场/退场动画状态改变时触发
@@ -169,6 +170,7 @@ export default _defineComponent({
169
170
  success: { type: Function, required: false },
170
171
  fail: { type: Function, required: false },
171
172
  complete: { type: Function, required: false },
173
+ cancel: { type: Function, required: false },
172
174
  id: { type: String, required: false },
173
175
  beforeCrop: { type: Function, required: false },
174
176
  cancelText: { type: String, required: false },
@@ -643,6 +645,7 @@ export default _defineComponent({
643
645
  });
644
646
  };
645
647
  const onCancel = () => {
648
+ props.cancel?.();
646
649
  close();
647
650
  };
648
651
  const onReset = () => {
@@ -35,6 +35,7 @@ export default _defineComponent({
35
35
  success: { type: Function, required: false },
36
36
  fail: { type: Function, required: false },
37
37
  complete: { type: Function, required: false },
38
+ cancel: { type: Function, required: false },
38
39
  beforeCrop: { type: Function, required: false },
39
40
  cancelText: { type: String, required: false },
40
41
  confirmText: { type: String, required: false }