使用vue3以及原生input实现一个可复用的组件(包括各种数组类型,手机号类型,小数类型)

看标题要实现可复用 那我就注册到全局组件里面 在component.ts

javascript 复制代码
//注册全局公共组件
import MxInput from '@/components/common/MxInput.vue' 
const commonComponents = {
    install(Vue) {
        Vue.component('MxInput', MxInput)
    }
};
export default commonComponents;

子组件:

javascript 复制代码
<template>
    <div class="van_input_wrapper">
        <input :type="props.type" :value="props.modelValue" :disabled="props.disabled"  :maxlength="props.maxlength" :placeholder="props.placeholder"  @input="_onInput"  @blur="_onBlur" @click="_click"  :class="{ 'disabled-input': props.disabled, 'error-input': props.error }"   class="van_input" />
        <span  v-if="props.modelValue && !props.disabled" class="input_del" @click="clearInputValue"></span>
    </div>
</template>

<script setup lang="ts">
import { reactive} from 'vue';
// var obj = {
// 1:'下拉列表', 2:'文本', 3:'多行文本', 4:'数字', 5:'小数', 6:'复选框',-->
//  7:"正则表达式", 8:"日期", 9:'短信', 10:'验证码', 11:'表单', 12:'附件',-->
//  13:'评星', 14:'高级复选框', 15:'商品表', 16:'满意度评价表', 17:'文本(电话类型)', 18:'级联',-->
// 19:'地理位置', 20:'资产表', 21:'表单关联', 24:'支付', 23:'签名', 25:'计算字段', 26:'日期时间'-->
// }
interface iObj {
    isDelButtonVisible:boolean
    [key: string]: any
}

//props 定义类型
interface iProps {
    type?:string //input类型
    fieldType?:string //字段类型
    placeholder: string
    maxlength?: string //长度设置
    disabled?: boolean  //disabled
    error?:boolean  //错误样式
    modelValue?: string  //v-model
    [key: string]: any
}
//emit
interface iEmit {
    (e: 'click', value: string): void
    (e: 'input', value: string): void
    (e: 'change', value: string): void
    (e: 'update:modelValue', value: string): void   //更新v-model
}
//vue3中props edit注册
let emit = defineEmits<iEmit>();
let props = withDefaults(defineProps<iProps>(), {
    type:'text'
})

const data:iObj = reactive({
    isDelButtonVisible:false
})
//input事件
function _onInput(event){
    const inputValue = event.target.value;
    const fieldType = props.fieldType;
    const inputElement = event.target;
    console.log(11212,event.target.value,props.fieldType)
    if(fieldType === '5'){
        // 限制小数点后两位
        const pattern = /^-?([1-9]\d*|0)(\.\d+)?$/;
        if (!pattern.test(inputValue)) {
            // 如果不符合格式,则调整输入值
            const parts = inputValue.split('.');
            if (parts.length > 1 && parts[1].length > 2) {
                // 如果小数点后超过两位,则截断
                event.target.value = `${parts[0]}.${parts[1].substring(0, 2)}`;
            }
        }
    }else if(fieldType === '4'){
        //只能输入数字
        inputElement.value = '';
        event.target.value = inputValue.replace(/[^\d]/g, '')
    }
    console.log(22212,event.target.value)
    emit('update:modelValue',event.target.value)
    emit('input',event)
}
//失去焦点
function _onBlur(event) {
    const inputValue = event.target.value;
    const fieldType = props.fieldType;

    if (fieldType === '5') {
        // 检查小数点后是否不足两位
        const parts = inputValue.split('.');
        console.log(parts,parts.length)
        if(inputValue){
            if (parts.length === 2 && parts[1].length === 1) {
                // 如果只有一位小数,则补全为两位
                event.target.value = `${inputValue}0`;
            } else if (parts.length === 1) {
                // 如果没有小数部分,则添加 .00
                event.target.value = `${inputValue}.00`;
            }
        }

        emit('update:modelValue', event.target.value);
    }else if (fieldType === '17') {
        // 手机号正则表达式
        const phonePattern = /^1[3-9]\d{9}$/;
        if (!phonePattern.test(inputValue)) {
            // 如果不是有效的手机号,可以显示错误提示或者进行其他处理
            console.error('请输入有效的手机号');
            // 这里可以添加更多的逻辑,比如显示错误消息或者修改样式等
        }else{
            emit('update:modelValue', inputValue);
        }
    }
}

function _click(event){
    emit('click',event)
}
function clearInputValue() {
    emit('update:modelValue','')
}
</script>

<style scoped lang="less">
.van_input_wrapper{
    position: relative;
}
.van_input{
    width: calc(100% - 38px);
    height: 40px;
    border-radius: 5px;
    border: 1px solid #DDE0E8;
    color:rgba(0,0,0,0.9);
    font-weight: 400;
    font-size: 14px;
    line-height: 42px;
    padding:0 30px 0 8px;
}
.disabled-input{
    background: #F0F2F4;
    border-radius: 4px;
    border: 1px solid #DDE0E8;
}
.error-input{
    box-shadow: 0px 0px 4px 0px rgba(244,78,78,0.5);
    border-radius: 4px;
    border: 1px solid #F44E4E;
}
.input_del{
    display: block;
    position: absolute;
    right: 10px;
    top:14px;
    width: 14px;
    height: 14px;
    background: url("./src/assets/img/input_del.png") no-repeat center center;
    background-size: 14px 14px;
}
.van_input:focus{
    border: 1px solid #0162E2;
    box-shadow: 0 0 4px 0 rgba(1,98,226,0.5);
}
.van_input::-webkit-input-placeholder{
    color:rgba(0,0,0,0.35);
    font-weight: 400;
    font-size: 14px;
}
.van_input:-moz-placeholder, textarea:-moz-placeholder {
    color:rgba(0,0,0,0.35);
    font-weight: 400;
    font-size: 14px;
}
.van_input::-moz-placeholder, textarea::-moz-placeholder {
    color:rgba(0,0,0,0.35);
    font-weight: 400;
    font-size: 14px;
}
.van_input:-ms-input-placeholder, textarea:-ms-input-placeholder {
    color:rgba(0,0,0,0.35);
    font-weight: 400;
    font-size: 14px;
}
</style>
相关推荐
树叶会结冰6 分钟前
HTML语义化:当网页会说话
前端·html
冰万森11 分钟前
解决 React 项目初始化(npx create-react-app)速度慢的 7 个实用方案
前端·react.js·前端框架
牧羊人_myr24 分钟前
Ajax 技术详解
前端
浩男孩33 分钟前
🍀封装个 Button 组件,使用 vitest 来测试一下
前端
蓝银草同学37 分钟前
阿里 Iconfont 项目丢失?手把手教你将已引用的 SVG 图标下载到本地
前端·icon
布列瑟农的星空1 小时前
重学React —— React事件机制 vs 浏览器事件机制
前端
程序定小飞1 小时前
基于springboot的在线商城系统设计与开发
java·数据库·vue.js·spring boot·后端
一小池勺1 小时前
CommonJS
前端·面试
孙牛牛1 小时前
实战分享:一招解决嵌套依赖版本失控问题,以 undici 为例
前端