添加 useForm 事件

This commit is contained in:
icssoa
2025-08-06 16:30:49 +08:00
parent ae566bf919
commit da573d0d35
12 changed files with 108 additions and 46 deletions

View File

@@ -358,10 +358,6 @@ const visible = ref(false);
* 检查禁用状态,如果未禁用则显示弹窗
*/
function open() {
if (props.disabled) {
return;
}
visible.value = true;
}

View File

@@ -3,7 +3,7 @@
class="cl-checkbox"
:class="[
{
'cl-checkbox--disabled': disabled,
'cl-checkbox--disabled': isDisabled,
'cl-checkbox--checked': isChecked
},
pt.className
@@ -47,6 +47,7 @@ import { computed, useSlots, type PropType } from "vue";
import type { PassThroughProps } from "../../types";
import { get, parseClass, parsePt, pull } from "@/cool";
import type { ClIconProps } from "../cl-icon/props";
import { useForm } from "../../hooks";
defineOptions({
name: "cl-checkbox"
@@ -99,6 +100,10 @@ const props = defineProps({
const emit = defineEmits(["update:modelValue", "change"]);
const slots = useSlots();
const { disabled } = useForm();
// 是否禁用
const isDisabled = computed(() => props.disabled || disabled.value);
// 透传样式类型定义
type PassThrough = {
@@ -142,7 +147,7 @@ const iconName = computed(() => {
* 在非禁用状态下切换选中状态
*/
function onTap() {
if (!props.disabled) {
if (!isDisabled.value) {
let val = props.modelValue;
if (Array.isArray(val)) {
@@ -166,7 +171,7 @@ function onTap() {
@apply flex flex-row items-center;
&--disabled {
@apply opacity-70;
@apply opacity-50;
}
}
</style>

View File

@@ -3,7 +3,7 @@
class="cl-radio"
:class="[
{
'cl-radio--disabled': disabled,
'cl-radio--disabled': isDisabled,
'cl-radio--checked': isChecked
},
pt.className
@@ -47,6 +47,7 @@ import { computed, useSlots } from "vue";
import type { PassThroughProps } from "../../types";
import { get, parseClass, parsePt } from "@/cool";
import type { ClIconProps } from "../cl-icon/props";
import { useForm } from "../../hooks";
defineOptions({
name: "cl-radio"
@@ -108,6 +109,12 @@ type PassThrough = {
// 解析透传样式配置
const pt = computed(() => parsePt<PassThrough>(props.pt));
// cl-form 上下文
const { disabled } = useForm();
// 是否禁用
const isDisabled = computed(() => props.disabled || disabled.value);
// 是否为选中状态
const isChecked = computed(() => props.modelValue == props.value);
@@ -130,7 +137,7 @@ const iconName = computed(() => {
* 在非禁用状态下切换选中状态
*/
function onTap() {
if (!props.disabled) {
if (!isDisabled.value) {
emit("update:modelValue", props.value);
emit("change", props.value);
}
@@ -142,7 +149,7 @@ function onTap() {
@apply flex flex-row items-center;
&--disabled {
@apply opacity-70;
@apply opacity-50;
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<view class="cl-rate" :class="[pt.className]">
<view class="cl-rate" :class="[{ 'cl-rate--disabled': isDisabled }, pt.className]">
<view
v-for="(item, index) in max"
:key="index"
@@ -48,6 +48,7 @@ import { computed } from "vue";
import { parseClass, parsePt } from "@/cool";
import type { PassThroughProps } from "../../types";
import type { ClIconProps } from "../cl-icon/props";
import { useForm } from "../../hooks";
defineOptions({
name: "cl-rate"
@@ -126,6 +127,12 @@ type PassThrough = {
// 解析透传样式
const pt = computed(() => parsePt<PassThrough>(props.pt));
// cl-form 上下文
const { disabled } = useForm();
// 是否禁用
const isDisabled = computed(() => props.disabled || disabled.value);
// 获取图标激活宽度
function getIconActiveWidth(item: number) {
// 如果评分值大于等于当前项,返回null表示完全填充
@@ -144,7 +151,7 @@ function getIconActiveWidth(item: number) {
// 点击事件处理
function onTap(index: number) {
if (props.disabled) {
if (isDisabled.value) {
return;
}
@@ -176,11 +183,14 @@ function onTap(index: number) {
.cl-rate {
@apply flex flex-row items-center;
&--disabled {
@apply opacity-50;
}
&__item {
@apply flex items-center justify-center relative duration-200;
@apply flex items-center justify-center relative duration-200 overflow-hidden;
transition-property: color;
margin-right: 6rpx;
overflow: hidden;
}
}
</style>

View File

@@ -51,7 +51,7 @@
@tap="setRange(0)"
>
<cl-text
v-if="values[0] != ''"
v-if="values.length > 0 && values[0] != ''"
:pt="{
className: 'text-center'
}"
@@ -78,7 +78,7 @@
@tap="setRange(1)"
>
<cl-text
v-if="values[1] != ''"
v-if="values.length > 1 && values[1] != ''"
:pt="{
className: 'text-center'
}"
@@ -393,10 +393,14 @@ const list = computed(() => {
).toArray();
// 解析结束日期为年月日时分秒数组
const [endYear, endMonth, endDate, endHour, endMinute, endSecond] = dayUts(props.end).toArray();
// 获取当前选中的年月日时分秒值
const [year, month, date, hour, minute] = value.value;
// 初始化年月日时分秒六个选项数组
const arr = [[], [], [], [], [], []] as ClSelectOption[][];
// 边界处理如果value为空返回空数组
if (isEmpty(value.value)) {
return arr;
}
// 获取当前选中的年月日时分秒值
const [year, month, date, hour, minute] = value.value;
// 判断是否为闰年
const isLeapYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
// 根据月份和是否闰年获取当月天数

View File

@@ -3,7 +3,7 @@
class="cl-slider"
:class="[
{
'cl-slider--disabled': disabled
'cl-slider--disabled': isDisabled
},
pt.className
]"
@@ -62,14 +62,16 @@
></view>
</view>
<cl-text
v-if="showValue"
:pt="{
className: parseClass(['text-center w-[100rpx]', pt.value?.className])
}"
>
{{ displayValue }}
</cl-text>
<slot name="value" :value="displayValue">
<cl-text
v-if="showValue"
:pt="{
className: parseClass(['text-center w-[100rpx]', pt.value?.className])
}"
>
{{ displayValue }}
</cl-text>
</slot>
</view>
</template>
@@ -77,6 +79,7 @@
import { computed, getCurrentInstance, nextTick, onMounted, ref, watch, type PropType } from "vue";
import { parseClass, parsePt, rpx2px } from "@/cool";
import type { PassThroughProps } from "../../types";
import { useForm } from "../../hooks";
defineOptions({
name: "cl-slider"
@@ -157,6 +160,12 @@ type PassThrough = {
// 计算样式穿透对象
const pt = computed(() => parsePt<PassThrough>(props.pt));
// cl-form 上下文
const { disabled } = useForm();
// 是否禁用
const isDisabled = computed(() => props.disabled || disabled.value);
// 当前滑块的值,单值模式
const value = ref<number>(props.modelValue);
@@ -356,7 +365,7 @@ function updateValue(newValue: number | number[]) {
// 触摸开始事件:获取轨道信息并初始化滑块位置
async function onTouchStart(e: TouchEvent) {
if (props.disabled) return;
if (isDisabled.value) return;
// 先获取轨道的位置和尺寸信息,这是后续计算的基础
await getTrackInfo();
@@ -381,7 +390,7 @@ async function onTouchStart(e: TouchEvent) {
// 触摸移动事件:实时更新滑块位置
function onTouchMove(e: TouchEvent) {
if (props.disabled) return;
if (isDisabled.value) return;
const clientX = e.touches[0].clientX;
const calculatedValue = calculateValue(clientX);
@@ -399,7 +408,7 @@ function onTouchMove(e: TouchEvent) {
// 触摸结束事件完成拖动触发最终的change事件
function onTouchEnd() {
if (props.disabled) return;
if (isDisabled.value) return;
// 触发change事件表示用户完成了一次完整的拖动操作
if (props.range) {
@@ -500,8 +509,7 @@ onMounted(() => {
@apply flex flex-row items-center w-full overflow-visible;
&--disabled {
opacity: 0.6;
pointer-events: none;
@apply opacity-50;
}
&__inner {
@@ -528,6 +536,8 @@ onMounted(() => {
transform: translateY(-50%);
pointer-events: none;
z-index: 1;
border-width: 4rpx;
box-shadow: 0 0 2rpx 2rpx rgba(100, 100, 100, 0.1);
&--min {
z-index: 2;

View File

@@ -3,7 +3,7 @@
class="cl-switch"
:class="[
{
'cl-switch--disabled': disabled,
'cl-switch--disabled': isDisabled,
'cl-switch--checked': isChecked
},
@@ -53,6 +53,7 @@ import { computed, ref, watch } from "vue";
import { isDark, parseClass, parsePt } from "@/cool";
import type { PassThroughProps } from "../../types";
import { vibrate } from "@/uni_modules/cool-vibrate";
import { useForm } from "../../hooks";
defineOptions({
name: "cl-switch"
@@ -107,6 +108,12 @@ type PassThrough = {
// 解析透传样式配置
const pt = computed(() => parsePt<PassThrough>(props.pt));
// cl-form 上下文
const { disabled } = useForm();
// 是否禁用
const isDisabled = computed(() => props.disabled || disabled.value);
// 绑定值
const value = ref(props.modelValue);
@@ -147,7 +154,7 @@ const rect = computed<Rect>(() => {
* 在非禁用且非加载状态下切换开关状态
*/
function onTap() {
if (!props.disabled && !props.loading) {
if (!isDisabled.value && !props.loading) {
// 切换开关状态
const val = !value.value;
value.value = val;

View File

@@ -5,7 +5,8 @@
:class="[
isDark ? 'text-surface-50' : 'text-surface-700',
{
'truncate w-full': ellipsis
'truncate w-full': ellipsis,
'cl-text--pre-wrap': preWrap
},
{
'!text-primary-500': color == 'primary',
@@ -35,7 +36,8 @@
:class="[
isDark ? 'text-surface-50' : 'text-surface-700',
{
'truncate w-full': ellipsis
'truncate w-full': ellipsis,
'cl-text--pre-wrap': preWrap
},
{
'!text-primary-500': color == 'primary',
@@ -140,6 +142,11 @@ const props = defineProps({
decode: {
type: Boolean,
default: false
},
// 是否保留单词
preWrap: {
type: Boolean,
default: false
}
});
@@ -268,5 +275,11 @@ const content = computed(() => {
<style lang="scss" scoped>
.cl-text {
@apply text-md;
&--pre-wrap {
// #ifdef H5
white-space: pre-wrap;
// #endif
}
}
</style>

View File

@@ -145,6 +145,11 @@ const props = defineProps({
disabled: {
type: Boolean,
default: false
},
// 演示用,本地预览
test: {
type: Boolean,
default: false
}
});
@@ -330,6 +335,13 @@ function choose(index: number) {
// 添加到列表并获取唯一ID
const uid = append(file.path);
// 测试用,本地预览
if (props.test) {
update(uid, { url: file.path, progress: 100 });
emit("success", file.path, uid);
return;
}
// 开始上传文件
uploadFile(file, {
// 上传进度回调