显示文本异常、弹窗打开时未重置值的问题

This commit is contained in:
icssoa
2025-08-21 22:15:11 +08:00
parent 7dccf02c03
commit b434516f38
4 changed files with 188 additions and 131 deletions

View File

@@ -56,7 +56,7 @@
</template>
<script setup lang="ts">
import { forInObject, isDark, isEqual, parseClass, rpx2px } from "@/cool";
import { forInObject, isDark, isEqual, isNull, parseClass, rpx2px } from "@/cool";
import type { ClSelectOption } from "../../types";
import { parseRpx } from "@/cool";
import { computed } from "vue";
@@ -153,6 +153,17 @@ function onChange(e: UniPickerViewChangeEvent) {
// 获取选择器当前选中值数组
const indexs = e.detail.value;
// 处理因快速滑动导致下级数据未及时渲染而产生的索引越界问题
indexs.forEach((v, i, arr) => {
if (i < props.columns.length) {
const n = props.columns[i].length;
if (v >= n) {
arr[i] = n - 1;
}
}
});
// 相同值不触发事件
if (isEqual(indexs, props.value)) {
return;
@@ -160,7 +171,7 @@ function onChange(e: UniPickerViewChangeEvent) {
// 获取所有列的值
const values = props.columns.map((c, i) => {
return c[indexs[i]].value;
return isNull(c[indexs[i]]) ? 0 : c[indexs[i]].value;
});
// 返回所有列的值或下标

View File

@@ -608,11 +608,11 @@ function checkDate(values: number[]): number[] {
return [year, month, date, hour, minute, second];
}
// 显示文本,展示当前选中的日期字符串
// 显示文本
const text = ref("");
// 获取显示文本格式化为labelFormat格式
function getText() {
// 更新文本内容
function updateText() {
if (props.rangeable) {
text.value = values.value
.map((e) => dayUts(e).format(labelFormat.value))
@@ -661,7 +661,7 @@ function setValue(val: string) {
} else {
// 否则解析为数组
value.value = checkDate(dayUts(val).toArray());
getText();
updateText();
}
}
@@ -792,7 +792,7 @@ function confirm() {
}
// 更新显示文本
getText();
updateText();
// 关闭选择器
close();
@@ -824,7 +824,7 @@ watch(
watch(
computed(() => props.labelFormat),
() => {
getText();
updateText();
}
);

View File

@@ -217,21 +217,74 @@ const columns = computed(() => {
});
// 显示文本
const text = computed(() => {
const text = ref("");
// 更新文本内容
function updateText() {
// 获取当前v-model绑定的时间字符串
const val = props.modelValue;
// 如果值为空或为null返回空字符串
if (isEmpty(val) || isNull(val)) {
return "";
text.value = "";
} else {
// 拆分时间字符串,分别获取小时、分钟、秒
const [h, m, s] = val.split(":");
// 按照labelFormat格式化显示文本
text.value = labelFormat.value.replace("{H}", h).replace("{m}", m).replace("{s}", s);
}
}
// 设置值
function setValue(val: string) {
// 声明选中值数组
let _value: string[];
// 判断输入值是否为空
if (isEmpty(val) || isNull(val)) {
// 设置空数组
_value = [];
} else {
// 按冒号分割字符串为数组
_value = val.split(":");
}
// 拆分时间字符串,分别获取小时、分钟、秒
const [h, m, s] = val.split(":");
// 声明索引数组
let _indexes = [] as number[];
// 按照labelFormat格式化显示文本
return labelFormat.value.replace("{H}", h).replace("{m}", m).replace("{s}", s);
});
// 遍历时分秒三列
for (let i = 0; i < 3; i++) {
// 判断是否需要设置默认值
if (i >= _value.length) {
// 添加默认索引0
_indexes.push(0);
// 添加默认值
_value.push(list.value[i][0].value as string);
} else {
// 查找当前值对应的索引
let index = list.value[i].findIndex((e) => e.value == _value[i]);
// 索引无效时重置为0
if (index < 0) {
index = 0;
}
// 添加索引
_indexes.push(index);
}
}
// 更新选中值
value.value = _value;
// 更新索引值
indexes.value = _indexes;
// 更新文本内容
updateText();
}
// 选择器值改变事件
function onChange(a: number[]) {
@@ -265,7 +318,13 @@ function open(cb: ((value: string) => void) | null = null) {
return;
}
// 显示选择器弹窗
visible.value = true;
// 设置值
setValue(props.modelValue);
// 保存回调函数
callback = cb;
}
@@ -276,6 +335,7 @@ function close() {
// 清空选择器
function clear() {
text.value = "";
emit("update:modelValue", "");
emit("change", "");
}
@@ -302,55 +362,21 @@ function confirm() {
watch(
computed(() => props.modelValue),
(val: string) => {
// 声明选中值数组
let _value: string[];
// 判断输入值是否为空
if (isEmpty(val) || isNull(val)) {
// 设置空数组
_value = [];
} else {
// 按冒号分割字符串为数组
_value = val.split(":");
}
// 声明索引数组
let _indexes = [] as number[];
// 遍历时分秒三列
for (let i = 0; i < 3; i++) {
// 判断是否需要设置默认值
if (i >= _value.length) {
// 添加默认索引0
_indexes.push(0);
// 添加默认值
_value.push(list.value[i][0].value as string);
} else {
// 查找当前值对应的索引
let index = list.value[i].findIndex((e) => e.value == _value[i]);
// 索引无效时重置为0
if (index < 0) {
index = 0;
}
// 添加索引
_indexes.push(index);
}
}
// 更新选中值
value.value = _value;
// 更新索引值
indexes.value = _indexes;
setValue(val);
},
{
immediate: true
}
);
// 监听labelFormat和type变化
watch(
computed(() => [props.labelFormat, props.type]),
() => {
updateText();
}
);
defineExpose({
open,
close

View File

@@ -68,7 +68,7 @@
<script setup lang="ts">
import { ref, computed, type PropType, watch } from "vue";
import type { ClSelectOption } from "../../types";
import { isEmpty, parsePt } from "@/cool";
import { isEmpty, isNull, parsePt } from "@/cool";
import type { ClSelectTriggerPassThrough } from "../cl-select-trigger/props";
import type { ClPopupPassThrough } from "../cl-popup/props";
import { t } from "@/locale";
@@ -213,37 +213,101 @@ const columns = computed<ClSelectOption[][]>(() => {
});
// 显示文本
const text = computed(() => {
// 获取当前v-model绑定的值
const text = ref("");
// 更新文本内容
function updateText() {
// 当前绑定的值
const val = props.modelValue;
// 如果值为null或空直接返回空字符串
if (val == null || isEmpty(val)) {
return "";
}
// 用于存储每列的选中值
let arr: any[];
if (props.columnCount == 1) {
// 单列时将值包装为数组
arr = [val];
text.value = "";
} else {
// 多列时直接使用数组
arr = val as any[];
}
// 用于存储每列的选中值
let arr: any[];
// 遍历每列的选中值查找对应label找不到则用空字符串
return arr
.map((e, i) => columns.value[i].find((a) => a.value == e)?.label ?? "")
.join(props.splitor);
});
if (props.columnCount == 1) {
// 单列时将值包装为数组
arr = [val];
} else {
// 多列时直接使用数组
arr = val as any[];
}
// 遍历每列的选中值查找对应label找不到则用空字符串
text.value = arr
.map((e, i) => columns.value[i].find((a) => a.value == e)?.label ?? "")
.join(props.splitor);
}
}
// 获取当前选中值
function getValue() {
return props.columnCount == 1 ? value.value[0] : value.value;
}
// 解析值
function setValue(val: Value) {
// 声明选中值数组
let _value: any[];
// 判断值是否为null
if (val == null) {
// 设置为空数组
_value = [];
}
// 判断是否为数组类型
else if (Array.isArray(val)) {
// 使用该数组
_value = [...(val as any[])];
}
// 其他类型
else {
// 转换为数组格式
_value = [val];
}
// 存储每列选中项的索引值
let _indexes = [] as number[];
// 遍历所有列
for (let i = 0; i < props.columnCount; i++) {
// 判断是否超出选中值数组长度
if (i >= _value.length) {
// 添加默认索引0
_indexes.push(0);
// 添加默认值
if (!isNull(columns.value[i][0])) {
_value.push(columns.value[i][0].value);
}
}
// 在范围内
else {
// 查找匹配的选项索引
let index = columns.value[i].findIndex((e) => e.value == _value[i]);
// 索引无效时重置为0
if (index < 0) {
index = 0;
}
// 添加索引
_indexes.push(index);
}
}
// 更新选中值
value.value = _value;
// 更新索引值
indexes.value = _indexes;
// 更新显示文本
updateText();
}
// 选择器值改变事件
function onChange(a: number[]) {
// 复制当前组件内部维护的索引数组
@@ -271,7 +335,7 @@ function onChange(a: number[]) {
// 更新组件内部维护的索引数组
indexes.value = b;
// 根据最新的索引数组,更新选中的值数组
value.value = b.map((e, i) => columns.value[i][e].value);
value.value = b.map((e, i) => (isNull(columns.value[i][e]) ? 0 : columns.value[i][e].value));
// 触发changing事件
emit("changing", getValue());
@@ -286,6 +350,11 @@ let callback: ((value: Value) => void) | null = null;
// 打开选择器
function open(cb: ((value: Value) => void) | null = null) {
visible.value = true;
// 设置值
setValue(props.modelValue);
// 回调
callback = cb;
}
@@ -296,6 +365,8 @@ function close() {
// 清空选择器
function clear() {
text.value = "";
if (props.columnCount == 1) {
emit("update:modelValue", null);
emit("change", null);
@@ -327,58 +398,7 @@ function confirm() {
watch(
computed(() => props.modelValue),
(val: Value) => {
// 声明选中值数组
let _value: any[];
// 判断值是否为null
if (val == null) {
// 设置为空数组
_value = [];
}
// 判断是否为数组类型
else if (Array.isArray(val)) {
// 使用该数组
_value = [...(val as any[])];
}
// 其他类型
else {
// 转换为数组格式
_value = [val];
}
// 存储每列选中项的索引值
let _indexes = [] as number[];
// 遍历所有列
for (let i = 0; i < props.columnCount; i++) {
// 判断是否超出选中值数组长度
if (i >= _value.length) {
// 添加默认索引0
_indexes.push(0);
// 添加默认值
_value.push(columns.value[i][0].value);
}
// 在范围内
else {
// 查找匹配的选项索引
let index = columns.value[i].findIndex((e) => e.value == _value[i]);
// 索引无效时重置为0
if (index < 0) {
index = 0;
}
// 添加索引
_indexes.push(index);
}
}
// 更新选中值
value.value = _value;
// 更新索引值
indexes.value = _indexes;
setValue(val);
},
{
immediate: true