分享一个完整的uniapp车牌号输入组件

UniApp车牌号输入组件封装摘要: 该组件提供标准化的车牌号输入功能,支持普通车牌和新能源车牌两种类型切换。主要特性包括: 智能键盘:自动切换省份、字母和数字键盘 新能源车牌支持:自动适配9位车牌格式 交互体验:点击车牌位自动弹出对应键盘 双向绑定:支持v-model绑定车牌值 可配置性:可设置初始车牌类型和是否显示类型选择器 组件采用Vue单文件组件形式开发,包含完整的模板、脚本和样式,可直接在UniApp项目中引用。通过watch监听value变化实现双向绑定,提供plate-type-change事
车牌号输入功能标准的uniapp组件形式,方便在项目中调用:

<!-- components/LicensePlateInput.vue -->
<template>
  <view class="license-plate-input">
    <!-- 车牌类型选择 -->
    <view class="plate-type-selector" v-if="showTypeSelector">
      <view 
        class="type-item" 
        :class="{ active: plateType === 'normal' }"
        @tap="switchPlateType('normal')"
      >
        普通车牌
      </view>
      <view 
        class="type-item" 
        :class="{ active: plateType === 'newEnergy' }"
        @tap="switchPlateType('newEnergy')"
      >
        新能源车牌
      </view>
    </view>
    
    <!-- 车牌显示区域 -->
    <view class="plate-display" :class="plateType">
      <view 
        class="plate-item" 
        :class="{ 'plate-item-active': index === activeIndex }"
        v-for="(item, index) in displayPlateArray" 
        :key="index"
        @tap="focusInput(index)"
      >
        {{ item || '' }}
      </view>
    </view>
    
    <!-- 键盘容器 -->
    <u-popup v-model="showKeyboard" mode="bottom" border-radius="20">
      <view class="keyboard-container">
        <view class="keyboard-header">
          <text class="keyboard-title">{{ getKeyboardTitle() }}</text>
          <u-icon name="close" @click="showKeyboard = false"></u-icon>
        </view>
        
        <view class="keyboard-keys">
          <view 
            class="key-item" 
            v-for="(key, index) in currentKeys" 
            :key="index"
            @tap="selectKey(key)"
          >
            {{ key }}
          </view>
          <view 
            class="key-item key-delete" 
            @tap="deleteKey"
            v-if="keyboardType !== 'province'"
          >
            删除
          </view>
        </view>
        
        <view class="keyboard-toggle" v-if="keyboardType !== 'province' && plateType === 'normal'">
          <view 
            class="toggle-btn" 
            :class="{ 'active': keyboardType === 'alphabet' }"
            @tap="switchKeyboard('alphabet')"
          >
            ABC
          </view>
          <view 
            class="toggle-btn" 
            :class="{ 'active': keyboardType === 'number' }"
            @tap="switchKeyboard('number')"
          >
            123
          </view>
        </view>
      </view>
    </u-popup>
  </view>
</template>

