Просмотр исходного кода

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

icssoa 7 месяцев назад
Родитель
Сommit
b434516f38

+ 13 - 2
uni_modules/cool-ui/components/cl-picker-view/cl-picker-view.uvue

@@ -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;
 	});
 
 	// 返回所有列的值或下标

+ 6 - 6
uni_modules/cool-ui/components/cl-select-date/cl-select-date.uvue

@@ -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();
 	}
 );
 

+ 76 - 50
uni_modules/cool-ui/components/cl-select-time/cl-select-time.uvue

@@ -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);
 	}
+}
 
-	// 拆分时间字符串,分别获取小时、分钟、秒
-	const [h, m, s] = val.split(":");
+// 设置值
+function setValue(val: string) {
+	// 声明选中值数组
+	let _value: string[];
 
-	// 按照labelFormat格式化显示文本
-	return labelFormat.value.replace("{H}", h).replace("{m}", m).replace("{s}", s);
-});
+	// 判断输入值是否为空
+	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;
+
+	// 更新文本内容
+	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

+ 92 - 72
uni_modules/cool-ui/components/cl-select/cl-select.uvue

@@ -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 "";
-	}
+		text.value = "";
+	} else {
+		// 用于存储每列的选中值
+		let arr: any[];
 
-	// 用于存储每列的选中值
-	let arr: any[];
+		if (props.columnCount == 1) {
+			// 单列时将值包装为数组
+			arr = [val];
+		} else {
+			// 多列时直接使用数组
+			arr = val as any[];
+		}
 
-	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);
 	}
-
-	// 遍历每列的选中值,查找对应label,找不到则用空字符串
-	return 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