使用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>
相关推荐
鑫~阳25 分钟前
html + css 淘宝网实战
前端·css·html
Catherinemin30 分钟前
CSS|14 z-index
前端·css
漫天转悠30 分钟前
Vue3项目中引入TailwindCSS(图文详情)
vue.js
qq_589568101 小时前
Echarts+vue电商平台数据可视化——后台实现笔记
vue.js·信息可视化·echarts
2401_882727572 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架
NoneCoder2 小时前
CSS系列(36)-- Containment详解
前端·css
anyup_前端梦工厂2 小时前
初始 ShellJS:一个 Node.js 命令行工具集合
前端·javascript·node.js
5hand2 小时前
Element-ui的使用教程 基于HBuilder X
前端·javascript·vue.js·elementui
GDAL3 小时前
vue3入门教程:ref能否完全替代reactive?
前端·javascript·vue.js
六卿3 小时前
react防止页面崩溃
前端·react.js·前端框架