<script>
export default {
  name: 'LicensePlateInput',
  props: {
    // 初始车牌类型
    initPlateType: {
      type: String,
      default: 'normal' // normal 或 newEnergy
    },
    // 是否显示车牌类型选择器
    showTypeSelector: {
      type: Boolean,
      default: true
    },
    // 初始车牌号码
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      plateType: this.initPlateType,
      plateArray: new Array(8).fill(''),
      newEnergyPlateArray: new Array(9).fill(''),
      activeIndex: 0,
      showKeyboard: false,
      keyboardType: 'province' // province, alphabet, number
    }
  },
  computed: {
    provinceKeys() {
      return [
        '京', '津', '冀', '晋', '蒙', '辽', '吉', '黑', '沪', '苏', 
        '浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '粤', '桂', 
        '琼', '渝', '川', '贵', '云', '藏', '陕', '甘', '青', '宁', 
        '新', '港', '澳', '台', '使', '领', '警', '学', '试'
      ]
    },
    alphabetKeys() {
      return [
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
        'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
        'W', 'X', 'Y', 'Z'
      ]
    },
    numberKeys() {
      return [
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
      ]
    },
    newEnergyKeys() {
      return [
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'A', 'B', 'C', 'D', 'E', 'F'
      ]
    },
    currentKeys() {
      // 新能源车牌特殊处理
      if (this.plateType === 'newEnergy') {
        // 新能源车牌最后一位只能是数字或特定字母
        if (this.activeIndex === 8) {
          return this.newEnergyKeys;
        }
      }
      
      switch(this.keyboardType) {
        case 'province':
          return this.provinceKeys;
        case 'alphabet':
          return this.alphabetKeys;
        case 'number':
          return this.numberKeys;
        default:
          return this.provinceKeys;
      }
    },
    displayPlateArray() {
      return this.plateType === 'newEnergy' ? this.newEnergyPlateArray : this.plateArray;
    }
  },
  watch: {
    value: {
      handler(newVal) {
        if (newVal) {
          this.setPlateNumber(newVal);
        }
      },
      immediate: true
    }
  },
  methods: {
    switchPlateType(type) {
      this.plateType = type;
      this.activeIndex = 0;
      this.showKeyboard = false;
      this.$emit('plate-type-change', type);
    },
    
    focusInput(index) {
      this.activeIndex = index;
      this.showKeyboard = true;
      
      // 根据车牌类型和位置确定键盘类型
      if (this.plateType === 'normal') {
        if (index === 0) {
          this.keyboardType = 'province';
        } else if (index === 1) {
          this.keyboardType = 'alphabet';
        } else {
          this.keyboardType = 'number';
        }
      } else {
        // 新能源车牌
        if (index === 0) {
          this.keyboardType = 'province';
        } else if (index === 1) {
          this.keyboardType = 'alphabet';
        } else if (index >= 2 && index <= 7) {
          this.keyboardType = 'number';
        } else if (index === 8) {
          // 新能源最后一位可以是数字或特定字母
          this.keyboardType = 'number';
        }
      }
    },
    
    selectKey(key) {
      // 设置当前位的值
      if (this.plateType === 'newEnergy') {
        this.$set(this.newEnergyPlateArray, this.activeIndex, key);
      } else {
        this.$set(this.plateArray, this.activeIndex, key);
      }
      
      // 自动跳转到下一位
      const maxIndex = this.plateType === 'newEnergy' ? 8 : 7;
      if (this.activeIndex < maxIndex) {
        this.activeIndex++;
        
        // 根据车牌类型和位置自动切换键盘类型
        if (this.plateType === 'normal') {
          if (this.activeIndex === 1) {
            this.keyboardType = 'alphabet';
          } else {
            this.keyboardType = 'number';
          }
        } else {
          // 新能源车牌
          if (this.activeIndex === 1) {
            this.keyboardType = 'alphabet';
          } else if (this.activeIndex >= 2 && this.activeIndex <= 7) {
            this.keyboardType = 'number';
          } else if (this.activeIndex === 8) {
            this.keyboardType = 'number';
          }
        }
      } else {
        // 最后一位输入完成后隐藏键盘
        this.showKeyboard = false;
      }
      
      // 触发输入事件
      this.$emit('input', this.getPlateNumber());
    },
    
    deleteKey() {
      if (this.activeIndex > 0) {
        // 清空当前位
        if (this.plateType === 'newEnergy') {
          this.$set(this.newEnergyPlateArray, this.activeIndex, '');
        } else {
          this.$set(this.plateArray, this.activeIndex, '');
        }
        // 如果当前位已空,则跳转到上一位
        if (this.getCurrentPlateArray()[this.activeIndex] === '') {
          this.activeIndex--;
        }
      } else {
        // 第一位时直接清空
        if (this.plateType === 'newEnergy') {
          this.$set(this.newEnergyPlateArray, this.activeIndex, '');
        } else {
          this.$set(this.plateArray, this.activeIndex, '');
        }
      }
      
      // 触发输入事件
      this.$emit('input', this.getPlateNumber());
    },
    
    switchKeyboard(type) {
      this.keyboardType = type;
    },
    
    getKeyboardTitle() {
      if (this.plateType === 'newEnergy' && this.activeIndex === 8) {
        return '选择数字或字母(A-F)';
      }
      
      switch(this.keyboardType) {
        case 'province':
          return '选择省份';
        case 'alphabet':
          return '选择字母';
        case 'number':
          return '选择数字';
        default:
          return '选择字符';
      }
    },
    
    getCurrentPlateArray() {
      return this.plateType === 'newEnergy' ? this.newEnergyPlateArray : this.plateArray;
    },
    
    getPlateNumber() {
      const plateArray = this.plateType === 'newEnergy' ? this.newEnergyPlateArray : this.plateArray;
      return plateArray.join('');
    },
    
    // 设置车牌号码
    setPlateNumber(plateNumber) {
      if (!plateNumber) return;
      
      const len = plateNumber.length;
      if (len === 8) {
        this.plateType = 'normal';
        for (let i = 0; i < 8; i++) {
          this.$set(this.plateArray, i, plateNumber[i] || '');
        }
      } else if (len === 9) {
        this.plateType = 'newEnergy';
        for (let i = 0; i < 9; i++) {
          this.$set(this.newEnergyPlateArray, i, plateNumber[i] || '');
        }
      }
    },
    
    // 清空车牌号码
    clearPlate() {
      this.plateArray = new Array(8).fill('');
      this.newEnergyPlateArray = new Array(9).fill('');
      this.activeIndex = 0;
      this.$emit('input', '');
    }
  }
}
</script>

