欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > uniapp微信小程序基于wu-input二次封装TInput组件(支持点击下拉选择、支持整数、电话、小数、身份证、小数点位数控制功能)

uniapp微信小程序基于wu-input二次封装TInput组件(支持点击下拉选择、支持整数、电话、小数、身份证、小数点位数控制功能)

2025/4/12 18:17:00 来源:https://blog.csdn.net/cwin8951/article/details/147065406  浏览:    关键词:uniapp微信小程序基于wu-input二次封装TInput组件(支持点击下拉选择、支持整数、电话、小数、身份证、小数点位数控制功能)

一、 最终效果

在这里插入图片描述

二、实现了功能

1、支持输入正整数---设置`specifyType=integer`
2、支持输入数字(含小数点)---设置`specifyType=decimal`,可设置`decimalLimit`来调整小数点位数
3、支持输入手机号--设置`specifyType=phone`
4、支持输入身份证号---设置`specifyType=idCard`
4、支持失焦后校验错误提示
5、支持title自定义或者slotLabel插槽
6、支持inputType输入框类型可选值:input/select 
7、支持自带下拉选择

三、TInput 参数配置

1、代码示例:

<TInput v-model="value" titlt="标题" />

2. 配置参数(Attributes)继承wu-input及wu-popup的所有参数事件

参数说明类型默认值
v-modelinput绑定值String /number-
v-model:select-valueinputType:select 的绑定值String /number-
titlelabel标题String-
inputType输入框类型可选值:input/selectStringinput
required是否必填红点标识booleanfalse
decimalLimit小数点后保留几位number2
specifyType指定输入类型"text"/“decimal”/“phone” /“integer” / “idCard”Stringtext
showThousands是否显示千分位booleanfalse
isShowErrorTip输入框失焦是否提示错误信息booleanfalse
isLink是否展示右侧箭头(inputType=select自动展示)booleanfalse
iconArrow右侧箭头图标String‘arrow-right’
iconArrowColor右侧箭头颜色String#969799
isColonlabel标题是否显示冒号booleantrue
isShowBorder是否显示下边框booleanfalse
listinputType=select自带下拉数据源array[]
customKey列表项自定义keyStringkey
customLabel列表项自定义labelstringlabel
popupTitle自带下拉框标题显示string-
isPopupTitleBorder自带下拉框标题与列表边框显示booleanfalse

3. Events

事件名说明返回值
clickInputlist没有设置时点击input触发-

4. Slot

事件名说明
slotInput右侧input框插槽
slotLabel左侧label插槽
prefixinput前缀插槽
suffixinput后缀插槽

四、源码

