添加查看更多组件
This commit is contained in:
230
uni_modules/cool-ui/components/cl-read-more/cl-read-more.uvue
Normal file
230
uni_modules/cool-ui/components/cl-read-more/cl-read-more.uvue
Normal file
@@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<view class="cl-read-more" :class="[pt.className]">
|
||||
<!-- 内容区域 -->
|
||||
<view class="cl-read-more__wrapper" :class="[pt.wrapper?.className]" :style="wrapperStyle">
|
||||
<view class="cl-read-more__content" :class="[pt.content?.className]">
|
||||
<slot></slot>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="cl-read-more__mask"
|
||||
:class="[
|
||||
{
|
||||
'is-show': !isExpanded && showToggle,
|
||||
'is-dark': isDark
|
||||
},
|
||||
pt.mask?.className
|
||||
]"
|
||||
></view>
|
||||
</view>
|
||||
|
||||
<!-- 展开/收起按钮 -->
|
||||
<slot name="toggle" :isExpanded="isExpanded">
|
||||
<view
|
||||
class="cl-read-more__toggle"
|
||||
:class="[
|
||||
{
|
||||
'is-disabled': disabled
|
||||
},
|
||||
pt.toggle?.className
|
||||
]"
|
||||
@tap="toggle"
|
||||
v-if="showToggle"
|
||||
>
|
||||
<cl-text
|
||||
color="primary"
|
||||
:pt="{
|
||||
className: 'text-sm mr-1'
|
||||
}"
|
||||
>
|
||||
{{ isExpanded ? collapseText : expandText }}
|
||||
</cl-text>
|
||||
<cl-icon :name="isExpanded ? collapseIcon : expandIcon" color="primary"></cl-icon>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, getCurrentInstance, ref, onMounted, watch } from "vue";
|
||||
import { getPx, isDark, parsePt } from "@/cool";
|
||||
import type { PassThroughProps } from "../../types";
|
||||
import { t } from "@/locale";
|
||||
|
||||
defineOptions({
|
||||
name: "cl-read-more"
|
||||
});
|
||||
|
||||
// 组件属性定义
|
||||
const props = defineProps({
|
||||
// 透传样式
|
||||
pt: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 是否展开
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 收起状态下的最大高度
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: 80
|
||||
},
|
||||
// 展开文本
|
||||
expandText: {
|
||||
type: String,
|
||||
default: () => t("展开")
|
||||
},
|
||||
// 收起文本
|
||||
collapseText: {
|
||||
type: String,
|
||||
default: () => t("收起")
|
||||
},
|
||||
// 展开图标
|
||||
expandIcon: {
|
||||
type: String,
|
||||
default: "arrow-down-s-line"
|
||||
},
|
||||
// 收起图标
|
||||
collapseIcon: {
|
||||
type: String,
|
||||
default: "arrow-up-s-line"
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
// 事件定义
|
||||
const emit = defineEmits(["update:modelValue", "change", "toggle"]);
|
||||
|
||||
// 插槽定义
|
||||
defineSlots<{
|
||||
toggle(props: { isExpanded: boolean }): any;
|
||||
}>();
|
||||
|
||||
const { proxy } = getCurrentInstance()!;
|
||||
|
||||
// 透传样式类型
|
||||
type PassThrough = {
|
||||
className?: string;
|
||||
wrapper?: PassThroughProps;
|
||||
content?: PassThroughProps;
|
||||
mask?: PassThroughProps;
|
||||
toggle?: PassThroughProps;
|
||||
};
|
||||
|
||||
// 解析透传样式
|
||||
const pt = computed(() => parsePt<PassThrough>(props.pt));
|
||||
|
||||
// 展开状态
|
||||
const isExpanded = ref(props.modelValue);
|
||||
|
||||
// 内容实际高度
|
||||
const contentHeight = ref(0);
|
||||
|
||||
// 是否显示切换按钮
|
||||
const showToggle = ref(true);
|
||||
|
||||
// 包裹器样式
|
||||
const wrapperStyle = computed(() => {
|
||||
const style = {};
|
||||
|
||||
if (showToggle.value) {
|
||||
style["height"] = isExpanded.value ? `${contentHeight.value}px` : `${props.height}rpx`;
|
||||
}
|
||||
|
||||
return style;
|
||||
});
|
||||
|
||||
/**
|
||||
* 切换展开/收起状态
|
||||
*/
|
||||
function toggle() {
|
||||
if (props.disabled) {
|
||||
emit("toggle", isExpanded.value);
|
||||
return;
|
||||
}
|
||||
|
||||
isExpanded.value = !isExpanded.value;
|
||||
emit("update:modelValue", isExpanded.value);
|
||||
emit("change", isExpanded.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容实际高度
|
||||
*/
|
||||
function getContentHeight() {
|
||||
uni.createSelectorQuery()
|
||||
.in(proxy)
|
||||
.select(".cl-read-more__content")
|
||||
.boundingClientRect((node) => {
|
||||
// 获取内容高度
|
||||
contentHeight.value = (node as NodeInfo).height ?? 0;
|
||||
|
||||
// 实际高度是否大于折叠高度
|
||||
showToggle.value = contentHeight.value > getPx(props.height);
|
||||
})
|
||||
.exec();
|
||||
}
|
||||
|
||||
// 监听modelValue变化
|
||||
watch(
|
||||
computed(() => props.modelValue),
|
||||
(val: boolean) => {
|
||||
isExpanded.value = val;
|
||||
}
|
||||
);
|
||||
|
||||
// 组件挂载后获取内容高度
|
||||
onMounted(() => {
|
||||
getContentHeight();
|
||||
});
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
toggle
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cl-read-more {
|
||||
@apply relative;
|
||||
|
||||
&__wrapper {
|
||||
@apply relative duration-300;
|
||||
transition-property: height;
|
||||
}
|
||||
|
||||
&__mask {
|
||||
@apply absolute bottom-0 left-0 w-full h-14 opacity-0 pointer-events-none;
|
||||
|
||||
// #ifndef APP-IOS
|
||||
transition-duration: 200ms;
|
||||
transition-property: opacity;
|
||||
// #endif
|
||||
|
||||
background-image: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
|
||||
|
||||
&.is-dark {
|
||||
background-image: linear-gradient(to top, rgba(30, 30, 30, 1), rgba(30, 30, 30, 0));
|
||||
}
|
||||
|
||||
&.is-show {
|
||||
@apply opacity-100;
|
||||
}
|
||||
}
|
||||
|
||||
&__toggle {
|
||||
@apply flex flex-row items-center justify-center mt-2;
|
||||
|
||||
&.is-disabled {
|
||||
@apply opacity-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
20
uni_modules/cool-ui/components/cl-read-more/props.ts
Normal file
20
uni_modules/cool-ui/components/cl-read-more/props.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { PassThroughProps } from "../../types";
|
||||
|
||||
export type ClReadMorePassThrough = {
|
||||
className?: string;
|
||||
content?: PassThroughProps;
|
||||
mask?: PassThroughProps;
|
||||
toggle?: PassThroughProps;
|
||||
};
|
||||
|
||||
export type ClReadMoreProps = {
|
||||
className?: string;
|
||||
pt?: ClReadMorePassThrough;
|
||||
modelValue?: boolean;
|
||||
height?: any;
|
||||
expandText?: string;
|
||||
collapseText?: string;
|
||||
expandIcon?: string;
|
||||
collapseIcon?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
2
uni_modules/cool-ui/index.d.ts
vendored
2
uni_modules/cool-ui/index.d.ts
vendored
@@ -51,6 +51,7 @@ import type { ClProgressCircleProps, ClProgressCirclePassThrough } from "./compo
|
||||
import type { ClQrcodeProps } from "./components/cl-qrcode/props";
|
||||
import type { ClRadioProps, ClRadioPassThrough } from "./components/cl-radio/props";
|
||||
import type { ClRateProps, ClRatePassThrough } from "./components/cl-rate/props";
|
||||
import type { ClReadMoreProps, ClReadMorePassThrough } from "./components/cl-read-more/props";
|
||||
import type { ClRowProps, ClRowPassThrough } from "./components/cl-row/props";
|
||||
import type { ClSafeAreaProps, ClSafeAreaPassThrough } from "./components/cl-safe-area/props";
|
||||
import type { ClSelectProps, ClSelectPassThrough } from "./components/cl-select/props";
|
||||
@@ -130,6 +131,7 @@ declare module "vue" {
|
||||
"cl-qrcode": (typeof import('./components/cl-qrcode/cl-qrcode.uvue')['default']) & import('vue').DefineComponent<ClQrcodeProps>;
|
||||
"cl-radio": (typeof import('./components/cl-radio/cl-radio.uvue')['default']) & import('vue').DefineComponent<ClRadioProps>;
|
||||
"cl-rate": (typeof import('./components/cl-rate/cl-rate.uvue')['default']) & import('vue').DefineComponent<ClRateProps>;
|
||||
"cl-read-more": (typeof import('./components/cl-read-more/cl-read-more.uvue')['default']) & import('vue').DefineComponent<ClReadMoreProps>;
|
||||
"cl-row": (typeof import('./components/cl-row/cl-row.uvue')['default']) & import('vue').DefineComponent<ClRowProps>;
|
||||
"cl-safe-area": (typeof import('./components/cl-safe-area/cl-safe-area.uvue')['default']) & import('vue').DefineComponent<ClSafeAreaProps>;
|
||||
"cl-select": (typeof import('./components/cl-select/cl-select.uvue')['default']) & import('vue').DefineComponent<ClSelectProps>;
|
||||
|
||||
4
uni_modules/cool-ui/types/component.d.ts
vendored
4
uni_modules/cool-ui/types/component.d.ts
vendored
@@ -238,3 +238,7 @@ declare type ClMarqueeComponentPublicInstance = {
|
||||
stop(): void;
|
||||
reset(): void;
|
||||
};
|
||||
|
||||
declare type ClReadMoreComponentPublicInstance = {
|
||||
toggle(): void;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user