Files
mini-yu/uni_modules/tdesign-uniapp/components/search/search.vue
lingxiao865 c5af079d8c first commit
2026-02-10 08:05:03 +08:00

286 lines
7.0 KiB
Vue

<template>
<view>
<view
:style="tools._style([customStyle])"
:class="classPrefix + ' ' + tClass"
>
<view
:class="
classPrefix +'__input-box ' +
prefix + '-' +(focus ? 'is-focused' : 'not-focused') +
' ' + classPrefix + '__input-box--' + (center ? 'center' : '') +
' ' + classPrefix + '__input-box--' + shape +
' ' + tClassInputContainer
"
>
<t-icon
v-if="leftIcon"
:name="leftIcon"
:t-class="prefix + '-icon ' + tClassLeft"
:aria-hidden="true"
/>
<slot
v-else
name="left-icon"
/>
<input
:type="type"
name="input"
:maxlength="maxlength"
:disabled="disabled || readonly"
:class="prefix + '-input__keyword ' + tClassInput + ' ' + (disabled ? prefix + '-input--disabled' : '')"
:focus="focus"
:value="dataValue"
:confirm-type="confirmType"
:confirm-hold="confirmHold"
:cursor="cursor"
:adjust-position="adjustPosition"
:always-embed="alwaysEmbed"
:selection-start="selectionStart"
:selection-end="selectionEnd"
:hold-keyboard="holdKeyboard"
:cursor-spacing="cursorSpacing"
:cursor-color="cursorColor"
:placeholder="placeholder"
:placeholder-style="placeholderStyle"
:placeholder-class="placeholderClass + ' ' + classPrefix + '__placeholder ' + classPrefix + '__placeholder--' + (center ? 'center' : 'normal')"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
@confirm="onConfirm"
>
<view
v-if="dataValue !== '' && clearable && showClearIcon"
:class="classPrefix + '__clear hotspot-expanded ' + tClassClear"
aria-role="button"
aria-label="清除"
@touchstart.stop.prevent="handleClear"
>
<t-icon
name="close-circle-filled"
size="inherit"
color="inherit"
/>
</view>
</view>
<view
v-if="action"
:class="classPrefix + '__search-action ' + tClassAction"
aria-role="button"
@click.stop.prevent="onActionClick"
>
{{ action }}
</view>
<slot
v-else
name="action"
/>
</view>
<view
v-if="isShowResultList && !isSelected"
:class="classPrefix + '__result-list'"
aria-role="listbox"
>
<t-cell
v-for="(item, index) in resultList"
:key="index"
:data-index="index"
:t-class="classPrefix + '__result-item'"
hover
aria-role="option"
@click="onSelectResultItem($event, { index })"
>
<template
#title
>
<rich-text
:nodes="highLight(item, dataValue)"
/>
</template>
</t-cell>
</view>
</view>
</template>
<script>
import TIcon from '../icon/icon';
import TCell from '../cell/cell';
import { uniComponent } from '../common/src/index';
import { prefix } from '../common/config';
import props from './props';
import { getCharacterLength, nextTick } from '../common/utils';
import tools from '../common/utils.wxs';
import { highLight } from './computed.js';
// import { getInnerMaxLen } from '../input/utils';
const name = `${prefix}-search`;
export default uniComponent({
name,
options: {
styleIsolation: 'shared',
},
externalClasses: [
`${prefix}-class`,
`${prefix}-class-input-container`,
`${prefix}-class-input`,
`${prefix}-class-action`,
`${prefix}-class-left`,
`${prefix}-class-clear`,
],
components: {
TIcon,
TCell,
},
props: {
...props,
},
emits: [
'selectresult',
],
data() {
return {
classPrefix: name,
prefix,
isShowResultList: false,
isSelected: false,
showClearIcon: false,
tools,
dataValue: this.value,
// innerMaxLen: -1,
// rawValue: '',
};
},
watch: {
resultList: {
handler(val) {
const { isSelected } = this;
if (val.length) {
if (isSelected) {
// 已选择
this.isShowResultList = false;
this.isSelected = false;
} else {
this.isShowResultList = true;
}
} else {
this.isShowResultList = false;
}
},
immediate: true,
},
dataValue: {
handler() {
// this.updateInnerMaxLen();
this.updateClearIconVisible();
},
},
clearTrigger: 'updateClearIconVisible',
clearable: 'updateClearIconVisible',
disabled: 'updateClearIconVisible',
readonly: 'updateClearIconVisible',
// maxcharacter: 'updateInnerMaxLen',
// maxlength: 'updateInnerMaxLen',
},
mounted() {
this.updateClearIconVisible();
},
methods: {
updateClearIconVisible(value = false) {
const { clearTrigger, disabled, readonly, dataValue } = this;
if (disabled || readonly || !dataValue) {
this.showClearIcon = false;
return;
}
this.showClearIcon = value || String(clearTrigger) === 'always';
},
onInput(e) {
let { value } = e.detail;
// this.rawValue = value;
this.dataValue = value;
const { maxcharacter } = this;
if (maxcharacter && typeof maxcharacter === 'number' && maxcharacter > 0) {
const { characters } = getCharacterLength('maxcharacter', value, maxcharacter);
value = characters;
}
nextTick().then(() => {
this.dataValue = value;
this.$emit('change', { value });
});
// this.updateInnerMaxLen();
},
onFocus(e) {
const { value } = e.detail;
this.updateClearIconVisible(true);
this.$emit('focus', { value });
},
onBlur(e) {
const { value } = e.detail;
this.updateClearIconVisible();
this.$emit('blur', { value });
},
handleClear() {
this.dataValue = '';
this.$emit('clear', { value: '' });
this.$emit('change', { value: '' });
},
onConfirm(e) {
const { value } = e.detail;
this.$emit('submit', { value });
},
onActionClick() {
this.$emit('action-click');
},
onSelectResultItem(tools, { index }) {
const item = this.resultList[index];
this.dataValue = item;
this.isSelected = true;
this.$emit('change', { value: item });
this.$emit('selectresult', { index, item });
},
highLight,
// updateInnerMaxLen() {
// // this.innerMaxLen = this.getInnerMaxLen();
// },
// getInnerMaxLen() {
// const {
// maxcharacter,
// maxlength,
// dataValue,
// rawValue,
// count,
// } = this;
// return getInnerMaxLen({
// allowInputOverMax: false,
// maxcharacter,
// maxlength,
// dataValue,
// rawValue,
// count,
// });
// },
},
});
</script>
<style scoped>
@import './search.css';
</style>