190 lines
3.4 KiB
Plaintext
190 lines
3.4 KiB
Plaintext
<template>
|
|
<view
|
|
class="cl-select-trigger"
|
|
:class="[
|
|
{
|
|
'is-dark': isDark,
|
|
'cl-select-trigger--disabled': isDisabled,
|
|
'cl-select-trigger--focus': focus,
|
|
'cl-select-trigger--error': isError
|
|
},
|
|
pt.className
|
|
]"
|
|
@tap="open"
|
|
>
|
|
<view class="cl-select-trigger__content">
|
|
<cl-text
|
|
v-if="showText"
|
|
:pt="{
|
|
className: parseClass([
|
|
{
|
|
'text-surface-400': isDisabled
|
|
},
|
|
pt.text?.className
|
|
])
|
|
}"
|
|
ellipsis
|
|
>
|
|
{{ text }}
|
|
</cl-text>
|
|
|
|
<cl-text
|
|
:pt="{
|
|
className: parseClass(['text-surface-400', pt.placeholder?.className])
|
|
}"
|
|
v-else
|
|
>
|
|
{{ placeholder }}
|
|
</cl-text>
|
|
</view>
|
|
|
|
<view v-if="showText && !isDisabled" class="cl-select-trigger__icon" @tap.stop="clear">
|
|
<cl-icon
|
|
name="close-circle-fill"
|
|
:size="32"
|
|
:pt="{ className: 'text-surface-400' }"
|
|
></cl-icon>
|
|
</view>
|
|
|
|
<view v-if="!isDisabled && !showText" class="cl-select-trigger__icon">
|
|
<cl-icon
|
|
:name="pt.icon?.name ?? arrowIcon"
|
|
:size="pt.icon?.size ?? 32"
|
|
:pt="{
|
|
className: `text-surface-400 ${pt.icon?.className}`
|
|
}"
|
|
></cl-icon>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from "vue";
|
|
import type { ClIconProps } from "../cl-icon/props";
|
|
import { isDark, parseClass, parsePt } from "@/cool";
|
|
import { t } from "@/locale";
|
|
import type { PassThroughProps } from "../../types";
|
|
import { useForm, useFormItem } from "../../hooks";
|
|
|
|
defineOptions({
|
|
name: "cl-select-trigger"
|
|
});
|
|
|
|
// 组件属性定义
|
|
const props = defineProps({
|
|
// 透传样式配置
|
|
pt: {
|
|
type: Object,
|
|
default: () => ({})
|
|
},
|
|
// 显示文本
|
|
text: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
// 占位符文本
|
|
placeholder: {
|
|
type: String,
|
|
default: () => t("请选择")
|
|
},
|
|
// 箭头图标名称
|
|
arrowIcon: {
|
|
type: String,
|
|
default: "arrow-down-s-line"
|
|
},
|
|
// 是否禁用选择器
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
// 是否聚焦
|
|
focus: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
});
|
|
|
|
const emit = defineEmits(["open", "clear"]);
|
|
|
|
// cl-form 上下文
|
|
const { disabled } = useForm();
|
|
|
|
// cl-form-item 上下文
|
|
const { isError } = useFormItem();
|
|
|
|
// 是否禁用
|
|
const isDisabled = computed(() => {
|
|
return disabled.value || props.disabled;
|
|
});
|
|
|
|
// 透传样式类型定义
|
|
type PassThrough = {
|
|
className?: string; // 根元素类名
|
|
icon?: ClIconProps; // 图标样式
|
|
placeholder?: PassThroughProps; // 占位符样式
|
|
text?: PassThroughProps; // 文本样式
|
|
};
|
|
|
|
// 解析透传样式配置
|
|
const pt = computed(() => parsePt<PassThrough>(props.pt));
|
|
|
|
// 是否显示文本
|
|
const showText = computed(() => props.text != "");
|
|
|
|
// 清空文本
|
|
function clear() {
|
|
emit("clear");
|
|
}
|
|
|
|
// 打开选择器
|
|
function open() {
|
|
if (isDisabled.value) {
|
|
return;
|
|
}
|
|
|
|
emit("open");
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.cl-select-trigger {
|
|
@apply flex flex-row items-center w-full box-border;
|
|
@apply border border-solid border-surface-200 rounded-lg bg-white;
|
|
height: 66rpx;
|
|
padding: 0 20rpx;
|
|
|
|
&__content {
|
|
flex: 1;
|
|
}
|
|
|
|
&__icon {
|
|
@apply flex flex-row items-center justify-center;
|
|
padding-left: 20rpx;
|
|
}
|
|
|
|
&--disabled {
|
|
@apply bg-surface-100 opacity-70;
|
|
}
|
|
|
|
&--focus {
|
|
@apply border-primary-500;
|
|
|
|
&.is-dark {
|
|
@apply border-primary-500;
|
|
}
|
|
}
|
|
|
|
&--error {
|
|
@apply border-red-500;
|
|
}
|
|
|
|
&.is-dark {
|
|
@apply border-surface-700 bg-surface-800;
|
|
|
|
&.cl-select-trigger--disabled {
|
|
@apply bg-surface-700;
|
|
}
|
|
}
|
|
}
|
|
</style>
|