Files
klp-oa/klp-ui/src/components/MemoInput/index.vue
砂糖 d15a629300 fix: 修复MemoInput空值处理和CoilSelector查询参数
修复MemoInput组件在空值情况下未触发input事件的问题,并更新CoilSelector组件的查询参数命名以保持一致性
2026-01-28 15:26:50 +08:00

188 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-autocomplete class="inline-input" v-model="inputValue" :fetch-suggestions="querySearch" :placeholder="placeholder"
:trigger-on-focus="triggerMode === 'focus'" @select="handleSelect" @change="handleInputChange"
clearable></el-autocomplete>
</template>
<script>
import { MemoInputStorageKey } from '@/utils/enum';
export default {
name: 'LocalStorageAutocomplete',
props: {
// localStorage 存储键名,必填
value: {
type: String,
default: ''
},
storageKey: {
type: String,
required: true,
validator: (value) => {
// 校验storageKey是否在MemoInputStorageKey中
if (!MemoInputStorageKey[value]) {
throw new Error(`storageKey ${value} is not valid`);
}
return value.trim() !== ''
} // 校验非空
},
// 输入框占位符,默认“请输入内容”
placeholder: {
type: String,
default: '请输入内容'
},
// // 当localstorage中不存在缓存时自动创建一个数组作为默认值
// autoCreateDefault: {
// type: Array,
// default: () => []
// },
// 最大缓存数量默认100条
maxCacheCount: {
type: Number,
default: 100,
validator: (value) => value > 0 // 校验正整数
},
// 匹配规则start-前缀匹配contain-包含匹配,默认前缀匹配
matchRule: {
type: String,
default: 'start',
validator: (value) => ['start', 'contain'].includes(value)
},
// 触发模式focus-激活即列出input-输入后匹配默认focus
triggerMode: {
type: String,
default: 'focus',
validator: (value) => ['focus', 'input'].includes(value)
}
},
data() {
return {
inputValue: '',
// 缓存历史列表(格式:[{value: 'xxx'}, ...]
historyList: []
};
},
computed: {
innerKey() {
if (!this.storageKey) {
throw new Error('storageKey is required');
}
return 'mono-' + this.storageKey;
}
},
watch: {
value: {
handler(newVal, oldVal) {
if (newVal !== oldVal) {
this.inputValue = newVal;
}
},
immediate: true
}
},
mounted() {
// 初始化时从localStorage读取历史记录
this.initHistoryList();
},
methods: {
/**
* 从localStorage初始化历史列表
*/
initHistoryList() {
const storedData = localStorage.getItem(this.innerKey);
this.historyList = storedData ? JSON.parse(storedData) : [];
},
/**
* 搜索查询方法Element UI autocomplete 要求的格式)
* @param {string} queryString - 输入的查询字符串
* @param {function} cb - 回调函数,返回匹配结果
*/
querySearch(queryString, cb) {
let results = [...this.historyList]; // 深拷贝避免修改原数组
// 根据查询字符串过滤结果
if (queryString) {
const lowerQuery = queryString.toLowerCase();
results = results.filter(item => {
const lowerValue = item.value.toLowerCase();
// 前缀匹配或包含匹配
return this.matchRule === 'start'
? lowerValue.indexOf(lowerQuery) === 0
: lowerValue.includes(lowerQuery);
});
}
cb(results); // 回调返回匹配结果
},
/**
* 选中建议项时的处理
* @param {object} item - 选中的项 {value: 'xxx'}
*/
handleSelect(item) {
this.cacheInputValue(item.value);
this.inputValue = item.value;
// 触发自定义事件,通知父组件选中结果
this.$emit('input', item.value);
},
/**
* 输入框内容变化时的处理(比如手动输入后回车/失焦)
* @param {string} value - 输入框的值
*/
handleInputChange(value) {
if (value && value.trim() !== '') {
this.cacheInputValue(value.trim());
// 触发自定义事件,通知父组件输入结果
this.$emit('input', value.trim());
} else {
this.$emit('input', '');
}
},
/**
* 缓存输入值到localStorage
* @param {string} value - 要缓存的值
*/
cacheInputValue(value) {
// 去重:如果已存在则移除原记录(保证最新输入在最前面)
this.historyList = this.historyList.filter(item => item.value !== value);
// 添加新记录到头部
this.historyList.unshift({ value });
// 限制最大缓存数量
if (this.historyList.length > this.maxCacheCount) {
this.historyList = this.historyList.slice(0, this.maxCacheCount);
}
// 保存到localStorage
localStorage.setItem(this.innerKey, JSON.stringify(this.historyList));
},
/**
* 清空历史记录(提供给父组件调用的方法)
*/
clearHistory() {
this.historyList = [];
localStorage.removeItem(this.innerKey);
this.inputValue = '';
this.$emit('clear');
}
}
};
</script>
<style scoped>
.demo-autocomplete {
margin-bottom: 20px;
}
.sub-title {
margin-bottom: 10px;
color: #666;
font-size: 14px;
}
.inline-input {
width: 100%;
}
</style>