@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,271 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="snake-radio" :style="[radioStyle, customStyle]" :class="customClass">
|
|
3
|
+
<view class="snake-radio__icon-wrap" @tap="toggle" :class="iconClass" :style="iconStyle">
|
|
4
|
+
<snake-icon name="checkmark" :size="elIconSize" :color="iconColor" />
|
|
5
|
+
</view>
|
|
6
|
+
<view class="snake-radio__label" @tap="onClickLabel" :style="{ fontSize: labelFontSize }">
|
|
7
|
+
<slot>{{ label }}</slot>
|
|
8
|
+
</view>
|
|
9
|
+
</view>
|
|
10
|
+
</template>
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
/**
|
|
13
|
+
* @component Radio
|
|
14
|
+
* @description radio 单选框,通过 `name` 参与 RadioGroup 互斥选择。
|
|
15
|
+
* @see /components/radio
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { computed, inject } from 'vue';
|
|
19
|
+
import { useParent } from '../../libs/hooks';
|
|
20
|
+
import { RADIO_GROUP_KEY } from '../snake-radio-group/types';
|
|
21
|
+
import { addUnit } from '../../libs/function/unit';
|
|
22
|
+
import { formKey } from '../snake-form/types';
|
|
23
|
+
import Icon from '../snake-icon/snake-icon.vue';
|
|
24
|
+
import { radioProps } from './types';
|
|
25
|
+
import type { RadioEmits } from './types';
|
|
26
|
+
|
|
27
|
+
defineOptions({
|
|
28
|
+
name: 'Radio',
|
|
29
|
+
options: {
|
|
30
|
+
addGlobalClass: true,
|
|
31
|
+
// #ifndef MP-TOUTIAO
|
|
32
|
+
virtualHost: true,
|
|
33
|
+
// #endif
|
|
34
|
+
styleIsolation: 'shared'
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const props = defineProps(radioProps);
|
|
39
|
+
const emit = defineEmits<RadioEmits>();
|
|
40
|
+
|
|
41
|
+
// 使用组件关系 hooks 获取父组件
|
|
42
|
+
const { parent: radioGroup } = useParent(RADIO_GROUP_KEY);
|
|
43
|
+
const form = inject(formKey, null);
|
|
44
|
+
|
|
45
|
+
// radio 的数据项标识符
|
|
46
|
+
const radioValue = computed(() => props.name);
|
|
47
|
+
|
|
48
|
+
// 父组件数据,供子组件使用(兼容没有父组件的场景,各字段回退为 null)
|
|
49
|
+
const parentData = computed(() => {
|
|
50
|
+
const group = radioGroup.value;
|
|
51
|
+
return {
|
|
52
|
+
iconSize: group?.props.iconSize ?? null,
|
|
53
|
+
labelDisabled: group?.props.labelDisabled ?? null,
|
|
54
|
+
disabled: group?.props.disabled ?? null,
|
|
55
|
+
shape: group?.props.shape ?? null,
|
|
56
|
+
activeColor: group?.props.activeColor ?? null,
|
|
57
|
+
size: group?.props.size ?? null,
|
|
58
|
+
width: group?.props.width ?? null,
|
|
59
|
+
value: group?.props.modelValue ?? null,
|
|
60
|
+
wrap: group?.props.wrap ?? null
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 根据 size 定义不同的配置
|
|
65
|
+
const sizeConfig = {
|
|
66
|
+
small: { size: 28, fontSize: 24, iconSize: 16 },
|
|
67
|
+
default: { size: 34, fontSize: 28, iconSize: 20 },
|
|
68
|
+
large: { size: 40, fontSize: 32, iconSize: 24 }
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// 获取实际使用的 size 值(优先级:props.size > snake-radio-group.size > snake-form.size)
|
|
72
|
+
const actualSize = computed(() => {
|
|
73
|
+
if (props.size !== '') return String(props.size);
|
|
74
|
+
if (radioGroup.value?.props.size) return String(radioGroup.value.props.size);
|
|
75
|
+
if (form?.size.value) return String(form.size.value);
|
|
76
|
+
return 'default';
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// 判断实际使用的 size 是否在预设配置中
|
|
80
|
+
const isInSizeConfig = computed(() => actualSize.value in sizeConfig);
|
|
81
|
+
|
|
82
|
+
// 获取预设 size(用于查找 sizeConfig 配置,如图标大小、高度等)
|
|
83
|
+
const presetSize = computed(() => {
|
|
84
|
+
return (isInSizeConfig.value ? actualSize.value : 'default') as 'small' | 'default' | 'large';
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// 获取当前尺寸配置
|
|
88
|
+
const currentSizeConfig = computed(() => sizeConfig[presetSize.value]);
|
|
89
|
+
|
|
90
|
+
// 是否禁用,如果父组件 snake-radio-group 禁用的话,将会忽略子组件的配置
|
|
91
|
+
const elDisabled = computed(() =>
|
|
92
|
+
props.disabled !== '' ? props.disabled : parentData.value.disabled !== null ? parentData.value.disabled : false
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// 是否禁用 label 点击
|
|
96
|
+
const elLabelDisabled = computed(() =>
|
|
97
|
+
props.labelDisabled !== ''
|
|
98
|
+
? props.labelDisabled
|
|
99
|
+
: parentData.value.labelDisabled !== null
|
|
100
|
+
? parentData.value.labelDisabled
|
|
101
|
+
: false
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// 组件尺寸,对应 size 的值,默认值为 34rpx
|
|
105
|
+
const elSize = computed(() => currentSizeConfig.value.size);
|
|
106
|
+
|
|
107
|
+
// 组件的勾选图标的尺寸,默认 20
|
|
108
|
+
const elIconSize = computed(() => {
|
|
109
|
+
if (props.iconSize) return props.iconSize;
|
|
110
|
+
if (radioGroup.value?.props.iconSize) return radioGroup.value.props.iconSize;
|
|
111
|
+
if (isInSizeConfig.value) return currentSizeConfig.value.iconSize;
|
|
112
|
+
return 20;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// label 字体大小,默认 28
|
|
116
|
+
const labelFontSize = computed(() => {
|
|
117
|
+
if (isInSizeConfig.value) return addUnit(currentSizeConfig.value.fontSize, 'rpx');
|
|
118
|
+
return props.labelSize ? addUnit(props.labelSize, 'rpx') : '';
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// 组件选中激活时的颜色
|
|
122
|
+
const elActiveColor = computed(() =>
|
|
123
|
+
props.activeColor
|
|
124
|
+
? props.activeColor
|
|
125
|
+
: parentData.value.activeColor
|
|
126
|
+
? parentData.value.activeColor
|
|
127
|
+
: 'var(--snake-color-primary, #06D290)'
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// 组件的形状
|
|
131
|
+
const elShape = computed(() =>
|
|
132
|
+
props.shape ? props.shape : parentData.value.shape ? parentData.value.shape : 'circle'
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// 设置 radio 的状态,要求 radio 的 name 等于 parent 的 value 时才为选中状态
|
|
136
|
+
const iconStyle = computed(() => {
|
|
137
|
+
const style: Record<string, string> = {};
|
|
138
|
+
if (elActiveColor.value && parentData.value.value == radioValue.value && !elDisabled.value) {
|
|
139
|
+
style.borderColor = elActiveColor.value;
|
|
140
|
+
style.backgroundColor = elActiveColor.value;
|
|
141
|
+
}
|
|
142
|
+
style.width = addUnit(elSize.value, 'rpx');
|
|
143
|
+
style.height = addUnit(elSize.value, 'rpx');
|
|
144
|
+
return style;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const iconColor = computed(() => (radioValue.value == parentData.value.value ? '#fff' : 'transparent'));
|
|
148
|
+
|
|
149
|
+
const iconClass = computed(() => {
|
|
150
|
+
const classes: string[] = [];
|
|
151
|
+
classes.push(`snake-radio__icon-wrap--${elShape.value}`);
|
|
152
|
+
if (radioValue.value == parentData.value.value) classes.push('snake-radio__icon-wrap--checked');
|
|
153
|
+
if (elDisabled.value) classes.push('snake-radio__icon-wrap--disabled');
|
|
154
|
+
if (radioValue.value == parentData.value.value && elDisabled.value)
|
|
155
|
+
classes.push('snake-radio__icon-wrap--disabled--checked');
|
|
156
|
+
return classes.join(' ');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const radioStyle = computed(() => {
|
|
160
|
+
const style: Record<string, string> = {};
|
|
161
|
+
if (parentData.value.width) {
|
|
162
|
+
style.width = addUnit(parentData.value.width, 'rpx');
|
|
163
|
+
// #ifdef MP
|
|
164
|
+
// 各家小程序因为它们特殊的编译结构,使用 float 布局
|
|
165
|
+
style.float = 'left';
|
|
166
|
+
// #endif
|
|
167
|
+
// #ifndef MP
|
|
168
|
+
// H5 和 APP 使用 flex 布局
|
|
169
|
+
style.flex = `0 0 ${addUnit(parentData.value.width, 'rpx')}`;
|
|
170
|
+
// #endif
|
|
171
|
+
}
|
|
172
|
+
if (parentData.value.wrap) {
|
|
173
|
+
style.width = '100%';
|
|
174
|
+
// #ifndef MP
|
|
175
|
+
// H5 和 APP 使用 flex 布局,将宽度设置 100%,即可自动换行
|
|
176
|
+
style.flex = '0 0 100%';
|
|
177
|
+
// #endif
|
|
178
|
+
}
|
|
179
|
+
return style;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 点击 label
|
|
184
|
+
*/
|
|
185
|
+
function onClickLabel() {
|
|
186
|
+
if (!elLabelDisabled.value && !elDisabled.value) {
|
|
187
|
+
setRadioCheckedStatus();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 点击 icon
|
|
193
|
+
*/
|
|
194
|
+
function toggle() {
|
|
195
|
+
if (!elDisabled.value) {
|
|
196
|
+
setRadioCheckedStatus();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* 发出事件
|
|
202
|
+
* snake-radio 的 name 不等于父组件的 v-model 的值时(意味着未选中),才发出事件,避免多次点击触发事件
|
|
203
|
+
*/
|
|
204
|
+
function emitEvent() {
|
|
205
|
+
if (parentData.value.value != radioValue.value) emit('change', radioValue.value);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 改变组件选中状态
|
|
210
|
+
* 通过父组件 setValue 更新 v-model,父级变化后所有 radio 由 computed 重新计算选中状态
|
|
211
|
+
*/
|
|
212
|
+
function setRadioCheckedStatus() {
|
|
213
|
+
emitEvent();
|
|
214
|
+
radioGroup.value?.setValue(radioValue.value);
|
|
215
|
+
}
|
|
216
|
+
</script>
|
|
217
|
+
<style scoped>
|
|
218
|
+
.snake-radio {
|
|
219
|
+
/* #ifndef APP-NVUE */
|
|
220
|
+
display: inline-flex;
|
|
221
|
+
/* #endif */
|
|
222
|
+
align-items: center;
|
|
223
|
+
overflow: hidden;
|
|
224
|
+
user-select: none;
|
|
225
|
+
line-height: 1.8;
|
|
226
|
+
}
|
|
227
|
+
.snake-radio__icon-wrap {
|
|
228
|
+
display: flex;
|
|
229
|
+
flex: none;
|
|
230
|
+
align-items: center;
|
|
231
|
+
justify-content: center;
|
|
232
|
+
box-sizing: border-box;
|
|
233
|
+
width: 42rpx;
|
|
234
|
+
height: 42rpx;
|
|
235
|
+
color: transparent;
|
|
236
|
+
text-align: center;
|
|
237
|
+
transition-property: color, border-color, background-color;
|
|
238
|
+
font-size: 20px;
|
|
239
|
+
border: 1px solid var(--snake-color-border, #dcdfe6);
|
|
240
|
+
transition-duration: 0.2s;
|
|
241
|
+
/* #ifdef MP-TOUTIAO */
|
|
242
|
+
/* 头条小程序兼容性问题,需要设置行高为 0,否则图标偏下 */
|
|
243
|
+
line-height: 0;
|
|
244
|
+
/* #endif */
|
|
245
|
+
}
|
|
246
|
+
.snake-radio__icon-wrap--circle {
|
|
247
|
+
border-radius: 100%;
|
|
248
|
+
}
|
|
249
|
+
.snake-radio__icon-wrap--square {
|
|
250
|
+
border-radius: 3px;
|
|
251
|
+
}
|
|
252
|
+
.snake-radio__icon-wrap--checked {
|
|
253
|
+
color: #fff;
|
|
254
|
+
background-color: var(--snake-color-primary, #06d290);
|
|
255
|
+
border-color: var(--snake-color-primary, #06d290);
|
|
256
|
+
}
|
|
257
|
+
.snake-radio__icon-wrap--disabled {
|
|
258
|
+
background-color: var(--snake-color-disabled-bg, #f1f1f1);
|
|
259
|
+
border-color: var(--snake-color-border, #dcdfe6);
|
|
260
|
+
}
|
|
261
|
+
.snake-radio__icon-wrap--disabled--checked {
|
|
262
|
+
color: var(--snake-color-disabled-bg, #f1f1f1) !important;
|
|
263
|
+
}
|
|
264
|
+
.snake-radio__label {
|
|
265
|
+
word-wrap: break-word;
|
|
266
|
+
margin-left: 10rpx;
|
|
267
|
+
margin-right: 24rpx;
|
|
268
|
+
color: var(--snake-color-text, #303133);
|
|
269
|
+
font-size: 30rpx;
|
|
270
|
+
}
|
|
271
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ExtractPropTypes, PropType } from 'vue';
|
|
2
|
+
import type { UnitValue } from '../../libs/function/unit';
|
|
3
|
+
import type { StyleValue } from '../../types/global';
|
|
4
|
+
|
|
5
|
+
/** radioProps 运行时属性及默认值。 */
|
|
6
|
+
export const radioProps = {
|
|
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
|
+
/** 是否禁用。 */
|
|
18
|
+
disabled: { type: [String, Boolean] as PropType<string | boolean>, default: '' },
|
|
19
|
+
/** 是否禁止点击标签选中。 */
|
|
20
|
+
labelDisabled: { type: [String, Boolean] as PropType<string | boolean>, default: '' },
|
|
21
|
+
/** 选中状态下的颜色,设置后将覆盖父级 activeColor。 */
|
|
22
|
+
activeColor: { type: String, default: '' },
|
|
23
|
+
/** 勾选图标的大小,单位 rpx。 */
|
|
24
|
+
iconSize: { type: [String, Number] as PropType<UnitValue>, default: '' },
|
|
25
|
+
/** 标签文字大小,单位 rpx。 */
|
|
26
|
+
labelSize: { type: [String, Number] as PropType<UnitValue>, default: '' },
|
|
27
|
+
/** 组件整体大小,small/default/large 或自定义数值。 */
|
|
28
|
+
size: { type: [String, Number] as PropType<string | number>, default: '' }
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
/** RadioResolved 组件的公开属性。 */
|
|
32
|
+
export type RadioResolvedProps = ExtractPropTypes<typeof radioProps>;
|
|
33
|
+
|
|
34
|
+
/** Radio 组件的公开属性。 */
|
|
35
|
+
export interface RadioProps {
|
|
36
|
+
/** 根节点自定义样式。 */
|
|
37
|
+
customStyle?: StyleValue;
|
|
38
|
+
/** 根节点自定义类名。 */
|
|
39
|
+
customClass?: string;
|
|
40
|
+
/** 展示标签文本。 */
|
|
41
|
+
label?: string;
|
|
42
|
+
/** 数据项名称或唯一标识。 */
|
|
43
|
+
name?: string | number;
|
|
44
|
+
/** 组件形状,square 为方形,circle 为圆形。 */
|
|
45
|
+
shape?: 'square' | 'circle';
|
|
46
|
+
/** 是否禁用。 */
|
|
47
|
+
disabled?: string | boolean;
|
|
48
|
+
/** 是否禁止点击标签选中。 */
|
|
49
|
+
labelDisabled?: string | boolean;
|
|
50
|
+
/** 选中状态下的颜色,设置后将覆盖父级 activeColor。 */
|
|
51
|
+
activeColor?: string;
|
|
52
|
+
/** 勾选图标的大小,单位 rpx。 */
|
|
53
|
+
iconSize?: UnitValue;
|
|
54
|
+
/** 标签文字大小,单位 rpx。 */
|
|
55
|
+
labelSize?: UnitValue;
|
|
56
|
+
/** 组件整体大小,small/default/large 或自定义数值。 */
|
|
57
|
+
size?: string | number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Radio 组件的事件契约。 */
|
|
61
|
+
export type RadioEmits = {
|
|
62
|
+
/** 未选中变为选中时触发,携带当前 radio 的 name。 */
|
|
63
|
+
change: [value: string | number];
|
|
64
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="snake-radio-group snake-radio-group--clearfix" :style="customStyle" :class="customClass">
|
|
3
|
+
<slot />
|
|
4
|
+
</view>
|
|
5
|
+
</template>
|
|
6
|
+
<script setup lang="ts">
|
|
7
|
+
/**
|
|
8
|
+
* @component RadioGroup
|
|
9
|
+
* @description radio 父组件,管理一组 Radio 的互斥值、禁用状态与布局。
|
|
10
|
+
* @see /components/radio
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { inject } from 'vue';
|
|
14
|
+
import { useChildren } from '../../libs/hooks';
|
|
15
|
+
import { RADIO_GROUP_KEY } from './types';
|
|
16
|
+
import { formItemKey } from '../snake-form-item/types';
|
|
17
|
+
import type { RadioGroupEmits, RadioGroupProps } from './types';
|
|
18
|
+
|
|
19
|
+
defineOptions({
|
|
20
|
+
name: 'RadioGroup',
|
|
21
|
+
options: {
|
|
22
|
+
addGlobalClass: true,
|
|
23
|
+
// #ifndef MP-TOUTIAO
|
|
24
|
+
virtualHost: true,
|
|
25
|
+
// #endif
|
|
26
|
+
styleIsolation: 'shared'
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const props = withDefaults(defineProps<RadioGroupProps>(), {
|
|
31
|
+
customStyle: '',
|
|
32
|
+
customClass: '',
|
|
33
|
+
disabled: false,
|
|
34
|
+
modelValue: '',
|
|
35
|
+
activeColor: 'var(--snake-color-primary, #06D290)',
|
|
36
|
+
size: '',
|
|
37
|
+
labelDisabled: false,
|
|
38
|
+
shape: 'circle',
|
|
39
|
+
iconSize: '',
|
|
40
|
+
width: 'auto',
|
|
41
|
+
wrap: false
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const emit = defineEmits<RadioGroupEmits>();
|
|
45
|
+
const formItem = inject(formItemKey, null);
|
|
46
|
+
|
|
47
|
+
// 收集子 radio 并注册父组件上下文(linkChildren 的调用在 setValue 定义之后)
|
|
48
|
+
const { linkChildren } = useChildren(RADIO_GROUP_KEY);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 父组件数据,供子组件使用
|
|
52
|
+
*/
|
|
53
|
+
function getData() {
|
|
54
|
+
return {
|
|
55
|
+
iconSize: props.iconSize,
|
|
56
|
+
labelDisabled: props.labelDisabled,
|
|
57
|
+
disabled: props.disabled,
|
|
58
|
+
shape: props.shape,
|
|
59
|
+
activeColor: props.activeColor,
|
|
60
|
+
size: props.size,
|
|
61
|
+
width: props.width,
|
|
62
|
+
wrap: props.wrap,
|
|
63
|
+
value: props.modelValue
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 设置选中值
|
|
69
|
+
* @param val 选中的 radio 的 name 值
|
|
70
|
+
*/
|
|
71
|
+
function setValue(val: string | number) {
|
|
72
|
+
// 通过 emit 事件,设置父组件通过 v-model 双向绑定的值
|
|
73
|
+
emit('update:modelValue', val);
|
|
74
|
+
emit('change', val);
|
|
75
|
+
// 通知 snake-form-item 进行校验
|
|
76
|
+
void formItem?.notify('change');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 向子 radio 提供上下文:props(含 modelValue)实时联动 + 选中值入口
|
|
80
|
+
linkChildren({ props, setValue });
|
|
81
|
+
|
|
82
|
+
defineExpose({ props, getData, setValue });
|
|
83
|
+
</script>
|
|
84
|
+
<style scoped>
|
|
85
|
+
.snake-radio-group {
|
|
86
|
+
/* #ifndef MP || APP-NVUE */
|
|
87
|
+
display: inline-flex;
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
/* #endif */
|
|
90
|
+
}
|
|
91
|
+
/* MP 下子项以 float 布局时,容器需要清除浮动 */
|
|
92
|
+
.snake-radio-group--clearfix::after {
|
|
93
|
+
content: '';
|
|
94
|
+
display: block;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
clear: both;
|
|
97
|
+
}
|
|
98
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { InjectionKey } from 'vue';
|
|
2
|
+
import type { UnitValue } from '../../libs/function/unit';
|
|
3
|
+
import type { StyleValue } from '../../types/global';
|
|
4
|
+
|
|
5
|
+
/** RadioGroup 组件的公开属性。 */
|
|
6
|
+
export interface RadioGroupProps {
|
|
7
|
+
/** 根节点自定义样式。 */
|
|
8
|
+
customStyle?: StyleValue;
|
|
9
|
+
/** 根节点自定义类名。 */
|
|
10
|
+
customClass?: string;
|
|
11
|
+
/** 是否禁用所有 radio。 */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** 匹配某一个 radio 组件,如果某个 radio 的 name 值等于此值,那么这个 radio 就被会选中。 */
|
|
14
|
+
modelValue?: string | number;
|
|
15
|
+
/** 选中状态下的颜色,应用到所有子 radio。 */
|
|
16
|
+
activeColor?: string;
|
|
17
|
+
/** 组件整体大小,small/default/large 或自定义数值。 */
|
|
18
|
+
size?: string | number;
|
|
19
|
+
/** 是否禁止点击标签选中。 */
|
|
20
|
+
labelDisabled?: boolean;
|
|
21
|
+
/** 组件形状,square 为方形,circle 为圆形。 */
|
|
22
|
+
shape?: 'square' | 'circle';
|
|
23
|
+
/** 勾选图标的大小,单位 rpx。 */
|
|
24
|
+
iconSize?: UnitValue;
|
|
25
|
+
/** 每个 radio 占 snake-radio-group 的宽度,需带单位。 */
|
|
26
|
+
width?: UnitValue;
|
|
27
|
+
/** 是否每个 radio 都换行。 */
|
|
28
|
+
wrap?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** RadioGroup 组件的事件契约。 */
|
|
32
|
+
export type RadioGroupEmits = {
|
|
33
|
+
/** 更新当前选中值。 */
|
|
34
|
+
'update:modelValue': [value: string | number];
|
|
35
|
+
/** 任一个 radio 状态发生变化时触发,携带最新选中值。 */
|
|
36
|
+
change: [value: string | number];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** RadioGroup 向子 radio 提供的配对上下文(useChildren / useParent 通道)。 */
|
|
40
|
+
export interface RadioGroupContext {
|
|
41
|
+
/** 父组件的响应式 props 对象,子项读取 modelValue 派生选中态。 */
|
|
42
|
+
props: RadioGroupProps;
|
|
43
|
+
/** 子项点击后由 group 统一更新 v-model 并派发 change。 */
|
|
44
|
+
setValue(val: string | number): void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** RadioGroup ↔ Radio 配对注入键。 */
|
|
48
|
+
export const RADIO_GROUP_KEY: InjectionKey<RadioGroupContext> = Symbol('snake-radio-group');
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view>
|
|
3
|
+
<view
|
|
4
|
+
class="snake-read-more__content"
|
|
5
|
+
:class="[elId, customClass]"
|
|
6
|
+
:style="[
|
|
7
|
+
{
|
|
8
|
+
height: isLongContent && !showMore ? `${showHeight}rpx` : 'auto',
|
|
9
|
+
textIndent: textIndent
|
|
10
|
+
},
|
|
11
|
+
customStyle
|
|
12
|
+
]"
|
|
13
|
+
>
|
|
14
|
+
<slot />
|
|
15
|
+
</view>
|
|
16
|
+
<view
|
|
17
|
+
v-if="isLongContent"
|
|
18
|
+
class="snake-read-more__toggle"
|
|
19
|
+
:class="{ 'snake-read-more__toggle--open': showMore }"
|
|
20
|
+
:style="[innerShadowStyle]"
|
|
21
|
+
@click="toggleReadMore"
|
|
22
|
+
>
|
|
23
|
+
<text
|
|
24
|
+
class="snake-read-more__toggle__btn"
|
|
25
|
+
:style="{
|
|
26
|
+
fontSize: `${fontSize}rpx`,
|
|
27
|
+
color: color
|
|
28
|
+
}"
|
|
29
|
+
>
|
|
30
|
+
{{ showMore ? openTextValue : closeTextValue }}
|
|
31
|
+
</text>
|
|
32
|
+
<view class="snake-read-more__toggle__btn__icon">
|
|
33
|
+
<snake-icon :color="color" :size="fontSize" :name="showMore ? 'arrow-up' : 'arrow-down'" />
|
|
34
|
+
</view>
|
|
35
|
+
</view>
|
|
36
|
+
</view>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup lang="ts">
|
|
40
|
+
/**
|
|
41
|
+
* @component ReadMore
|
|
42
|
+
* @description 阅读更多,用于内容较长时预先收起一部分、点击展开全部内容的场景,支持自定义提示与阴影。
|
|
43
|
+
* @see /components/read-more
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from 'vue';
|
|
47
|
+
import { guid } from '../../libs/function/guid';
|
|
48
|
+
import { getRect } from '../../libs/function/getRect';
|
|
49
|
+
import { useLocale } from '../../libs/hooks/useLocale';
|
|
50
|
+
import { readMoreProps, type ReadMoreEmits, type ReadMoreExpose } from './types';
|
|
51
|
+
|
|
52
|
+
defineOptions({ name: 'ReadMore', options: { virtualHost: true, styleIsolation: 'shared' } });
|
|
53
|
+
const props = defineProps(readMoreProps);
|
|
54
|
+
const emit = defineEmits<ReadMoreEmits>();
|
|
55
|
+
const { t } = useLocale('readMore');
|
|
56
|
+
|
|
57
|
+
// 是否需要隐藏一部分内容
|
|
58
|
+
const isLongContent = ref(false);
|
|
59
|
+
// 当前隐藏与显示的状态,true 显示,false 收起
|
|
60
|
+
const showMore = ref(false);
|
|
61
|
+
// 生成唯一 class 用于测量内容高度
|
|
62
|
+
const elId = ref('');
|
|
63
|
+
const instance = getCurrentInstance();
|
|
64
|
+
let measureVersion = 0;
|
|
65
|
+
|
|
66
|
+
// 展开后无需阴影,收起时才需要阴影样式
|
|
67
|
+
const innerShadowStyle = computed(() => (showMore.value ? {} : props.shadowStyle));
|
|
68
|
+
|
|
69
|
+
const openTextValue = computed(() => props.openText || t('openText'));
|
|
70
|
+
const closeTextValue = computed(() => props.closeText || t('closeText'));
|
|
71
|
+
|
|
72
|
+
// 监听 toggle 和 showHeight 变化,重新初始化
|
|
73
|
+
watch(
|
|
74
|
+
() => `${props.toggle}-${props.showHeight}`,
|
|
75
|
+
() => {
|
|
76
|
+
init();
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
onMounted(() => {
|
|
81
|
+
elId.value = guid();
|
|
82
|
+
void init();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
/** 初始化内容高度判断,决定是否显示展开/收起按钮。 */
|
|
86
|
+
async function init() {
|
|
87
|
+
const version = ++measureVersion;
|
|
88
|
+
// 先移除折叠高度,避免把已裁切的高度当作完整内容高度。
|
|
89
|
+
isLongContent.value = false;
|
|
90
|
+
await nextTick();
|
|
91
|
+
if (!elId.value) return;
|
|
92
|
+
const rect = await getRect(`.${elId.value}`, instance);
|
|
93
|
+
if (version !== measureVersion) return;
|
|
94
|
+
isLongContent.value = rect.height > uni.upx2px(Number(props.showHeight));
|
|
95
|
+
if (!isLongContent.value) showMore.value = false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
defineExpose<ReadMoreExpose>({ init });
|
|
99
|
+
|
|
100
|
+
/** 展开或收起内容,发出 open/close 事件。 */
|
|
101
|
+
function toggleReadMore() {
|
|
102
|
+
showMore.value = !showMore.value;
|
|
103
|
+
// toggle 为 false 时,隐藏收起部分的内容
|
|
104
|
+
if (props.toggle === false) isLongContent.value = false;
|
|
105
|
+
if (showMore.value) emit('open', props.index);
|
|
106
|
+
else emit('close', props.index);
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<style scoped>
|
|
111
|
+
.snake-read-more__content {
|
|
112
|
+
overflow: hidden;
|
|
113
|
+
font-size: 30rpx;
|
|
114
|
+
color: var(--snake-color-text-secondary, #606266);
|
|
115
|
+
line-height: 1.8;
|
|
116
|
+
text-align: left;
|
|
117
|
+
}
|
|
118
|
+
.snake-read-more__toggle {
|
|
119
|
+
position: relative;
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
width: 100%;
|
|
124
|
+
padding-bottom: 26rpx;
|
|
125
|
+
}
|
|
126
|
+
.snake-read-more__toggle--open {
|
|
127
|
+
padding-top: 0;
|
|
128
|
+
margin-top: 20rpx;
|
|
129
|
+
background: none;
|
|
130
|
+
}
|
|
131
|
+
.snake-read-more__toggle__btn {
|
|
132
|
+
display: flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
justify-content: center;
|
|
135
|
+
line-height: 1;
|
|
136
|
+
}
|
|
137
|
+
.snake-read-more__toggle__btn__icon {
|
|
138
|
+
margin-left: 14rpx;
|
|
139
|
+
}
|
|
140
|
+
</style>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ExtractPropTypes, PropType } from 'vue';
|
|
2
|
+
import type { StyleValue } from '../../types/global';
|
|
3
|
+
|
|
4
|
+
/** readMoreProps 运行时属性及默认值。 */
|
|
5
|
+
export const readMoreProps = {
|
|
6
|
+
/** 根节点自定义样式。 */
|
|
7
|
+
customStyle: { type: [String, Object, Array] as PropType<StyleValue>, default: '' },
|
|
8
|
+
/** 根节点自定义类名。 */
|
|
9
|
+
customClass: { type: String, default: '' },
|
|
10
|
+
/** 默认的显示占位高度,数值按 rpx 处理,内容超出才显示展开按钮。 */
|
|
11
|
+
showHeight: { type: [Number, String] as PropType<number | string>, default: 400 },
|
|
12
|
+
/** 展开后是否显示收起按钮。 */
|
|
13
|
+
toggle: { type: Boolean, default: false },
|
|
14
|
+
/** 收起状态的提示文字。 */
|
|
15
|
+
closeText: { type: String, default: '' },
|
|
16
|
+
/** 展开状态的提示文字。 */
|
|
17
|
+
openText: { type: String, default: '' },
|
|
18
|
+
/** 提示文字的颜色。 */
|
|
19
|
+
color: { type: String, default: 'var(--snake-color-primary, #06D290)' },
|
|
20
|
+
/** 提示文字的大小,数值按 rpx 处理。 */
|
|
21
|
+
fontSize: { type: [Number, String] as PropType<number | string>, default: 28 },
|
|
22
|
+
/** 收起时覆盖在内容底部的阴影样式,对象形式。 */
|
|
23
|
+
shadowStyle: {
|
|
24
|
+
type: [Object, Array] as PropType<StyleValue>,
|
|
25
|
+
default: () => ({
|
|
26
|
+
backgroundImage:
|
|
27
|
+
'linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, var(--snake-color-surface, #fff) 80%)',
|
|
28
|
+
paddingTop: '300rpx',
|
|
29
|
+
marginTop: '-300rpx'
|
|
30
|
+
})
|
|
31
|
+
},
|
|
32
|
+
/** 段落首行缩进的字符个数。 */
|
|
33
|
+
textIndent: { type: String, default: '2em' },
|
|
34
|
+
/** open 和 close 事件回调中返回的标识值。 */
|
|
35
|
+
index: { type: [Number, String] as PropType<number | string>, default: '' }
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
/** ReadMore 组件的公开属性。 */
|
|
39
|
+
export type ReadMoreProps = ExtractPropTypes<typeof readMoreProps>;
|
|
40
|
+
|
|
41
|
+
/** ReadMore 组件的事件契约。 */
|
|
42
|
+
export type ReadMoreEmits = {
|
|
43
|
+
/** 展开时触发。 */
|
|
44
|
+
open: [index: string | number];
|
|
45
|
+
/** 收起时触发。 */
|
|
46
|
+
close: [index: string | number];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/** ReadMore 组件实例公开的方法。 */
|
|
50
|
+
export interface ReadMoreExpose {
|
|
51
|
+
/** 重新测量内容高度并刷新展开状态。 */
|
|
52
|
+
init(): void;
|
|
53
|
+
}
|