<template><view class="t_input"><view class="list-call" :class="{ is_border: isShowBorder }"><view class="t_input_title" v-if="isShow('slotLabel')"><slot name="slotLabel" /></view><view class="t_input_title" v-else><view class="t_input_required" v-if="required">*</view>{{ title }}<text v-if="isColon">: </text></view><view class="t_input_value_slot" v-if="isShow('slotInput')"><slot name="slotInput" /></view><view class="t_input_value" v-else @click="openPopup"><wu-input v-bind="fieldAttrs" v-model="selectValue" @blur="handleBlur" v-if="inputType === 'input'"><template #prefix><slot name="prefix" /></template><template #suffix><slot name="suffix" /></template></wu-input><wu-input v-bind="fieldAttrs" v-model="finallySelectLabel" v-else><template #prefix><slot name="prefix" /></template><template #suffix><slot name="suffix" /></template></wu-input><wu-icon :name="iconArrow" :color="iconArrowColor" v-if="isLink || inputType === 'select'"></wu-icon></view></view><wu-popup ref="popup" v-bind="{ closeable: true, mode: 'bottom', round: 15, ...attrs }"><view class="t_input_popup-list"><view class="t_input_popup-title" :class="{ 't_input_popup-title-border': isPopupTitleBorder }">{{ popupTitle }}</view><viewclass="t_input_popup-item"v-for="(item, index) in list":key="index"@click="selectItem(item)":class="{ is_active: selectLabel === item[props.customLabel] }">{{ item[props.customLabel] }}</view></view></wu-popup></view>
</template><script lang="ts" setup>
import { ref, computed, useAttrs, useSlots } from "vue";
// 定义 ListItem 接口
interface ListItem {[key: string]: string | number; // 支持任意字符串键customKey: string | number;customLabel: string;
}
interface TInputProps {title?: string;inputType: "input" | "select";decimalLimit?: number; // 小数点后保留几位specifyType?: "text" | "decimal" | "phone" | "integer" | "idCard"; // 指定输入类型showThousands?: boolean; // 是否显示千分位isShowErrorTip?: boolean; // 是否显示错误提示required?: boolean; // 是否必填isLink?: boolean; // 是否展示右侧箭头iconArrow?: string; // 右侧箭头图标iconArrowColor?: string; // 右侧箭头颜色isColon?: boolean; // 是否显示冒号isShowBorder?: boolean; // 是否显示下边框list?: ListItem[]; // 列表项customKey?: string; // 列表项的keycustomLabel?: string; // 列表项的labelpopupTitle?: string; // 弹出框标题isPopupTitleBorder?: boolean; // 是否显示弹出框title的边框modelValue?: string | number; // type:input 的绑定值selectValue?: string | number; // type:select 的绑定值
}
const props = withDefaults(defineProps<TInputProps>(), {title: "",inputType: "input",specifyType: "text",showThousands: false,isShowErrorTip: false,decimalLimit: 2,required: false,list: () => [] as ListItem[],customKey: "key",customLabel: "label",popupTitle: "",isPopupTitleBorder: false,isLink: false,isShowBorder: true,isColon: true,iconArrow: "arrow-right",iconArrowColor: "#969799",modelValue: "",selectValue: ""
});const emit = defineEmits<{(event: "update:modelValue", value: string | number): void;(event: "update:selectValue", value: string | number): void;(event: "clickInput"): void;
}>();
const attrs = useAttrs();
const popup = ref<null | any>(null);
const slots = useSlots();const isShow = (name: string) => {return Object.keys(slots).includes(name);
};const selectLabel = ref<string | number>("");const selectValue = computed({get: () => props.modelValue,set: (val: string | number) => {emit("update:modelValue", val);}
});
const selectModelLabel = computed({get: () => props.selectValue,set: (val: string | number) => {emit("update:selectValue", val);}
});
const finallySelectLabel = computed(() => {if (props?.list?.length > 0) {return selectLabel.value;} else {return selectModelLabel.value;}
});
const handleBlur = () => {let formattedValue = selectValue.value;const formatValue = (value: any, formatter: (val: any) => any) => {if (formatter) {return formatter(value);}return value;};switch (props.specifyType) {case "decimal": // 小数点后保留几位formattedValue = formatValue(Number(selectValue.value), value =>formatDecimal(value, props.decimalLimit));break;case "phone": // 手机号码formattedValue = formatValue(selectValue.value.toString(), validatePhone);break;case "integer": // 整数formattedValue = formatValue(selectValue.value.toString(), validateInteger);break;case "idCard": // 身份证号码formattedValue = formatValue(selectValue.value.toString(), validateIdCard);break;default: // 默认处理formattedValue = selectValue.value;}selectValue.value = formattedValue;
};
// 手机号码校验
const validatePhone = (value: string) => {const phoneReg = /^1[3456789]\d{9}$/;if (phoneReg.test(value)) {return value;} else {props.isShowErrorTip &&uni.showToast({title: "请输入正确的手机号码",icon: "none"});return "";}
};
// 身份证号码校验
const validateIdCard = (value: string) => {const idCardReg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;if (idCardReg.test(value)) {return value;} else {props.isShowErrorTip &&uni.showToast({title: "请输入正确的身份证号码",icon: "none"});return "";}
};
// 整数校验
const validateInteger = (value: string) => {const integerReg = /^\d+$/;if (integerReg.test(value)) {return value;} else {props.isShowErrorTip &&uni.showToast({title: "请输入正确的整数",icon: "none"});return "";}
};
// 小数转换
const formatDecimal = (value: number, decimalLimit: number) => {if (!value) {props.isShowErrorTip &&uni.showToast({title: "请输入正确的数字",icon: "none"});return "";}// 格式化千分号if (props.showThousands) {const val = value.toFixed(decimalLimit).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");return val;} else {return value.toFixed(decimalLimit);}
};
// 计算属性 fieldAttrs
const fieldAttrs = computed(() => ({border: "none",placeholder: props.inputType === "select" ? `请选择${props.title}` : `请输入${props.title}`,readonly: props.inputType === "select",type: "text",inputAlign: "right",clearable: true,...attrs
}));// 选择列表项
const selectItem = (item: ListItem) => {if (props.customLabel && item[props.customLabel]) {selectLabel.value = item[props.customLabel];emit("update:modelValue", item[props.customKey]);popup.value?.close();} else {console.error("Invalid customLabel or item:", props.customLabel, item);}
};// 打开弹窗
const openPopup = () => {if (props.inputType === "select" && props.list.length > 0) {popup.value?.open();} else {emit("clickInput");}
};
</script><style lang="scss" scoped>
.t_input {.list-call {display: flex;height: 54px;align-items: center;padding: 0 10px;&.is_border {border-bottom: 1px solid #eee;}.t_input_title {display: flex;height: inherit;align-items: center;.t_input_required {color: red;}}.t_input_value {flex: 1;display: flex;height: inherit;align-items: center;justify-content: flex-end;}.t_input_value_slot {display: flex;height: inherit;align-items: center;justify-content: flex-end;}}.t_input_popup-list {.t_input_popup-title {display: flex;align-items: center;justify-content: center;font-size: 16px;color: #101010;height: 44px;font-weight: bold;&.t_input_popup-title-border {border-bottom: 1px solid #eee;}}.t_input_popup-item {text-align: center;line-height: 45px;&.is_active {background-color: #f0f0f0;}}}
}
</style>

相关文章

基于ElementUi再次封装基础组件文档


Vue3+Vite+Ts+Pinia+Qiankun后台管理系统


vue3+ts基于Element-plus再次封装基础组件文档

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词