-
- 根据文档阅读,找到icons的用法,放到我们封装的
MySearch组件里即可
<uni-icons type="search" size="15"></uni-icons>
search - 首页搜索实现吸顶效果(粘性布局)
- 在 home 首页定义如下的 UI 结构:
<MySearch class="my-search"></MySearch>
- 通过如下的样式实现吸顶的效果:
.my-search {
// 设置定位效果为“吸顶”
position: sticky;
// 吸顶的“位置”
top: 0;
// 提高层级,防止被轮播图覆盖
z-index: 999;
}
准备一个搜索页
- 来到
subpkg右键新建页面,输入search,用来做搜索页面
search - 点击自定义组件跳转到搜索页
- 此时需要在
home和 cate 里给我们封装的顶部的自定义组件加click,但是我们要知道,给自己封装的组件写@事件名,那必须组件内部要加$emit('事件名'),不然是没效果的
- 所以来到
components/mysearch给内容盒子加点击事件,点击事件里写$emit
<view class="search-content" @click="bindClick">
<uni-icons type="search" size="15"></uni-icons>搜索
</view>
methods: {
bindClick() {
this.$emit('click')
}
}
- 然后就可以来到
home 和 cate找到MySearch加点击事件和对应的方法即可
<MySearch @click="toSearch" class="my-search"></MySearch>
toSearch () {
uni.navigateTo({
url: "/subpkg/search/search"
})
}
search - 搜索页基本布局
- 放一个view,view里放一个
uni-ui里面的 搜索栏(快捷键usearch)
<view>
<view class="search-box">
<uni-search-bar v-model="key" radius="100" placeholder="请输入搜索内容" cancelButton="none" @confirm="search" />
</view>
</view>
.search-box {
background-color: #c00000;
}
search - 搜索建议区域布局
<!-- 搜索结果列表区域 -->
<uni-list>
<uni-list-item v-for="item in 10" title="列表文字" link></uni-list-item>
</uni-list>
search - 历史记录布局
- 一个大view,里面包上面和下面两个小view,上面的view放标题和垃圾删除的图标,下面放tag
<!-- 搜索历史区域 -->
<view class="history-box">
<view class="title">
<text>搜索历史</text>
<uni-icons type="trash" size="18"></uni-icons>
</view>
<!-- 具体的每一项历史记录 -->
<view class="history-item">
<uni-tag class="tag" v-for="item in 12" text="标签1" type="success" />
</view>
</view>
- 对应的布局:标题部分用弹性布局,设置它们一左一右,并给左右间距
- 标签每一项部分也用弹性布局,但是允许换行。然后给每一项设置右间距和下间距即可
.history-box {
.title {
padding: 0 10px;
display: flex;
font-size: 14px;
justify-content: space-between;
}
.history-item {
display: flex;
flex-wrap: wrap;
margin-top: 15px;
padding-left: 30px;
.tag {
margin-right: 10px;
margin-bottom: 10px;
}
}
}
search - 搜索建议与搜索历史布局只显示一个
- 根据需要观察得到结论,搜索框里有内容就显示搜索结果,没内容就显示搜索历史
- 所以给他们加v-if与v-else
<uni-list v-if="key != ''">
<uni-list-item v-for="item in 10" title="列表文字" link></uni-list-item>
</uni-list>
<!-- 搜索历史区域 -->
<view v-else class="history-box">
......
</view>
search - 根据输入关键词查询搜索结果
- 要给搜索框加
input事件,因为只有input是一边输入一边触发的(把之前confirm事件删了)
<view class="search-box">
<uni-search-bar v-model="key" radius="100" placeholder="请输入搜索内容" cancelButton="none" @input="onInput" />
</view>
data() {
return {
key: '',
resultList: []
};
},
methods: {
async onInput() {
// 发请求获取搜索的结果
const res = await uni.$http.get('goods/qsearch', {
query: this.key
})
this.resultList = res.data.message
},
}
<uni-list v-if="key">
<uni-list-item v-for="item in resultList" :key="item.goods_id" :title="item.goods_name" link>
</uni-list-item>
</uni-list>
设置文字一行显示,超出显示省略号
- 通过审查元素发现只要给某个span加样式即可,但是这个span在组件内部,而默认有样式隔离的影响
- 所以要加深度作用选择器才有用
::v-deep .uni-list-item__content-title {
span {
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
使用防抖优化请求
- 此时存在问题:我一边输就一边发请求,会造成性能浪费
- 根据用户习惯,应该是在没输完的时候是连续输入的,输完肯定会停顿,所以我们就应该是停顿时才去发请求
- 要用防抖:
- 先让代码延迟执行,并且如果短时间内不断触发,就不断关掉定时器再开心的定时器
- 代码如下
data() {
return {
.....
time: null
};
},
methods: {
onInput() {
// 每次开启新的之前,把上一次的关掉
clearTimeout(this.time)
this.time = setTimeout(async () => {
// 如果输入框为空没必要发请求,直接return
if (this.key === '') return
// 发请求获取搜索的结果
const res = await uni.$http.get('goods/qsearch', {
query: this.key
})
this.resultList = res.data.message
}, 500)
},
}
search - 搜索结果点击跳转至商品详情页
- 要设置跳转,uni-list-item加一个to属性即可跳转)
<uni-list-item v-for="item in resultList" :key="item.goods_id" :title="item.goods_name" link
:to="`/subpkg/goods_detail/goods_detail?goods_id=${item.goods_id}`">
</uni-list-item>
- 因为跳转还要携带参数,所以加
:以及在里面用模板字符串拼接
给搜索框加吸顶效果
.search-wrap {
background-color: #c00000;
position: sticky;
top: 0;
z-index: 9999;
}
search - 保存历史记录并缓存数据
- 官方文档
-
- 缓存数据跟localStorage的区别在于
- localStorage保存时如果要存复杂类型必须转JSON字符串,而这个方法不用转,直接就可以存
- 一套代码,它会自动根据不同的环境编译成不同的代码,比如浏览器就存到localStorage,如果微信就存到微信的地方
- 先声明一个数组用来保存历史记录
data () {
return {
historyList:[]
}
}
- 去改良
uni-tag ,v-for改成根据 historyList 来生成
<view class="history-item">
<uni-tag v-for="(item,index) in historyList" :key="index" :text="item" type="success" />
</view>
- 然后在每次去做搜索建议的时候,把输入的内容存到数组里
this.time = setTimeout(async () => {
if (this.key === '') return
// 发请求之前我先把历史记录存起来
// 先把输入的内容加到数组里
this.historyList.unshift(this.key)
// 把数组存到本地
uni.setStorageSync('history', this.historyList)
............
})
data () {
return {
historyList: uni.getStorageSync('history') || []
}
}
- 此时发现:如果输入以前就搜索过的内容会让记录多一条,所以要做一个判断,如果搜索的内容不在数组里,才允许加到数组里
if (this.historyList.indexOf(this.key) === -1) {
// 发请求之前我先把历史记录存起来
// 先把输入的内容加到数组里
this.historyList.unshift(this.key)
// 把数组存到本地
uni.setStorageSync('history', this.historyList)
}