做业务系统时,车牌号、零件号、订单号......各种编号字段都需要大写。后端存大写、前端也显示大写,但用户打字时往往习惯输入小写,每次都要等表单报错才知道改。
与其让用户"试错",不如在前端直接帮用户转大写------体验好,后端压力也小。本文分享一套完整方案:自定义指令 精准控制 + 全局插件一次搞定。
方案一:自定义指令 v-input-uppercase
适合对特定输入框做精细化控制。
创建指令文件
src/directives/inputUppercase.js
js
const globalUppercaseConfig = {
defaultEnabled: true,
processedInputs: new WeakSet(),
disabledInputs: new WeakSet()
};
export default {
mounted(el, binding) {
const inputElement = el.querySelector('.el-input__inner')
|| el.querySelector('input')
|| el.querySelector('textarea');
if (!inputElement) return;
const config = binding.value || {};
const enabled = config.enabled !== false;
if (!enabled) {
globalUppercaseConfig.disabledInputs.add(el);
return;
}
if (globalUppercaseConfig.processedInputs.has(el)) return;
globalUppercaseConfig.processedInputs.add(el);
let isComposing = false;
const toUpperCase = () => {
if (isComposing || !inputElement.value) return;
const oldValue = inputElement.value;
const newValue = oldValue.toUpperCase();
if (oldValue !== newValue) {
inputElement.value = newValue;
inputElement.dispatchEvent(new Event('input', { bubbles: true }));
}
};
if (inputElement.value) toUpperCase();
inputElement.addEventListener('input', toUpperCase);
inputElement.addEventListener('paste', () => setTimeout(toUpperCase, 10));
inputElement.addEventListener('compositionstart', () => { isComposing = true; });
inputElement.addEventListener('compositionend', () => {
isComposing = false;
setTimeout(toUpperCase, 10);
});
el._toUpperCase = toUpperCase;
el._inputElement = inputElement;
},
beforeUnmount(el) {
if (el._inputElement && el._toUpperCase) {
el._inputElement.removeEventListener('input', el._toUpperCase);
el._inputElement.removeEventListener('paste', el._toUpperCase);
}
globalUppercaseConfig.processedInputs.delete(el);
}
};
export { globalUppercaseConfig };
注册指令
js
// src/main.js
import uppercase from './directives/inputUppercase.js'
app.directive('input-uppercase', uppercase)
使用
vue
<!-- 自动大写 -->
<el-input v-model="plateNo" v-input-uppercase placeholder="请输入车牌号" />
<!-- 某些字段不需要转大写 -->
<el-input v-model="name" v-input-uppercase="{ enabled: false }" />
方案二:全局插件(推荐)
一个插件,覆盖所有 el-input / el-textarea / el-select,无需逐个添加指令。
创建插件文件
src/plugins/globalUppercase.js
js
import { globalUppercaseConfig } from '../directives/inputUppercase.js';
// 排除某些页面(如登录页不需要大写)
const globalUppercasePluginConfig = {
excludedPaths: ['/home/login', '/qp/tableModuSet']
};
export const GlobalUppercasePlugin = {
install(app) {
app.mixin({
mounted() {
this.$nextTick(() => {
if (!this.$el || typeof this.$el.querySelectorAll !== 'function') return;
const currentPath = window.location.hash || window.location.pathname;
if (globalUppercasePluginConfig.excludedPaths.some(p => currentPath.includes(p))) return;
const applyTo = (el) => {
if (globalUppercaseConfig.processedInputs.has(el)) return;
const actualInput = el.querySelector('.el-input__inner')
|| el.querySelector('input')
|| el.querySelector('textarea')
|| (['INPUT', 'TEXTAREA'].includes(el.tagName) ? el : null);
if (!actualInput) return;
let isComposing = false;
const toUpperCase = () => {
if (isComposing || !actualInput.value) return;
const newVal = actualInput.value.toUpperCase();
if (actualInput.value !== newVal) {
actualInput.value = newVal;
actualInput.dispatchEvent(new Event('input', { bubbles: true }));
}
};
if (actualInput.value) toUpperCase();
actualInput.addEventListener('input', toUpperCase);
actualInput.addEventListener('paste', () => setTimeout(toUpperCase, 10));
actualInput.addEventListener('compositionstart', () => { isComposing = true; });
actualInput.addEventListener('compositionend', () => {
isComposing = false;
setTimeout(toUpperCase, 10);
});
globalUppercaseConfig.processedInputs.add(el);
el._toUpperCase = toUpperCase;
el._inputElement = actualInput;
};
// 处理 el-input
this.$el.querySelectorAll('.el-input').forEach(applyTo);
// 处理 el-textarea
this.$el.querySelectorAll('.el-textarea').forEach(applyTo);
// 处理 el-select(搜索模式下的输入框)
this.$el.querySelectorAll('.el-select').forEach(el => {
const selectInput = el.querySelector('.el-select__input');
if (selectInput) applyTo(selectInput);
});
});
},
beforeUnmount() {
if (!this.$el) return;
this.$el.querySelectorAll('.el-input, .el-textarea, .el-select').forEach(el => {
if (el._inputElement && el._toUpperCase) {
el._inputElement.removeEventListener('input', el._toUpperCase);
el._inputElement.removeEventListener('paste', el._toUpperCase);
}
globalUppercaseConfig.processedInputs.delete(el);
});
}
});
}
};
export { globalUppercasePluginConfig };
注册插件
js
// src/main.js
import { GlobalUppercasePlugin } from './plugins/globalUppercase.js'
app.use(GlobalUppercasePlugin)
完成! 全站所有输入框自动大写,用户输入 abc123 → 直接显示 ABC123。
两种方案对比
| 自定义指令 | 全局插件 | |
|---|---|---|
| 适用范围 | 单个输入框 | 全站 |
| 控制粒度 | 精准 | 全局 + 路径排除 |
| 支持组件 | el-input / input / textarea | el-input / el-textarea / el-select |
| 注册方式 | app.directive() |
app.use() |
和单引号禁止方案的对比
| 单引号禁止 | 大写转换 | |
|---|---|---|
| 核心操作 | replace(/'/g, '') 删除 |
toUpperCase() 转换 |
| 行为 | 输入时被阻止 | 输入后自动转换 |
| 默认触发时机 | input + blur | input |
| 特殊处理 | 中文输入法 | 中文输入法 |
两套方案代码结构几乎一致,如果你两个功能都要,完全可以合并成一个插件,通过配置项切换行为。
合并成一套插件
js
export const GlobalInputFilterPlugin = {
install(app, options = {}) {
const { mode = 'uppercase' } = options; // 'uppercase' | 'noQuote' | 'both'
app.mixin({
mounted() {
this.$nextTick(() => {
// ...统一的处理逻辑
const transform = (val) => {
if (mode === 'uppercase') return val.toUpperCase();
if (mode === 'noQuote') return val.replace(/'/g, '');
if (mode === 'both') return val.toUpperCase().replace(/'/g, '');
return val;
};
// ...
});
}
});
}
};
// 使用
app.use(GlobalInputFilterPlugin, { mode: 'both' })
总结
- 全局覆盖 → 插件
app.use()一次搞定 - 局部控制 → 指令
v-input-uppercase精准禁用 - 两个功能都要 → 合并成一个插件,
mode参数切换 - 中文输入法兼容,始终是标配