更新记录
1.0.1(2023-04-21)
下载此版本
- 功能自测
- 输入关键词,下拉列表展示搜索结果
- 类似百度搜索,搜索关键词变红
- 优化组件逻辑,方便父子组件传值
- 增加DEMO:/components/pages/index
- 增加完整说明文档 +案例
1.0.0(2023-04-20)
下载此版本
v1.0.0
搜索组件:
包含热门搜索,搜索联想,关键词标红
平台兼容性
App |
快应用 |
微信小程序 |
支付宝小程序 |
百度小程序 |
字节小程序 |
QQ小程序 |
HBuilderX 3.3.13 app-vue app-nvue |
√ |
√ |
√ |
√ |
√ |
√ |
钉钉小程序 |
快手小程序 |
飞书小程序 |
京东小程序 |
√ |
√ |
√ |
√ |
H5-Safari |
Android Browser |
微信浏览器(Android) |
QQ浏览器(Android) |
Chrome |
IE |
Edge |
Firefox |
PC-Safari |
√ |
√ |
√ |
√ |
√ |
× |
√ |
√ |
√ |
search 搜索页
- 【搜索页面,界面简洁大气,颜值即正义】
- 本地项目引入阿里图标库,小巧的字体文件节省空间
- 使用方法:“HBuilderX导入插件”,然后复制参考DEMO的代码
参考DEMO /components/pages/index
<zhangguangsen-search
:hotList="hotList"
:searchList="searchList"
@onInput="onInput"\
@onSearchConfirm="onSearchConfirm">
</zhangguangsen-search>
export default {
data() {
return {
hotList:['aa','bb','cc','dd','测试一个超产的龙欧索','aa','bb','cc','dd','测试一个超产的龙欧索'],
searchList:[]
}
},
mounted(){
},
methods: {
onInput(val){
console.log('**input',val)
//模拟后端返回数据,根据val调用接口
setTimeout(()=>{
this.searchList = ['aabacd','bb','cc','dd','测试一个超产的龙欧索','aa',Math.random()]//这里模拟 axios 返回的数据
},2000)
},
onSearchConfirm(searchVal){
console.log('搜索词',searchVal)
}
}
}
组件代码
- 可复制代码,自己封一个组件;再需要下载插件ZIP,将字体文件引入项目即可;
- 推荐的用法,还是通过“HBuilderX导入插件”
<view class="search">
<view class="search-head">
<view class="head-icon__search iconfont icon-sousuo1"></view>
<view class="head-input__search">
<input v-model="val" :focus="true" :adjustPosition="false" placeholder="请输入配件名称" placeholder-class="head-input__placeholder" confirmType="搜索" :confirmHold="false" @input="handleInput" @click="handleClick" @confirm="handleConfirm"/>
<button @click="handleConfirm">搜索</button>
</view>
</view>
<view class="hotSearch">
<view class="hotSearch-head">
<view class="hotSearch-icon__hot iconfont icon-remensousuo"></view>
<text class="hotSearch-text__hot">
热门搜索
</text>
</view>
<view class="hotSearch-list">
<view class="hotSearch-li" v-for="(item,index) in hotList" :key="index" @click="handleConfirm(item)">
{{item}}
</view>
</view>
</view>
<view v-show="showPop">
<view class="pop-search__list">
<view class="pop-search__li" v-for="(item,index) in formatSearchList" :key="index" @click="handleConfirm(item)">
<text v-for="(titem,tindex) in item" :key="tindex" :class="titem.key ? 'active' : ''">{{titem.str}}</text>
</view>
</view>
<view class="pop-search__mask" @click="showPop=false"></view>
</view>
</view>
props:{
hotList:{
type:Array
},
searchList:{
type:Array
}
},
watch:{
searchList:{
handler(searchList){
uni.hideLoading();
console.log('watch',searchList)
if(searchList.length>0 && this.val){
this.formatSearchList = searchList.map(item=>this.hilight_word(this.val, item))
}
},
deep:true
}
},
data() {
return {
val:'',
showPop:false,
formatSearchList:[]
}
},
mounted(){
},
methods: {
handleConfirm(val){
let searchVal = val
if(Array.isArray((val))){
searchVal = val.map(({str})=>str).join('')
}else if(val instanceof Object){
searchVal = this.val
}
this.$emit('onSearchConfirm',searchVal)
},
handleClick(){
this.showPop = !!this.val
},
handleInput(e){
this.showPop = !!this.val
if(!this.val) {
return
}
uni.showLoading({
title: '加载中'
});
setTimeout(()=>uni.hideLoading(),3000)
this.$emit('onInput',this.val)
},
// 根据搜索字分割字符
hilight_word: function (key, word) {
key=key.trim()
word=''+word
let idx = word.indexOf(key), t = [];
if (idx > -1) {
if (idx == 0) {
t =this.hilight_word(key, word.substr(key.length));
t.unshift({ key: true, str: key });
return t;
}
if (idx > 0) {
t =this.hilight_word(key, word.substr(idx));
t.unshift({ key: false, str: word.substring(0, idx) });
return t;
}
}
return [{ key: false, str: word }];
}
}
<style lang="scss">
@font-face {
font-family: "iconfont"; /* Project id 3928599 */
src: url('@/static/zhangguangsen-search/zhangguangsen-search.woff2?t=1681960188787') format('woff2'),
url('@/static/zhangguangsen-search/zhangguangsen-search.woff?t=1681960188787') format('woff'),
url('@/static/zhangguangsen-search/zhangguangsen-search.ttf?t=1681960188787') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-remensousuo:before {
content: "\e73d";
}
.icon-sousuo1:before {
content: "\e61c";
}
.search{
background-color: #fff;
overflow: hidden;
&-head{
display: flex;
align-items: center;
padding:0 10rpx 0 47rpx;
margin:30rpx 30rpx 0;
height: 70rpx;
background: #F5F5F5;
border-radius: 35rpx;
.head-icon__search{
font-size: 30rpx;
color: #231815;
}
.head-input__search{
display: flex;
align-items: center;
flex: 1;
input{
margin-left: 15rpx;
border: none;
height: 29rpx;
font-size: 30rpx;
font-weight: 400;
color: #AAAAAA;
line-height: 28rpx;
flex:1;
}
button{
width: 128rpx;
height: 53rpx;
background: linear-gradient(0deg, #0AA0F5, #00E3F2);
border-radius: 30rpx;
font-size: 28rpx;
font-weight: 500;
color: #FFFFFF;
line-height: 42rpx;
}
.head-input__placeholder{
color: #AAAAAA;
}
}
}
.hotSearch{
margin-top: 30rpx;
&-head{
display: flex;
align-items: center;
padding:0 0 0 30rpx;
}
&-icon__hot{
margin-left: 10rpx;
font-size: 30rpx;
color: rgb(255,43,57);
}
&-text__hot{
margin-left: 10rpx;
font-size: 30rpx;
color: #999999;
}
&-list{
padding: 20rpx 0 50rpx 30rpx;
display: flex;
flex-wrap: wrap;
}
&-li{
margin: 10rpx 0 0 10rpx;
padding: 0 20rpx;
border-radius: 20rpx;
background: #f2f2f2;
line-height: 50rpx;
&:first-child{
margin-left: 0;
}
}
}
}
.pop{
&-search{
&__mask{
position: fixed;
top: 100rpx;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0,0,.3);
z-index: 1;
}
&__list{
padding:0 30rpx;
position: fixed;
top: 100rpx;
left: 0;
right: 0;
background-color: #fff;
z-index: 9;
}
&__li{
font-size: 30rpx;
color: #231815;
line-height: 90rpx;
border-bottom: solid 1px #F5F5F5;
.active{
color: red;
}
}
}
}
</style>