@puresnake/snake-ui 0.0.0-stage → 0.0.2
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.
- package/LICENSE +21 -0
- package/changelog.md +83 -0
- package/components/snake-activity-list/snake-activity-list.vue +365 -0
- package/components/snake-activity-list/types.ts +29 -0
- package/components/snake-auxiliary-segmentation/snake-auxiliary-segmentation.vue +44 -0
- package/components/snake-auxiliary-segmentation/types.ts +5 -0
- package/components/snake-button/snake-button.vue +357 -0
- package/components/snake-button/types.ts +103 -0
- package/components/snake-button-sort/snake-button-sort.vue +72 -0
- package/components/snake-button-sort/types.ts +22 -0
- package/components/snake-calendar/snake-calendar.vue +998 -0
- package/components/snake-calendar/types.ts +189 -0
- package/components/snake-cell-group/snake-cell-group.vue +55 -0
- package/components/snake-cell-group/types.ts +19 -0
- package/components/snake-cell-item/snake-cell-item.vue +159 -0
- package/components/snake-cell-item/types.ts +66 -0
- package/components/snake-checkbox/snake-checkbox.vue +264 -0
- package/components/snake-checkbox/types.ts +70 -0
- package/components/snake-checkbox-group/snake-checkbox-group.vue +154 -0
- package/components/snake-checkbox-group/types.ts +52 -0
- package/components/snake-cms/blocks/v2/cms-v2-carousel.vue +87 -0
- package/components/snake-cms/blocks/v2/cms-v2-coupon.vue +25 -0
- package/components/snake-cms/blocks/v2/cms-v2-custom.vue +12 -0
- package/components/snake-cms/blocks/v2/cms-v2-divider.vue +33 -0
- package/components/snake-cms/blocks/v2/cms-v2-floatbutton.vue +28 -0
- package/components/snake-cms/blocks/v2/cms-v2-goods-list.vue +150 -0
- package/components/snake-cms/blocks/v2/cms-v2-hotzone.vue +41 -0
- package/components/snake-cms/blocks/v2/cms-v2-images.vue +41 -0
- package/components/snake-cms/blocks/v2/cms-v2-magiccube.vue +93 -0
- package/components/snake-cms/blocks/v2/cms-v2-notice.vue +80 -0
- package/components/snake-cms/blocks/v2/cms-v2-popup.vue +46 -0
- package/components/snake-cms/blocks/v2/cms-v2-richtext.vue +18 -0
- package/components/snake-cms/blocks/v2/cms-v2-search.vue +115 -0
- package/components/snake-cms/blocks/v2/cms-v2-video.vue +25 -0
- package/components/snake-cms/blocks/v2/shared.ts +84 -0
- package/components/snake-cms/snake-cms.vue +409 -0
- package/components/snake-cms/types.ts +50 -0
- package/components/snake-commodity-search/snake-commodity-search.vue +234 -0
- package/components/snake-commodity-search/types.ts +11 -0
- package/components/snake-config-provider/snake-config-provider.vue +61 -0
- package/components/snake-config-provider/types.ts +22 -0
- package/components/snake-count-down/snake-count-down.vue +231 -0
- package/components/snake-count-down/types.ts +103 -0
- package/components/snake-coupon/snake-coupon.vue +209 -0
- package/components/snake-coupon/types.ts +21 -0
- package/components/snake-custom-module/snake-custom-module.vue +25 -0
- package/components/snake-custom-module/types.ts +11 -0
- package/components/snake-drop-menu/snake-drop-menu.vue +123 -0
- package/components/snake-drop-menu/types.ts +95 -0
- package/components/snake-drop-menu-item/snake-drop-menu-item.vue +181 -0
- package/components/snake-drop-menu-item/types.ts +48 -0
- package/components/snake-empty/snake-empty.vue +100 -0
- package/components/snake-empty/types.ts +48 -0
- package/components/snake-filter-sorts/filter-page.vue +695 -0
- package/components/snake-filter-sorts/snake-filter-sorts.vue +185 -0
- package/components/snake-filter-sorts/types.ts +57 -0
- package/components/snake-floating-bubble/snake-floating-bubble.vue +157 -0
- package/components/snake-floating-bubble/types.ts +43 -0
- package/components/snake-follow/snake-follow.vue +18 -0
- package/components/snake-follow/types.ts +2 -0
- package/components/snake-form/snake-form.vue +124 -0
- package/components/snake-form/types.ts +96 -0
- package/components/snake-form-item/snake-form-item.vue +331 -0
- package/components/snake-form-item/types.ts +70 -0
- package/components/snake-goods-list/snake-goods-list.vue +792 -0
- package/components/snake-goods-list/types.ts +55 -0
- package/components/snake-graphic-navigation/snake-graphic-navigation.vue +198 -0
- package/components/snake-graphic-navigation/types.ts +43 -0
- package/components/snake-icon/icon-names.ts +222 -0
- package/components/snake-icon/snake-icon.vue +220 -0
- package/components/snake-icon/types.ts +45 -0
- package/components/snake-image/snake-image.vue +230 -0
- package/components/snake-image/types.ts +70 -0
- package/components/snake-images/snake-images.vue +80 -0
- package/components/snake-images/types.ts +5 -0
- package/components/snake-index-anchor/snake-index-anchor.vue +83 -0
- package/components/snake-index-anchor/types.ts +14 -0
- package/components/snake-index-list/anchor-registry.ts +80 -0
- package/components/snake-index-list/snake-index-list.vue +259 -0
- package/components/snake-index-list/types.ts +115 -0
- package/components/snake-index-list-panel/snake-index-list-panel.vue +277 -0
- package/components/snake-index-list-panel/types.ts +10 -0
- package/components/snake-input/snake-input.vue +225 -0
- package/components/snake-input/types.ts +99 -0
- package/components/snake-jump-applet/snake-jump-applet.vue +99 -0
- package/components/snake-jump-applet/types.ts +17 -0
- package/components/snake-line/snake-line.vue +42 -0
- package/components/snake-line/types.ts +30 -0
- package/components/snake-line-progress/snake-line-progress.vue +105 -0
- package/components/snake-line-progress/types.ts +26 -0
- package/components/snake-link/snake-link.vue +74 -0
- package/components/snake-link/types.ts +30 -0
- package/components/snake-list-switching/components/tree-select/index.vue +156 -0
- package/components/snake-list-switching/snake-list-switching.vue +1285 -0
- package/components/snake-list-switching/types.ts +11 -0
- package/components/snake-loading/snake-loading.vue +241 -0
- package/components/snake-loading/types.ts +34 -0
- package/components/snake-loadmore/snake-loadmore.vue +103 -0
- package/components/snake-loadmore/types.ts +56 -0
- package/components/snake-magic-cube/snake-magic-cube.vue +622 -0
- package/components/snake-magic-cube/types.ts +5 -0
- package/components/snake-modal/snake-modal.vue +434 -0
- package/components/snake-modal/types.ts +71 -0
- package/components/snake-navbar/snake-navbar.vue +194 -0
- package/components/snake-navbar/types.ts +54 -0
- package/components/snake-no-network/snake-no-network.vue +125 -0
- package/components/snake-no-network/types.ts +27 -0
- package/components/snake-notice/snake-notice.vue +44 -0
- package/components/snake-notice/types.ts +5 -0
- package/components/snake-notice-bar/snake-notice-bar.vue +336 -0
- package/components/snake-notice-bar/types.ts +82 -0
- package/components/snake-overlay/snake-overlay.vue +73 -0
- package/components/snake-overlay/types.ts +35 -0
- package/components/snake-page-popup/snake-page-popup.vue +146 -0
- package/components/snake-page-popup/types.ts +28 -0
- package/components/snake-parse/audio/audio.vue +286 -0
- package/components/snake-parse/audio/context.js +11 -0
- package/components/snake-parse/audio/index.js +34 -0
- package/components/snake-parse/node/node.vue +830 -0
- package/components/snake-parse/parser.js +1480 -0
- package/components/snake-parse/snake-parse.vue +548 -0
- package/components/snake-parse/static/app-plus/snake-parse/js/handler.js +109 -0
- package/components/snake-parse/static/app-plus/snake-parse/js/uni.webview.js +0 -0
- package/components/snake-parse/static/app-plus/snake-parse/js/uni.webview.min.js +1 -0
- package/components/snake-parse/static/app-plus/snake-parse/local.html +3 -0
- package/components/snake-parse/style/index.js +132 -0
- package/components/snake-parse/style/parser.js +175 -0
- package/components/snake-parse/types.ts +49 -0
- package/components/snake-picture-ads/snake-picture-ads.vue +292 -0
- package/components/snake-picture-ads/types.ts +5 -0
- package/components/snake-popup/snake-popup.vue +348 -0
- package/components/snake-popup/types.ts +88 -0
- package/components/snake-qr-code/qrcode.ts +1214 -0
- package/components/snake-qr-code/snake-qr-code.vue +408 -0
- package/components/snake-qr-code/types.ts +78 -0
- package/components/snake-radio/snake-radio.vue +271 -0
- package/components/snake-radio/types.ts +64 -0
- package/components/snake-radio-group/snake-radio-group.vue +98 -0
- package/components/snake-radio-group/types.ts +48 -0
- package/components/snake-read-more/snake-read-more.vue +140 -0
- package/components/snake-read-more/types.ts +53 -0
- package/components/snake-rich-text/snake-rich-text.vue +24 -0
- package/components/snake-rich-text/types.ts +5 -0
- package/components/snake-root-portal/snake-root-portal.vue +92 -0
- package/components/snake-root-portal/types.ts +9 -0
- package/components/snake-search/snake-search.vue +202 -0
- package/components/snake-search/types.ts +84 -0
- package/components/snake-select/snake-select.vue +371 -0
- package/components/snake-select/types.ts +75 -0
- package/components/snake-skeleton/snake-skeleton.vue +104 -0
- package/components/snake-skeleton/types.ts +32 -0
- package/components/snake-skeleton-item/snake-skeleton-item.vue +90 -0
- package/components/snake-skeleton-item/types.ts +30 -0
- package/components/snake-slider/snake-slider.vue +249 -0
- package/components/snake-slider/types.ts +59 -0
- package/components/snake-sticky/snake-sticky.vue +178 -0
- package/components/snake-sticky/types.ts +48 -0
- package/components/snake-subsection/snake-subsection.vue +188 -0
- package/components/snake-subsection/types.ts +54 -0
- package/components/snake-swiper/snake-swiper.vue +229 -0
- package/components/snake-swiper/types.ts +79 -0
- package/components/snake-switch/snake-switch.vue +100 -0
- package/components/snake-switch/types.ts +41 -0
- package/components/snake-tabbar/snake-tabbar.vue +306 -0
- package/components/snake-tabbar/types.ts +93 -0
- package/components/snake-tabs/snake-tabs.vue +305 -0
- package/components/snake-tabs/types.ts +79 -0
- package/components/snake-text/snake-text.vue +292 -0
- package/components/snake-text/types.ts +100 -0
- package/components/snake-textarea/snake-textarea.vue +171 -0
- package/components/snake-textarea/types.ts +79 -0
- package/components/snake-toast/snake-toast.vue +330 -0
- package/components/snake-toast/types.ts +55 -0
- package/components/snake-tooltip/position.ts +33 -0
- package/components/snake-tooltip/snake-tooltip.vue +339 -0
- package/components/snake-tooltip/types.ts +80 -0
- package/components/snake-transition/snake-transition.vue +315 -0
- package/components/snake-transition/types.ts +65 -0
- package/components/snake-upload/snake-upload.vue +1801 -0
- package/components/snake-upload/types.ts +256 -0
- package/components/snake-videos/snake-videos.vue +122 -0
- package/components/snake-videos/types.ts +7 -0
- package/iconfont.css +881 -0
- package/index.d.ts +7 -0
- package/index.scss +26 -0
- package/index.ts +94 -0
- package/libs/cms/blocks.ts +103 -0
- package/libs/cms/config.ts +25 -0
- package/libs/cms/index.ts +7 -0
- package/libs/cms/normalize.ts +135 -0
- package/libs/cms/resolve.ts +12 -0
- package/libs/cms/types.ts +164 -0
- package/libs/cms/use-commerce.ts +385 -0
- package/libs/cms/v2.ts +193 -0
- package/libs/config/index.ts +4 -0
- package/libs/config/modal.ts +93 -0
- package/libs/config/state.ts +33 -0
- package/libs/config/theme.ts +351 -0
- package/libs/config/toast.ts +71 -0
- package/libs/config/types.ts +135 -0
- package/libs/config/zIndex.ts +44 -0
- package/libs/css/color.scss +105 -0
- package/libs/css/common.scss +171 -0
- package/libs/css/style.h5.scss +7 -0
- package/libs/css/style.mp.scss +7 -0
- package/libs/css/style.theme.scss +70 -0
- package/libs/css/style.vue.scss +140 -0
- package/libs/form/async-validator.min.d.ts +75 -0
- package/libs/form/async-validator.min.js +3 -0
- package/libs/form/index.ts +3 -0
- package/libs/form/path.ts +40 -0
- package/libs/form/types.ts +51 -0
- package/libs/form/validate.ts +149 -0
- package/libs/foundation.ts +96 -0
- package/libs/function/$parent.ts +33 -0
- package/libs/function/clipboard.ts +13 -0
- package/libs/function/color.ts +55 -0
- package/libs/function/debounce.ts +34 -0
- package/libs/function/deepClone.ts +30 -0
- package/libs/function/deepMerge.ts +25 -0
- package/libs/function/emitter.ts +30 -0
- package/libs/function/format.ts +27 -0
- package/libs/function/getParent.ts +53 -0
- package/libs/function/getRect.ts +29 -0
- package/libs/function/guid.ts +11 -0
- package/libs/function/index.ts +31 -0
- package/libs/function/queryParams.ts +73 -0
- package/libs/function/random.ts +6 -0
- package/libs/function/randomArray.ts +14 -0
- package/libs/function/route.ts +155 -0
- package/libs/function/sleep.ts +7 -0
- package/libs/function/style.ts +58 -0
- package/libs/function/styleUtils.ts +83 -0
- package/libs/function/system.ts +14 -0
- package/libs/function/test.ts +202 -0
- package/libs/function/throttle.ts +36 -0
- package/libs/function/timeFormat.ts +27 -0
- package/libs/function/timeFrom.ts +27 -0
- package/libs/function/toast.ts +10 -0
- package/libs/function/trim.ts +11 -0
- package/libs/function/type2icon.ts +11 -0
- package/libs/function/unit.ts +45 -0
- package/libs/hooks/index.ts +11 -0
- package/libs/hooks/useChildren.ts +125 -0
- package/libs/hooks/useColor.ts +5 -0
- package/libs/hooks/useDebounce.ts +5 -0
- package/libs/hooks/useLocale.ts +13 -0
- package/libs/hooks/useModal.ts +131 -0
- package/libs/hooks/useParent.ts +62 -0
- package/libs/hooks/useRect.ts +44 -0
- package/libs/hooks/useRouter.ts +5 -0
- package/libs/hooks/useTheme.ts +31 -0
- package/libs/hooks/useThrottle.ts +5 -0
- package/libs/hooks/useToast.ts +116 -0
- package/libs/index.ts +18 -0
- package/libs/request/auto-http.ts +1 -0
- package/libs/request/index.ts +343 -0
- package/libs/runtime/accessors.ts +55 -0
- package/libs/runtime/context.ts +40 -0
- package/libs/runtime/index.ts +18 -0
- package/libs/runtime/types.ts +49 -0
- package/libs/util/calendar.ts +6 -0
- package/locale/index.ts +130 -0
- package/locale/lang/en-US.ts +67 -0
- package/locale/lang/zh-CN.ts +67 -0
- package/package.json +134 -5
- package/plugins/index.ts +1 -0
- package/plugins/root/README.md +86 -0
- package/plugins/root/index.ts +123 -0
- package/plugins/root/page.ts +77 -0
- package/plugins/root/root.ts +53 -0
- package/plugins/root/utils.ts +137 -0
- package/readme.md +79 -0
- package/theme.scss +118 -0
- package/types/components.d.ts +236 -0
- package/types/global.d.ts +21 -0
- package/types/index.d.ts +6 -0
- package/types/uni-app.d.ts +16 -0
- package/README.md +0 -3
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="snake-checkbox" :style="[checkboxStyle, customStyle]" :class="customClass">
|
|
3
|
+
<view class="snake-checkbox__icon-wrap" @tap="toggle" :class="iconClass" :style="iconStyle">
|
|
4
|
+
<snake-icon name="checkmark" :size="checkboxIconSize" :color="iconColor" />
|
|
5
|
+
</view>
|
|
6
|
+
<view class="snake-checkbox__label" @tap="onClickLabel" :style="{ fontSize: labelFontSize }">
|
|
7
|
+
<slot>{{ label }}</slot>
|
|
8
|
+
</view>
|
|
9
|
+
</view>
|
|
10
|
+
</template>
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
/**
|
|
13
|
+
* @component Checkbox
|
|
14
|
+
* @description checkbox 复选框,可独立 v-model 使用,也可放入 CheckboxGroup 参与多选。
|
|
15
|
+
* @see /components/checkbox
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { computed, inject } from 'vue';
|
|
19
|
+
import { useParent } from '../../libs/hooks';
|
|
20
|
+
import { addUnit } from '../../libs/function/unit';
|
|
21
|
+
import { CHECKBOX_GROUP_KEY } from '../snake-checkbox-group/types';
|
|
22
|
+
import { formKey } from '../snake-form/types';
|
|
23
|
+
import Icon from '../snake-icon/snake-icon.vue';
|
|
24
|
+
import { checkboxProps } from './types';
|
|
25
|
+
import type { CheckboxEmits } from './types';
|
|
26
|
+
|
|
27
|
+
defineOptions({
|
|
28
|
+
name: 'Checkbox',
|
|
29
|
+
options: {
|
|
30
|
+
addGlobalClass: true,
|
|
31
|
+
// #ifndef MP-TOUTIAO
|
|
32
|
+
virtualHost: true,
|
|
33
|
+
// #endif
|
|
34
|
+
styleIsolation: 'shared'
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const props = defineProps(checkboxProps);
|
|
39
|
+
const emit = defineEmits<CheckboxEmits>();
|
|
40
|
+
// 使用组件关系 hooks 获取父组件
|
|
41
|
+
const { parent: checkboxGroup } = useParent(CHECKBOX_GROUP_KEY);
|
|
42
|
+
const form = inject(formKey, null);
|
|
43
|
+
|
|
44
|
+
// checkbox 的数据项标识符
|
|
45
|
+
const checkboxValue = computed(() => props.name);
|
|
46
|
+
|
|
47
|
+
// group 绑定了 modelValue 时由 group 托管选中态(单一数据源),否则回落子项自身 v-model
|
|
48
|
+
const groupManaged = computed(() => checkboxGroup.value !== null && checkboxGroup.value.props.modelValue !== undefined);
|
|
49
|
+
|
|
50
|
+
// 是否选中:托管模式从 group 的 modelValue 派生,独立模式读自身 v-model
|
|
51
|
+
const isChecked = computed(() => {
|
|
52
|
+
if (groupManaged.value) {
|
|
53
|
+
return (checkboxGroup.value?.props.modelValue ?? []).includes(checkboxValue.value);
|
|
54
|
+
}
|
|
55
|
+
return !!props.modelValue;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// 根据 size 定义不同的配置
|
|
59
|
+
const sizeConfig = {
|
|
60
|
+
small: { size: 28, fontSize: 24, iconSize: 16 },
|
|
61
|
+
default: { size: 34, fontSize: 28, iconSize: 20 },
|
|
62
|
+
large: { size: 40, fontSize: 32, iconSize: 24 }
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// 获取实际使用的 size 值(优先级:props.size > snake-checkbox-group.size > snake-form.size)
|
|
66
|
+
const actualSize = computed(() => {
|
|
67
|
+
if (props.size !== '') return String(props.size);
|
|
68
|
+
if (checkboxGroup.value?.props.size) return String(checkboxGroup.value.props.size);
|
|
69
|
+
if (form?.size.value) return String(form.size.value);
|
|
70
|
+
return 'default';
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// 判断实际使用的 size 是否在预设配置中
|
|
74
|
+
const isInSizeConfig = computed(() => actualSize.value in sizeConfig);
|
|
75
|
+
|
|
76
|
+
// 获取预设 size(用于查找 sizeConfig 配置,如图标大小、高度等)
|
|
77
|
+
const presetSize = computed(() => {
|
|
78
|
+
return (isInSizeConfig.value ? actualSize.value : 'default') as 'small' | 'default' | 'large';
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// 获取当前尺寸配置
|
|
82
|
+
const currentSizeConfig = computed(() => sizeConfig[presetSize.value]);
|
|
83
|
+
|
|
84
|
+
// 是否禁用,如果父组件 snake-checkbox-group 禁用的话,将会忽略子组件的配置
|
|
85
|
+
const isDisabled = computed(() => {
|
|
86
|
+
return props.disabled !== '' ? props.disabled : (checkboxGroup.value?.props.disabled ?? false);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// 是否禁用 label 点击
|
|
90
|
+
const isLabelDisabled = computed(() => {
|
|
91
|
+
return props.labelDisabled !== '' ? props.labelDisabled : (checkboxGroup.value?.props.labelDisabled ?? false);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// 组件尺寸,对应 size 的值,默认值为 34rpx
|
|
95
|
+
const checkboxSize = computed(() => currentSizeConfig.value.size);
|
|
96
|
+
|
|
97
|
+
// 组件的勾选图标的尺寸,默认 20rpx
|
|
98
|
+
const checkboxIconSize = computed(() => {
|
|
99
|
+
if (props.iconSize) return props.iconSize;
|
|
100
|
+
if (checkboxGroup.value?.props.iconSize) return checkboxGroup.value.props.iconSize;
|
|
101
|
+
if (isInSizeConfig.value) return currentSizeConfig.value.iconSize;
|
|
102
|
+
return 20;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// label 字体大小,默认 28rpx
|
|
106
|
+
const labelFontSize = computed(() => {
|
|
107
|
+
if (isInSizeConfig.value) return addUnit(currentSizeConfig.value.fontSize, 'rpx');
|
|
108
|
+
return props.labelSize ? addUnit(props.labelSize, 'rpx') : '';
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// 组件选中激活时的颜色
|
|
112
|
+
const elActiveColor = computed(() => {
|
|
113
|
+
return props.activeColor
|
|
114
|
+
? props.activeColor
|
|
115
|
+
: (checkboxGroup.value?.props.activeColor ?? 'var(--snake-color-primary, #06D290)');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// 组件的形状
|
|
119
|
+
const elShape = computed(() => {
|
|
120
|
+
return props.shape ? props.shape : (checkboxGroup.value?.props.shape ?? 'square');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 图标样式
|
|
124
|
+
const iconStyle = computed(() => {
|
|
125
|
+
const style: Record<string, string> = {};
|
|
126
|
+
if (elActiveColor.value && isChecked.value && !isDisabled.value) {
|
|
127
|
+
style.borderColor = elActiveColor.value;
|
|
128
|
+
style.backgroundColor = elActiveColor.value;
|
|
129
|
+
}
|
|
130
|
+
style.width = addUnit(checkboxSize.value, 'rpx');
|
|
131
|
+
style.height = addUnit(checkboxSize.value, 'rpx');
|
|
132
|
+
return style;
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// checkbox 内部的勾选图标,如果选中状态,为白色,否则为透明色即可
|
|
136
|
+
const iconColor = computed(() => {
|
|
137
|
+
return isChecked.value ? '#fff' : 'transparent';
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const iconClass = computed(() => {
|
|
141
|
+
const classes: string[] = [];
|
|
142
|
+
classes.push(`snake-checkbox__icon-wrap--${elShape.value}`);
|
|
143
|
+
if (isChecked.value) classes.push('snake-checkbox__icon-wrap--checked');
|
|
144
|
+
if (isDisabled.value) classes.push('snake-checkbox__icon-wrap--disabled');
|
|
145
|
+
if (isChecked.value && isDisabled.value) classes.push('snake-checkbox__icon-wrap--disabled--checked');
|
|
146
|
+
return classes.join(' ');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const checkboxStyle = computed(() => {
|
|
150
|
+
const style: Record<string, string> = {};
|
|
151
|
+
if (checkboxGroup.value?.props.width) {
|
|
152
|
+
style.width = checkboxGroup.value.props.width;
|
|
153
|
+
// #ifdef MP
|
|
154
|
+
// 各家小程序因为它们特殊的编译结构,使用 float 布局
|
|
155
|
+
style.float = 'left';
|
|
156
|
+
// #endif
|
|
157
|
+
// #ifndef MP
|
|
158
|
+
// H5 和 APP 使用 flex 布局
|
|
159
|
+
style.flex = `0 0 ${checkboxGroup.value.props.width}`;
|
|
160
|
+
// #endif
|
|
161
|
+
}
|
|
162
|
+
if (checkboxGroup.value?.props.wrap) {
|
|
163
|
+
style.width = '100%';
|
|
164
|
+
// #ifndef MP
|
|
165
|
+
// H5 和 APP 使用 flex 布局,将宽度设置 100%,即可自动换行
|
|
166
|
+
style.flex = '0 0 100%';
|
|
167
|
+
// #endif
|
|
168
|
+
}
|
|
169
|
+
return style;
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 点击 label
|
|
174
|
+
*/
|
|
175
|
+
function onClickLabel() {
|
|
176
|
+
if (!isLabelDisabled.value && !isDisabled.value) {
|
|
177
|
+
setValue();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 点击 icon
|
|
183
|
+
*/
|
|
184
|
+
function toggle() {
|
|
185
|
+
if (!isDisabled.value) {
|
|
186
|
+
setValue();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 点击切换选中态:托管模式交给 group 统一判定(max 校验与事件派发),独立模式更新自身 v-model
|
|
192
|
+
*/
|
|
193
|
+
function setValue() {
|
|
194
|
+
if (groupManaged.value) {
|
|
195
|
+
checkboxGroup.value?.toggleSelect(checkboxValue.value);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const next = !isChecked.value;
|
|
199
|
+
emit('update:modelValue', next);
|
|
200
|
+
emit('change', next);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
defineExpose({
|
|
204
|
+
isChecked,
|
|
205
|
+
isDisabled,
|
|
206
|
+
value: checkboxValue,
|
|
207
|
+
props
|
|
208
|
+
});
|
|
209
|
+
</script>
|
|
210
|
+
<style scoped>
|
|
211
|
+
.snake-checkbox {
|
|
212
|
+
/* #ifndef APP-NVUE */
|
|
213
|
+
display: inline-flex;
|
|
214
|
+
/* #endif */
|
|
215
|
+
align-items: center;
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
user-select: none;
|
|
218
|
+
line-height: 1.8;
|
|
219
|
+
}
|
|
220
|
+
.snake-checkbox__icon-wrap {
|
|
221
|
+
display: flex;
|
|
222
|
+
flex: none;
|
|
223
|
+
align-items: center;
|
|
224
|
+
justify-content: center;
|
|
225
|
+
box-sizing: border-box;
|
|
226
|
+
width: 42rpx;
|
|
227
|
+
height: 42rpx;
|
|
228
|
+
color: transparent;
|
|
229
|
+
text-align: center;
|
|
230
|
+
transition-property: color, border-color, background-color;
|
|
231
|
+
font-size: 20px;
|
|
232
|
+
border: 1px solid var(--snake-color-border, #dcdfe6);
|
|
233
|
+
transition-duration: 0.2s;
|
|
234
|
+
/* #ifdef MP-TOUTIAO */
|
|
235
|
+
/* 头条小程序兼容性问题,需要设置行高为 0,否则图标偏下 */
|
|
236
|
+
line-height: 0;
|
|
237
|
+
/* #endif */
|
|
238
|
+
}
|
|
239
|
+
.snake-checkbox__icon-wrap--circle {
|
|
240
|
+
border-radius: 100%;
|
|
241
|
+
}
|
|
242
|
+
.snake-checkbox__icon-wrap--square {
|
|
243
|
+
border-radius: 6rpx;
|
|
244
|
+
}
|
|
245
|
+
.snake-checkbox__icon-wrap--checked {
|
|
246
|
+
color: #fff;
|
|
247
|
+
background-color: var(--snake-color-primary, #06d290);
|
|
248
|
+
border-color: var(--snake-color-primary, #06d290);
|
|
249
|
+
}
|
|
250
|
+
.snake-checkbox__icon-wrap--disabled {
|
|
251
|
+
background-color: var(--snake-color-disabled-bg, #f1f1f1);
|
|
252
|
+
border-color: var(--snake-color-border, #dcdfe6);
|
|
253
|
+
}
|
|
254
|
+
.snake-checkbox__icon-wrap--disabled--checked {
|
|
255
|
+
color: var(--snake-color-disabled-bg, #f1f1f1) !important;
|
|
256
|
+
}
|
|
257
|
+
.snake-checkbox__label {
|
|
258
|
+
word-wrap: break-word;
|
|
259
|
+
margin-left: 10rpx;
|
|
260
|
+
margin-right: 24rpx;
|
|
261
|
+
color: var(--snake-color-text, #303133);
|
|
262
|
+
font-size: 30rpx;
|
|
263
|
+
}
|
|
264
|
+
</style>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ExtractPropTypes, PropType } from 'vue';
|
|
2
|
+
import type { UnitValue } from '../../libs/function/unit';
|
|
3
|
+
import type { StyleValue } from '../../types/global';
|
|
4
|
+
|
|
5
|
+
/** checkboxProps 运行时属性及默认值。 */
|
|
6
|
+
export const checkboxProps = {
|
|
7
|
+
/** 根节点自定义样式。 */
|
|
8
|
+
customStyle: { type: [String, Object, Array] as PropType<StyleValue>, default: () => ({}) },
|
|
9
|
+
/** 根节点自定义类名。 */
|
|
10
|
+
customClass: { type: String, default: '' },
|
|
11
|
+
/** 展示标签文本。 */
|
|
12
|
+
label: { type: String, default: '' },
|
|
13
|
+
/** 数据项名称或唯一标识。 */
|
|
14
|
+
name: { type: [String, Number] as PropType<string | number>, default: '' },
|
|
15
|
+
/** 组件形状,square 为方形,circle 为圆形。 */
|
|
16
|
+
shape: { type: String as PropType<'square' | 'circle'>, default: '' },
|
|
17
|
+
/** 是否选中,支持 v-model。 */
|
|
18
|
+
modelValue: { type: Boolean, default: false },
|
|
19
|
+
/** 是否禁用。 */
|
|
20
|
+
disabled: { type: [String, Boolean] as PropType<string | boolean>, default: '' },
|
|
21
|
+
/** 是否禁止点击标签选中。 */
|
|
22
|
+
labelDisabled: { type: [String, Boolean] as PropType<string | boolean>, default: '' },
|
|
23
|
+
/** 选中状态下的颜色,设置后将覆盖父级 activeColor。 */
|
|
24
|
+
activeColor: { type: String, default: '' },
|
|
25
|
+
/** 勾选图标的大小,单位 rpx。 */
|
|
26
|
+
iconSize: { type: [String, Number] as PropType<UnitValue>, default: '' },
|
|
27
|
+
/** 标签文字大小,单位 rpx。 */
|
|
28
|
+
labelSize: { type: [String, Number] as PropType<UnitValue>, default: '' },
|
|
29
|
+
/** 组件整体大小,small/default/large 或自定义数值。 */
|
|
30
|
+
size: { type: [String, Number] as PropType<string | number>, default: '' }
|
|
31
|
+
} as const;
|
|
32
|
+
|
|
33
|
+
/** CheckboxResolved 组件的公开属性。 */
|
|
34
|
+
export type CheckboxResolvedProps = ExtractPropTypes<typeof checkboxProps>;
|
|
35
|
+
|
|
36
|
+
/** Checkbox 组件的公开属性。 */
|
|
37
|
+
export interface CheckboxProps {
|
|
38
|
+
/** 根节点自定义样式。 */
|
|
39
|
+
customStyle?: StyleValue;
|
|
40
|
+
/** 根节点自定义类名。 */
|
|
41
|
+
customClass?: string;
|
|
42
|
+
/** 展示标签文本。 */
|
|
43
|
+
label?: string;
|
|
44
|
+
/** 数据项名称或唯一标识。 */
|
|
45
|
+
name?: string | number;
|
|
46
|
+
/** 组件形状,square 为方形,circle 为圆形。 */
|
|
47
|
+
shape?: 'square' | 'circle';
|
|
48
|
+
/** 是否选中,支持 v-model。 */
|
|
49
|
+
modelValue?: boolean;
|
|
50
|
+
/** 是否禁用。 */
|
|
51
|
+
disabled?: string | boolean;
|
|
52
|
+
/** 是否禁止点击标签选中。 */
|
|
53
|
+
labelDisabled?: string | boolean;
|
|
54
|
+
/** 选中状态下的颜色,设置后将覆盖父级 activeColor。 */
|
|
55
|
+
activeColor?: string;
|
|
56
|
+
/** 勾选图标的大小,单位 rpx。 */
|
|
57
|
+
iconSize?: UnitValue;
|
|
58
|
+
/** 标签文字大小,单位 rpx。 */
|
|
59
|
+
labelSize?: UnitValue;
|
|
60
|
+
/** 组件整体大小,small/default/large 或自定义数值。 */
|
|
61
|
+
size?: string | number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Checkbox 组件的事件契约。 */
|
|
65
|
+
export type CheckboxEmits = {
|
|
66
|
+
/** 选中状态变化时触发。 */
|
|
67
|
+
'update:modelValue': [value: boolean];
|
|
68
|
+
/** 选中状态变化时触发,携带变化后的新状态。 */
|
|
69
|
+
change: [value: boolean];
|
|
70
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="snake-checkbox-group snake-checkbox-group--clearfix" :style="customStyle" :class="customClass">
|
|
3
|
+
<slot />
|
|
4
|
+
</view>
|
|
5
|
+
</template>
|
|
6
|
+
<script setup lang="ts">
|
|
7
|
+
/**
|
|
8
|
+
* @component CheckboxGroup
|
|
9
|
+
* @description checkbox 父组件,管理一组 Checkbox 的数组值、最大选择数与布局。
|
|
10
|
+
* @see /components/checkbox
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { computed, inject } from 'vue';
|
|
14
|
+
import { useChildren } from '../../libs/hooks';
|
|
15
|
+
import { formItemKey } from '../snake-form-item/types';
|
|
16
|
+
import {
|
|
17
|
+
CHECKBOX_GROUP_KEY,
|
|
18
|
+
type CheckboxGroupContext,
|
|
19
|
+
type CheckboxGroupEmits,
|
|
20
|
+
type CheckboxGroupProps
|
|
21
|
+
} from './types';
|
|
22
|
+
|
|
23
|
+
/** Checkbox 子项在公开代理上的形态(defineExpose 暴露的 ref 已被解包)。 */
|
|
24
|
+
interface CheckboxChild {
|
|
25
|
+
isChecked: boolean;
|
|
26
|
+
isDisabled: boolean;
|
|
27
|
+
value: string | number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
defineOptions({
|
|
31
|
+
name: 'CheckboxGroup',
|
|
32
|
+
options: {
|
|
33
|
+
addGlobalClass: true,
|
|
34
|
+
// #ifndef MP-TOUTIAO
|
|
35
|
+
virtualHost: true,
|
|
36
|
+
// #endif
|
|
37
|
+
styleIsolation: 'shared'
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const props = withDefaults(defineProps<CheckboxGroupProps>(), {
|
|
42
|
+
customStyle: '',
|
|
43
|
+
customClass: '',
|
|
44
|
+
max: 999,
|
|
45
|
+
disabled: false,
|
|
46
|
+
name: '',
|
|
47
|
+
labelDisabled: false,
|
|
48
|
+
shape: 'square',
|
|
49
|
+
activeColor: 'var(--snake-color-primary, #06D290)',
|
|
50
|
+
size: '',
|
|
51
|
+
width: 'auto',
|
|
52
|
+
wrap: false,
|
|
53
|
+
iconSize: ''
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const emit = defineEmits<CheckboxGroupEmits>();
|
|
57
|
+
const formItem = inject(formItemKey, null);
|
|
58
|
+
|
|
59
|
+
// 使用组件关系 hooks 收集子 checkbox(自动注册 / 按 vnode 序排列),
|
|
60
|
+
// 选中态以 modelValue 为单一数据源,子项仅派生展示
|
|
61
|
+
const { children, linkChildren } = useChildren<CheckboxChild, CheckboxGroupContext>(CHECKBOX_GROUP_KEY);
|
|
62
|
+
|
|
63
|
+
const selectedValues = computed<(string | number)[]>(() => props.modelValue ?? []);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 子项点击入口:在 modelValue 上增删自身值,统一做 max 校验与事件派发
|
|
67
|
+
*/
|
|
68
|
+
function toggleSelect(value: string | number) {
|
|
69
|
+
if (props.disabled) return;
|
|
70
|
+
let next: (string | number)[];
|
|
71
|
+
if (selectedValues.value.includes(value)) {
|
|
72
|
+
next = selectedValues.value.filter(item => item !== value);
|
|
73
|
+
} else {
|
|
74
|
+
if (props.max && selectedValues.value.length >= props.max) {
|
|
75
|
+
uni.showToast({ title: `超过最大选择数量: ${props.max}`, icon: 'none' });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
next = [...selectedValues.value, value];
|
|
79
|
+
}
|
|
80
|
+
emit('update:modelValue', next);
|
|
81
|
+
emit('change', next);
|
|
82
|
+
// 通知 snake-form-item 进行校验
|
|
83
|
+
void formItem?.notify('change');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 全选/全不选方法(禁用子项保持原状态)
|
|
88
|
+
*/
|
|
89
|
+
function setAllChecked(checked: boolean) {
|
|
90
|
+
if (props.disabled) {
|
|
91
|
+
console.warn('snake-checkbox-group 已禁用,无法操作');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const enabledValues = children.filter(child => !child.isDisabled).map(child => child.value);
|
|
95
|
+
const next = checked ? enabledValues : selectedValues.value.filter(value => !enabledValues.includes(value));
|
|
96
|
+
emit('update:modelValue', next);
|
|
97
|
+
emit('change', next);
|
|
98
|
+
void formItem?.notify('change');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 获取选中的值
|
|
103
|
+
*/
|
|
104
|
+
function getSelectedValues() {
|
|
105
|
+
return [...selectedValues.value];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 验证选择是否超过最大数量
|
|
110
|
+
*/
|
|
111
|
+
function validateSelection() {
|
|
112
|
+
if (props.max && selectedValues.value.length >= props.max) {
|
|
113
|
+
uni.showToast({ title: `超过最大选择数量: ${props.max}`, icon: 'none' });
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 向子 checkbox 提供上下文(props 实时联动 + 选中值增删入口)
|
|
120
|
+
linkChildren({ props, toggleSelect });
|
|
121
|
+
|
|
122
|
+
// 使用 defineExpose 暴露给外部
|
|
123
|
+
defineExpose({
|
|
124
|
+
// props
|
|
125
|
+
props,
|
|
126
|
+
|
|
127
|
+
// 方法
|
|
128
|
+
setAllChecked,
|
|
129
|
+
getSelectedValues,
|
|
130
|
+
validateSelection,
|
|
131
|
+
|
|
132
|
+
// 计算属性
|
|
133
|
+
selectedCount: computed(() => selectedValues.value.length),
|
|
134
|
+
isFull: computed(() => Boolean(props.max) && selectedValues.value.length >= props.max),
|
|
135
|
+
isEmpty: computed(() => selectedValues.value.length === 0),
|
|
136
|
+
// 工具方法
|
|
137
|
+
getChildrenCount: () => children.length
|
|
138
|
+
});
|
|
139
|
+
</script>
|
|
140
|
+
<style scoped>
|
|
141
|
+
.snake-checkbox-group {
|
|
142
|
+
/* #ifndef MP || APP-NVUE */
|
|
143
|
+
display: inline-flex;
|
|
144
|
+
flex-wrap: wrap;
|
|
145
|
+
/* #endif */
|
|
146
|
+
}
|
|
147
|
+
/* MP 下子项以 float 布局时,容器需要清除浮动 */
|
|
148
|
+
.snake-checkbox-group--clearfix::after {
|
|
149
|
+
content: '';
|
|
150
|
+
display: block;
|
|
151
|
+
overflow: hidden;
|
|
152
|
+
clear: both;
|
|
153
|
+
}
|
|
154
|
+
</style>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { InjectionKey } from 'vue';
|
|
2
|
+
import type { UnitValue } from '../../libs/function/unit';
|
|
3
|
+
import type { StyleValue } from '../../types/global';
|
|
4
|
+
|
|
5
|
+
/** CheckboxGroup 组件的公开属性。 */
|
|
6
|
+
export interface CheckboxGroupProps {
|
|
7
|
+
/** 根节点自定义样式。 */
|
|
8
|
+
customStyle?: StyleValue;
|
|
9
|
+
/** 根节点自定义类名。 */
|
|
10
|
+
customClass?: string;
|
|
11
|
+
/** 绑定值,选中的 checkbox name 组成的数组,支持 v-model。 */
|
|
12
|
+
modelValue?: (string | number)[];
|
|
13
|
+
/** 最多能选中多少个 checkbox。 */
|
|
14
|
+
max?: number;
|
|
15
|
+
/** 是否禁用所有 checkbox。 */
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/** 在表单内提交时的标识符。 */
|
|
18
|
+
name?: boolean | string;
|
|
19
|
+
/** 是否禁止点击标签选中。 */
|
|
20
|
+
labelDisabled?: boolean;
|
|
21
|
+
/** 组件形状,square 为方形,circle 为圆形。 */
|
|
22
|
+
shape?: 'square' | 'circle';
|
|
23
|
+
/** 选中状态下的颜色,应用到所有子 checkbox。 */
|
|
24
|
+
activeColor?: string;
|
|
25
|
+
/** 组件整体大小,small/default/large 或自定义数值。 */
|
|
26
|
+
size?: string | number;
|
|
27
|
+
/** 每个 checkbox 占 snake-checkbox-group 的宽度,需带单位。 */
|
|
28
|
+
width?: string;
|
|
29
|
+
/** 是否每个 checkbox 都换行。 */
|
|
30
|
+
wrap?: boolean;
|
|
31
|
+
/** 勾选图标的大小,单位 rpx。 */
|
|
32
|
+
iconSize?: UnitValue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** CheckboxGroup 组件的事件契约。 */
|
|
36
|
+
export type CheckboxGroupEmits = {
|
|
37
|
+
/** 更新当前选中值数组。 */
|
|
38
|
+
'update:modelValue': [value: (string | number)[]];
|
|
39
|
+
/** 任一个 checkbox 状态发生变化时触发,回调为选中的 name 数组。 */
|
|
40
|
+
change: [value: (string | number)[]];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** CheckboxGroup 向子 checkbox 提供的配对上下文(useChildren / useParent 通道)。 */
|
|
44
|
+
export interface CheckboxGroupContext {
|
|
45
|
+
/** 父组件的响应式 props 对象,子项直接读取即可保持联动。 */
|
|
46
|
+
props: CheckboxGroupProps;
|
|
47
|
+
/** 子项点击入口:在 modelValue 上增删自身值,max 校验与事件派发由 group 统一处理。 */
|
|
48
|
+
toggleSelect(value: string | number): void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** CheckboxGroup ↔ Checkbox 配对注入键。 */
|
|
52
|
+
export const CHECKBOX_GROUP_KEY: InjectionKey<CheckboxGroupContext> = Symbol('snake-checkbox-group');
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="cms-v2-carousel" :style="rootStyle">
|
|
3
|
+
<swiper
|
|
4
|
+
class="cms-v2-carousel__swiper"
|
|
5
|
+
:style="mediaStyle"
|
|
6
|
+
:autoplay="data.play?.autoplay !== false"
|
|
7
|
+
:interval="interval"
|
|
8
|
+
:circular="data.play?.loop !== false"
|
|
9
|
+
:indicator-dots="indicatorType === 'bullets'"
|
|
10
|
+
indicator-color="rgba(255, 255, 255, 0.55)"
|
|
11
|
+
:indicator-active-color="data.indicator?.color || '#1989fa'"
|
|
12
|
+
@change="current = $event.detail.current"
|
|
13
|
+
>
|
|
14
|
+
<swiper-item v-for="(item, index) in items" :key="item.id ?? index">
|
|
15
|
+
<image
|
|
16
|
+
class="cms-v2-carousel__image"
|
|
17
|
+
:src="item.src || ''"
|
|
18
|
+
mode="aspectFill"
|
|
19
|
+
@click="openV2Link(item.link, linkService, pageInfo)"
|
|
20
|
+
/>
|
|
21
|
+
</swiper-item>
|
|
22
|
+
</swiper>
|
|
23
|
+
<view v-if="indicatorType === 'fraction' && items.length" class="cms-v2-carousel__fraction">
|
|
24
|
+
{{ current + 1 }}/{{ items.length }}
|
|
25
|
+
</view>
|
|
26
|
+
<view v-if="indicatorType === 'progressbar' && items.length" class="cms-v2-carousel__progress">
|
|
27
|
+
<view class="cms-v2-carousel__progress-fill" :style="progressStyle" />
|
|
28
|
+
</view>
|
|
29
|
+
</view>
|
|
30
|
+
</template>
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
/** @component CmsV2Carousel @description CMS v2 图片轮播内部渲染器。 @see /cms/overview */
|
|
33
|
+
import { computed, ref } from 'vue';
|
|
34
|
+
import {
|
|
35
|
+
blockStyle,
|
|
36
|
+
carouselIndicatorType,
|
|
37
|
+
carouselProgress,
|
|
38
|
+
mediaHeightStyle,
|
|
39
|
+
openV2Link,
|
|
40
|
+
type V2BlockProps
|
|
41
|
+
} from './shared';
|
|
42
|
+
const props = defineProps<V2BlockProps>();
|
|
43
|
+
const current = ref(0);
|
|
44
|
+
const items = computed(() => (Array.isArray(props.data.items) ? props.data.items : []));
|
|
45
|
+
const interval = computed(() => Math.max(1000, Number(props.data.play?.interval || 3) * 1000));
|
|
46
|
+
const indicatorType = computed(() => carouselIndicatorType(props.data));
|
|
47
|
+
const progressStyle = computed(() => ({
|
|
48
|
+
width: `${carouselProgress(current.value, items.value.length)}%`,
|
|
49
|
+
backgroundColor: props.data.indicator?.color || '#1989fa'
|
|
50
|
+
}));
|
|
51
|
+
const rootStyle = computed(() => blockStyle(props.data.style));
|
|
52
|
+
const mediaStyle = computed(() => mediaHeightStyle(props.data.style));
|
|
53
|
+
</script>
|
|
54
|
+
<style scoped>
|
|
55
|
+
.cms-v2-carousel {
|
|
56
|
+
position: relative;
|
|
57
|
+
}
|
|
58
|
+
.cms-v2-carousel__swiper {
|
|
59
|
+
width: 100%;
|
|
60
|
+
}
|
|
61
|
+
.cms-v2-carousel__image {
|
|
62
|
+
width: 100%;
|
|
63
|
+
height: 100%;
|
|
64
|
+
}
|
|
65
|
+
.cms-v2-carousel__fraction {
|
|
66
|
+
position: absolute;
|
|
67
|
+
right: 20rpx;
|
|
68
|
+
bottom: 16rpx;
|
|
69
|
+
padding: 4rpx 12rpx;
|
|
70
|
+
color: #fff;
|
|
71
|
+
font-size: 22rpx;
|
|
72
|
+
background: rgba(0, 0, 0, 0.45);
|
|
73
|
+
border-radius: 20rpx;
|
|
74
|
+
}
|
|
75
|
+
.cms-v2-carousel__progress {
|
|
76
|
+
position: absolute;
|
|
77
|
+
right: 0;
|
|
78
|
+
bottom: 0;
|
|
79
|
+
left: 0;
|
|
80
|
+
height: 6rpx;
|
|
81
|
+
overflow: hidden;
|
|
82
|
+
background-color: #eee;
|
|
83
|
+
}
|
|
84
|
+
.cms-v2-carousel__progress-fill {
|
|
85
|
+
height: 100%;
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<snake-coupon
|
|
3
|
+
:datas="legacyData"
|
|
4
|
+
:coupon-service="couponService"
|
|
5
|
+
:link-service="linkService"
|
|
6
|
+
:page-info="pageInfo"
|
|
7
|
+
@error="$emit('error', $event)"
|
|
8
|
+
@received="$emit('received')"
|
|
9
|
+
/>
|
|
10
|
+
</template>
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
/** @component CmsV2Coupon @description CMS v2 优惠券协议内部渲染器。 @see /cms/overview */
|
|
13
|
+
import { computed } from 'vue';
|
|
14
|
+
import Coupon from '../../../snake-coupon/snake-coupon.vue';
|
|
15
|
+
import type { CmsCouponService, CmsError, CmsLinkService, CmsPageInfo } from '../../../../libs/cms';
|
|
16
|
+
import { v2CouponLegacyData } from './shared';
|
|
17
|
+
const props = defineProps<{
|
|
18
|
+
data: Record<string, any>;
|
|
19
|
+
couponService?: CmsCouponService;
|
|
20
|
+
linkService?: CmsLinkService;
|
|
21
|
+
pageInfo?: CmsPageInfo;
|
|
22
|
+
}>();
|
|
23
|
+
defineEmits<{ error: [error: CmsError]; received: [] }>();
|
|
24
|
+
const legacyData = computed(() => v2CouponLegacyData(props.data));
|
|
25
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="cms-v2-custom"><slot /></view>
|
|
3
|
+
</template>
|
|
4
|
+
<script setup lang="ts">
|
|
5
|
+
/** @component CmsV2Custom @description CMS v2 自定义插槽内部渲染器。 @see /cms/overview */
|
|
6
|
+
defineProps<{ data: Record<string, any> }>();
|
|
7
|
+
</script>
|
|
8
|
+
<style scoped>
|
|
9
|
+
.cms-v2-custom {
|
|
10
|
+
width: 100%;
|
|
11
|
+
}
|
|
12
|
+
</style>
|