封装代码组件custom-downSearch.vue 组件
<template>
<div class="drop-down-search" @click.stop>
<view style="display: flex; align-items: center;">
<input
@focus="handleFocus"
@blur="closeDropDown"
:style="{height: '100%', paddingRight: clear? '60rpx' : '16rpx', display: 'flex'}"
type="text"
v-model="searchText"
@input="handleSearch"
:placeholder="placeholder"/>
<text v-if="searchText.length && clear" @click="handleClearInput" class="iconfont icon-shanchu"></text>
<view
@click="handleDropDownBox"
v-if="icon"
:class="['dropdown-container', { rotated: isDropDownVisible}]"
></view> <!-- 添加小三角图标 -->
</view>
<scroll-view
:scroll-y="true"
class="dropdown-scroll"
:style="{ maxHeight: (isDropDownVisible && hasOptions) ? dropdownHeight + 'rpx' : '0rpx' }">
<div class="dropdown-content">
<div v-for="(option, index) in filteredOptions" :key="index" class="option" @click="selectOption(option, $event)">
{{ option }}
</div>
</div>
</scroll-view>
</div>
</template>
<script>
export default {
props: {
options: {
type: Array,
default: []
},
value: {
type: [String, Number],
default: ''
},
dropdownHeight: { // 下拉框的高度
type: Number,
default: 200
},
placeholder: {
type: String,
default: ''
},
icon: {
type: Boolean,
default: true
},
clear: {
type: Boolean,
default: true,
}
},
data() {
return {
searchText: this.value.toString(), // 默认将数字转字符串
isDropDownVisible: false,
hasOptions: false,
};
},
computed: {
// 根据搜索文本过滤选项
filteredOptions() {
return this.options.filter(option =>
option.toLowerCase().includes(this.searchText.toLowerCase())
);
}
},
watch: { // 监听 options 数组,要是输入的东西没有,就关闭下拉框
searchText() {
// this.hasOptions = (this.filteredOptions.length > 0)
},
},
mounted() {
// 添加点击外部关闭下拉框的事件监听器
document.addEventListener('click', this.closeDropDown.bind(this));
},
beforeDestroy() {
// 移除事件监听器以防止内存泄漏
document.removeEventListener('click', this.closeDropDown.bind(this));
},
methods: {
handleClearInput() { // 清除 input 输入框内容
this.searchText = ''
this.$emit('input',''); // 向父组件传递选中的值 // 重新获取新的数据
},
handleDropDownBox() { // 控制三角图表事件
this.isDropDownVisible = !this.isDropDownVisible
this.hasOptions = (this.filteredOptions.length > 0)
},
// 处理搜索事件
handleSearch(e) {
this.$emit('input', e.target.value); // 向父组件传递选中的值
this.isDropDownVisible = this.hasOptions;
},
handleFocus() {
this.isDropDownVisible = true;
this.hasOptions = true;
},
// 选择选项
selectOption(option, event) {
event.stopPropagation();
// 处理选项选择逻辑,比如触发事件、更新绑定值等
this.searchText = option; // 选中选项后更新搜索文本
this.isDropDownVisible = false; // 隐藏下拉框
this.hasOptions = false;
this.$emit('changeInput', option); // 向父组件传递选中的值
},
// // 获取当前输入的值
// getSearchText() {
// return this.searchText;
// },
closeDropDown() {
// 点击事件的目标不包含搜索框或下拉框时,隐藏下拉框
// this.isDropDownVisible = true;
// this.hasOptions = true;
if (!this.$el.contains(event.target)) {
this.isDropDownVisible = false;
}
}
}
};
</script>
<style scoped>
.drop-down-search {
position: relative;
height: 100% !important;
}
.dropdown-scroll {
position: absolute;
top: calc(100% + 12rpx);
left: 0;
width: 100%;
background: #fff;
z-index: 99;
/* border: 1rpx solid #ccc; */
box-shadow: 0 14rpx 30rpx rgb(0, 0, 0, 0.1);
transition: max-height 0.3s ease;
}
.dropdown-content {
padding: 10rpx;
}
.option {
padding: 10rpx;
cursor: pointer;
border-bottom: 1rpx solid #ccc;
}
input {
width: 100%;
padding: 10rpx;
box-sizing: border-box;
}
.iconfont {
position: absolute;
top: 50%;
right: 55rpx;
font-size: 50rpx;
transform: translateY(-50%);
font-size: 20rpx;
color: #999;
cursor: pointer;
}
.dropdown-container {
position: relative;
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
transform: rotate(180deg);
}
.dropdown-container::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 0;
height: 0;
border-left: 15rpx solid transparent;
border-right: 15rpx solid transparent;
border-bottom: 15rpx solid #ccc; /* 使用border-bottom创建向下的三角形 */
transition: transform 0.3s ease; /* 添加过渡效果 */
}
.rotated::before {
transform: translate(-50%, -50%) rotate(180deg); /* 旋转三角形 */
}
</style>
组件使用
<customDownSearch
style="flex: 1; height: 30rpx; border: 1rpx solid #ccc; font-size: 30rpx;"
:options="stateListCom"
:value="form.dingdanStatus"
v-model="form.dingdanStatus"
@changeInput="changeInput2"
@input="handleInput2"
></customDownSearch>
import customPagination from '@/components/custom-pagination/custom-pagination.vue'
components:{
customPagination,
},