效果图如下:
1、组件代码:
<template>
<view @click.stop>
<view class="popup_box">
<view class="popup_input">
<u-form-item label="卡曼橘" prop="clientName" borderBottom required>
<u-input v-model="value" disabledColor="#ffffff" placeholder="请输入" border="none"
@change="handleChange" @confirm="handleChange">
<view class="buyer_act" slot="suffix">
<u-icon size="20" name="search" color="#1890ff" @click="handleChange(value)"></u-icon>
</view>
</u-input>
</u-form-item>
</view>
<view class="popup_select" v-if="popupSelect">
<view v-if="loading">
<u-loading-icon></u-loading-icon>
</view>
<view v-if="!loading && !total" style="padding-bottom: 30rpx;">
<u-empty mode="search">
</u-empty>
</view>
<view v-if="!loading && total">
<view class="popup_select_item" v-for="(item,index) in companyList" :key="index"
@click="childEvent(item)">
<view class="popup_select_item_tit">
<u-parse :content="item.jgmc | highlight(value)"></u-parse>
</view>
<view class="popup_select_flex">
<view class="popup_select_item_con">{{item.tyshxydm || '--'}}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
loading: true, // 加载状态
isGreater: true, // 弹窗位置
total: 0, // 数据条数
companyList: [], // 数据
value: this.cModel, // input值
debounceTimeout: null, // 防抖节流 定时器
popupSelect: this.cPopupSelect // 弹窗显示隐藏
}
},
filters: {
// 定义高亮显示过滤器
highlight(val, keyword) {
if (!keyword || !val) return val;
const regex = new RegExp(keyword, 'gi');
const highlighted = val.replace(regex, '<text style="color:#1890ff">$&</text>');
return highlighted;
}
},
watch: {
cModel(newValue) {
this.value = newValue;
},
cPopupSelect(newValue) {
this.popupSelect = newValue;
}
},
props: {
cModel: {
type: String,
default: ''
},
cPopupSelect: {
type: Boolean,
default: false
}
},
methods: {
// 监听输入框变化事件
handleChange(e) {
this.$emit('cModelChange', e)
if (e.length > 3) {
this.$emit('isPopupSelect', true);
clearTimeout(this.debounceTimeout);
this.debounceTimeout = setTimeout(() => {
this.queryData(this.value);
}, 300);
} else {
this.clearData()
}
},
// 确定弹窗展示位置 需要优化
comGreater() {
const query = uni.createSelectorQuery().in(this); // 'this' 指代Vue实例
query.select('.popup_input').boundingClientRect(function(rect) {
// rect.bottom 就是组件底部的位置
const screenHeight = uni.getSystemInfoSync().windowHeight;
const distanceToBottom = screenHeight - rect.bottom;
// 判断是否大于300
const isGreater = distanceToBottom > 200;
this.isGreater = isGreater
}).exec();
},
// 模糊搜索
queryData() {
this.loading = true;
queryDataApi(this.value).then(res => {
this.loading = false;
if (res.rows.length > 0) {
this.companyList = res.rows;
this.total = res.rows.length;
} else {
this.total = 0;
}
})
},
// 清空
clearData() {
this.total = 0;
this.loading = true;
this.$emit('isPopupSelect', false);
},
// 选中一项 调用父
childEvent(item) {
this.clearData()
this.$emit('childEvent', item);
},
}
}
</script>
<style scoped lang="scss">
.popup_box {
position: relative;
}
.popup_select {
width: 96%;
max-height: 400rpx;
overflow-y: scroll;
border-radius: 8rpx;
padding: 10rpx;
box-sizing: border-box;
position: absolute;
left: 50%;
transform: translateX(-50%);
border: 1rpx solid #ccc;
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.1);
background-color: #fff;
z-index: 99;
.popup_close {
width: 100%;
display: flex;
justify-content: end;
}
.popup_select_item {
margin-bottom: 10rpx;
.popup_select_item_tit {
margin-bottom: 0;
}
.popup_select_item_con {
color: #acacac;
font-size: 28rpx;
}
}
.popup_select_item:last-child {
margin-bottom: 0;
}
.popup_select_flex {
display: flex;
justify-content: space-between;
}
}
</style>
2、引用组件
<template>
<view class="body-scroll" @click="handlePageTap">
<u-form>
<SelectFilter :cPopupSelect.sync="popupShow.popupSelect" :cModel.sync="userClient.enterpriseName"
@cModelChange="cModelChange" @childEvent="childEvent" @isPopupSelect="isPopupSelect"></SelectFilter>
</u-form>
</view>
</template>
<script>
import SelectFilter from './components/selectFilter.vue'
export default {
components: {
SelectFilter
},
data() {
return {
popupShow: {
popupSelect: false,
},
userClient: {
enterpriseName: ''
}
}
},
methods: {
// 子调父 打开关闭弹窗
isPopupSelect(e) {
this.$set(this.popupShow, 'popupSelect', e);
},
// 页面点击事件 用于关闭弹窗
handlePageTap() {
this.$set(this.popupShow, 'popupSelect', false);
},
// 子调父 修改enterpriseName的值
cModelChange(e) {
this.$set(this.userClient, 'enterpriseName', e);
},
// 子调父 修改通过enterpriseName查询出来的其他相关字段信息
childEvent(e) {
},
}
}
</script>
3、需要优化的地方很多........