<style lang="scss" scoped>
.license-plate-input {
  padding: 20rpx;
}

.plate-type-selector {
  display: flex;
  justify-content: center;
  margin-bottom: 30rpx;
}

.type-item {
  padding: 15rpx 30rpx;
  border: 2rpx solid #ddd;
  border-radius: 50rpx;
  margin: 0 20rpx;
  font-size: 28rpx;
  
  &.active {
    background-color: #2979ff;
    color: #fff;
    border-color: #2979ff;
  }
}

.plate-display {
  display: flex;
  justify-content: center;
  margin-bottom: 40rpx;
  
  &.normal .plate-item {
    width: 60rpx;
  }
  
  &.newEnergy .plate-item {
    width: 55rpx;
  }
}

.plate-item {
  height: 100rpx;
  border: 2rpx solid #ddd;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 36rpx;
  font-weight: bold;
  margin: 0 5rpx;
  border-radius: 8rpx;
  
  &.plate-item-active {
    border-color: #2979ff;
    box-shadow: 0 0 10rpx rgba(41, 121, 255, 0.3);
  }
}

.keyboard-container {
  background-color: #f5f5f5;
  padding: 20rpx;
}

.keyboard-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20rpx 0;
  border-bottom: 2rpx solid #eee;
}

.keyboard-title {
  font-size: 32rpx;
  font-weight: bold;
}

.keyboard-keys {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  padding: 20rpx 0;
  max-height: 500rpx;
  overflow-y: auto;
}

.key-item {
  width: calc(10% - 10rpx);
  height: 70rpx;
  background-color: #fff;
  border-radius: 10rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 10rpx 5rpx;
  font-size: 32rpx;
  box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
  
  &.key-delete {
    background-color: #ff5a5f;
    color: #fff;
    width: 15%;
  }
}

.keyboard-toggle {
  display: flex;
  justify-content: center;
  padding: 20rpx 0;
}

