需求:特殊开发,需要给element plus的某些输入框计算字符数量。
环境:vue3+ vite+elementPlus
实际效果:
过程:
1.创建自定义命令文件(inputCount.js)
/**
* el-input字符统计自定义指令
* 使用方式:v-input-count="{ max: 100 }"
* 参数:
* - max: 最大字符数(可选)
* - showCount: 是否显示字符数(默认true)
* - position: 位置,'inside'、'right'或'bottom'(默认'inside')
*/
export default {
mounted(el, binding) {
// 获取el-input组件实例
const inputElement = el.querySelector('.el-input__inner') || el.querySelector('input') || el.querySelector('textarea');
if (!inputElement) return;
// 获取配置参数
const config = binding.value || {};
const max = config.max || null;
const showCount = config.showCount !== false; // 默认为true
const position = config.position || 'inside'; // 默认为内部显示
if (!showCount) return;
// 创建字符计数元素
const countElement = document.createElement('span');
countElement.className = 'input-count';
countElement.style.fontSize = '12px';
countElement.style.color = '#100aff';
countElement.style.pointerEvents = 'none'; // 防止点击计数元素
countElement.style.userSelect = 'none'; // 防止选择计数元素
// 根据位置设置样式
if (position === 'inside') {
// 输入框内部靠右显示
countElement.style.position = 'absolute';
countElement.style.right = '2px';
countElement.style.top = '-3px';
countElement.style.transform = 'translateY(-50%)';
countElement.style.zIndex = '1';
countElement.style.backgroundColor = '#ffffff00';
countElement.style.padding = '0 2px';
// 确保父元素有相对定位
el.style.position = 'relative';
// 为输入框添加右侧内边距,避免文字与计数重叠
// if (inputElement.tagName === 'INPUT') {
// inputElement.style.paddingRight = '10px';
// } else if (inputElement.tagName === 'TEXTAREA') {
// inputElement.style.paddingRight = '10px';
// }
// 添加到输入框内部
el.appendChild(countElement);
} else if (position === 'right') {
// 输入框右侧外部显示
countElement.style.position = 'absolute';
countElement.style.right = '-40px';
countElement.style.top = '50%';
countElement.style.transform = 'translateY(-50%)';
el.style.position = 'relative';
el.style.marginRight = '50px';
el.appendChild(countElement);
} else if (position === 'bottom') {
// 输入框下方显示
countElement.style.display = 'block';
countElement.style.textAlign = 'right';
countElement.style.marginTop = '4px';
countElement.style.marginRight = '8px';
el.parentNode.style.position = 'relative';
el.parentNode.appendChild(countElement);
}
// 更新字符计数函数
const updateCount = () => {
// 使用多种方式获取输入框的值,确保准确性
let value = '';
// 尝试从Vue组件获取值
if (el.__vueParentComponent && el.__vueParentComponent.props) {
value = el.__vueParentComponent.props.modelValue || '';
}
// 尝试从input元素获取值
if (!value && inputElement.value !== undefined) {
value = inputElement.value;
}
// 尝试从属性获取值
if (!value && inputElement.getAttribute) {
value = inputElement.getAttribute('value') || '';
}
// 确保值是字符串类型
value = String(value || '');
const length = value.length;
let text = `${length}`;
if (max) {
text += `/${max}`;
// 超过限制时改变颜色
if (length > max) {
countElement.style.color = '#f56c6c';
} else {
countElement.style.color = '#909399';
}
}
// 只有当长度大于0时才显示计数,否则隐藏计数元素
if (length > 0) {
countElement.textContent = text;
countElement.style.display = '';
} else {
countElement.style.display = 'none';
}
};
// 初始化计数
updateCount();
// 监听输入事件
inputElement.addEventListener('input', updateCount);
// 监听键盘事件,处理删除等操作
inputElement.addEventListener('keydown', updateCount);
// 监听粘贴和剪切事件
inputElement.addEventListener('paste', () => {
setTimeout(updateCount, 10);
});
inputElement.addEventListener('cut', () => {
setTimeout(updateCount, 10);
});
// 定期检查值的变化(作为备用方案)
const intervalId = setInterval(() => {
updateCount();
}, 1000);
// 保存更新函数,以便后续使用
el._updateCount = updateCount;
el._countElement = countElement;
el._inputElement = inputElement;
el._intervalId = intervalId;
},
updated(el, binding) {
// 如果配置发生变化,更新计数显示
if (el._updateCount) {
el._updateCount();
}
},
beforeUnmount(el) {
// 清理事件监听器
if (el._inputElement && el._updateCount) {
el._inputElement.removeEventListener('input', el._updateCount);
el._inputElement.removeEventListener('keydown', el._updateCount);
el._inputElement.removeEventListener('paste', el._updateCount);
el._inputElement.removeEventListener('cut', el._updateCount);
}
// 清理定时器
if (el._intervalId) {
clearInterval(el._intervalId);
}
// 移除计数元素
if (el._countElement && el._countElement.parentNode) {
el._countElement.parentNode.removeChild(el._countElement);
}
}
};
2.在主文件导入该自定义指令
例如在main.js中
import inputCountDirective(自定义)form 'xxxx.js'(文件位置)
并注册app.directive('input-count', inputCountDirective);
3.使用
在输入框添加属性v-input-count,更多使用方式看文件内头部示例。