.toggle-btn {
  padding: 10rpx 30rpx;
  background-color: #e0e0e0;
  border-radius: 30rpx;
  margin: 0 20rpx;
  font-size: 28rpx;
  
  &.active {
    background-color: #2979ff;
    color: #fff;
  }
}
</style>

使用示例:

<!-- pages/example/example.vue -->
<template>
  <view class="container">
    <view class="title">车牌号输入示例</view>
    
    <!-- 基础用法 -->
    <view class="section">
      <view class="section-title">基础用法</view>
      <LicensePlateInput 
        v-model="plateNumber" 
        @plate-type-change="onPlateTypeChange"
      />
      <view class="result">输入的车牌号: {{ plateNumber }}</view>
    </view>
    
    <!-- 指定初始车牌类型 -->
    <view class="section">
      <view class="section-title">新能源车牌</view>
      <LicensePlateInput 
        v-model="newEnergyPlate"
        init-plate-type="newEnergy"
      />
      <view class="result">输入的车牌号: {{ newEnergyPlate }}</view>
    </view>
    
    <!-- 隐藏类型选择器 -->
    <view class="section">
      <view class="section-title">隐藏类型选择器</view>
      <LicensePlateInput 
        v-model="fixedPlate"
        :show-type-selector="false"
        init-plate-type="normal"
      />
      <view class="result">输入的车牌号: {{ fixedPlate }}</view>
    </view>
    
    <!-- 操作按钮 -->
    <view class="actions">
      <u-button @click="clearAll">清空所有</u-button>
      <u-button @click="setPlate">设置车牌号</u-button>
    </view>
  </view>
</template>

<script>
import LicensePlateInput from '@/components/LicensePlateInput.vue'

export default {
  components: {
    LicensePlateInput
  },
  data() {
    return {
      plateNumber: '',
      newEnergyPlate: '',
      fixedPlate: ''
    }
  },
  methods: {
    onPlateTypeChange(type) {
      console.log('车牌类型切换为:', type)
    },
    
    clearAll() {
      this.plateNumber = ''
      this.newEnergyPlate = ''
      this.fixedPlate = ''
    },
    
    setPlate() {
      this.plateNumber = '京A12345'
      this.newEnergyPlate = '京AD123456'
    }
  }
}
</script>

<style lang="scss" scoped>
.container {
  padding: 20rpx;
}

.title {
  text-align: center;
  font-size: 36rpx;
  font-weight: bold;
  margin-bottom: 40rpx;
}

.section {
  margin-bottom: 40rpx;
  padding: 20rpx;
  background-color: #f8f8f8;
  border-radius: 10rpx;
}

.section-title {
  font-size: 32rpx;
  font-weight: bold;
  margin-bottom: 20rpx;
}

.result {
  margin-top: 20rpx;
  padding: 20rpx;
  background-color: #fff;
  border-radius: 10rpx;
}

.actions {
  display: flex;
  justify-content: space-around;
  margin-top: 40rpx;
}
</style>

组件特性

Props

  • initPlateType: 初始车牌类型 (‘normal’ | ‘newEnergy’),默认 ‘normal’
  • showTypeSelector: 是否显示车牌类型选择器 (Boolean),默认 true
  • value: 初始车牌号码 (String),默认 ‘’

Events

  • input: 车牌号码变化时触发,返回完整车牌号
  • plate-type-change: 车牌类型切换时触发,返回类型值

Methods

  • getPlateNumber(): 获取当前车牌号码
  • setPlateNumber(plateNumber): 设置车牌号码
  • clearPlate(): 清空车牌号码

使用方式

  1. 将组件文件保存到 components/LicensePlateInput.vue
  2. 在页面中引入并注册组件
  3. 使用 v-model 进行双向绑定
  4. 可通过 init-plate-type 指定初始车牌类型
  5. 可通过 show-type-selector 控制是否显示类型选择器

这样就完成了一个功能完整的uniapp车牌号输入组件,可以直接在项目中使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值