大致实现页面如下:
分析:
在这里其实热门搜索以及搜索历史共用的是同一个组件--card组件这里暂时起名为 分析不难发现这两部分皆是由头部和躯体两部分组成,只是显示的标题不同,内容不同。搜索记录头部比热门搜索多了一个“清除搜索记录”,那么这里完全可以利用插槽实现,其主体内容部分也可以由插槽实现,即实现头部和主体区域要展示什么皆由“我”自己决定
封装card组件: components/common/card/card.vue
<template>
<view class="card" :style="cardStyle">
<!-- 头部 -->
<view v-if="showHead" class="p-2 main-border-color d-flex a-center j-sb" :class="getHeadClass">
<slot name="title">
<text v-if="headerTitle" class="font-md" :class="headerTitleWeight ? 'font-weight' : ''">{{headerTitle}}</text>
</slot>
<slot name="right"></slot>
</view>
<!-- 内容 -->
<view :class="getBodyClass" :style="bodyStyle">
<image v-if="bodyCover" :src="bodyCover" mode="widthFix" style="height: 300rpx;width: 750rpx;"></image>
<slot name="body"></slot>
</view>
</view>
</template>
<script>
export default {
props: {
// 头部标题
headerTitle: String,
// 封面图片
bodyCover: String,
// 是否显示头部
showHead: {
type:Boolean,
default: true
},
// 头部标题是否加粗
headerTitleWeight: {
type: Boolean,
default: true
},
//是否显示下边
headBorderBottom: {
type: Boolean,
default: true
},
// 是否给body加padding
bodyPadding: {
type: Boolean,
default: false
},
// body样式
bodyStyle: String,
cardStyle:{
type:String,
default:""
}
},
name:"card",
data() {
return {
};
},
computed: {
getHeadClass() {
let borderBottom = this.headBorderBottom ? 'border-bottom' : ''
return `${borderBottom}`
},
getBodyClass(){
let padding = this.bodyPadding ? 'p-2' : ''
return `${padding}`
},
}
}
</script>
<style lang="scss" scoped>
</style>
搜索实现 search.vue
<template>
<view>
<card headerTitle="热门搜索" bodyCover="/static/images/demo/search-banner.png"></card>
<!-- 多色按钮 -->
<view class="px-1 mb-2">
<colorTag v-for="(item ,index) in hot" :key="item.id" :item="item" :color="true" />
</view>
<!-- 常用分类 -->
<card headerTitle="常用分类" :bodyPadding="true" :headBorderBottom="false">
<template slot="body">
<colorTag v-for="(item,index) in cate" :key="index" :item="item" :color="false" />
</template>
</card>
<!-- 搜索记录 -->
<template v-if="historyList.length > 0">
<!-- 分割线 -->
<divider></divider>
<!-- 搜索记录 -->
<card headerTitle="搜索记录">
<view class="font text-primary" slot="right" @click="clearHistory">
清除搜索记录
</view>
<template slot="body">
<uni-list>
<uni-list-item v-for="(item,index) in historyList" :key="index" :title="item"></uni-list-item>
</uni-list>
</template>
</card>
</template>
</view>
</template>
<script>
import colorTag from '@/components/search/color-tag.vue';
import card from '@/components/common/card/card.vue';
export default {
components: {
colorTag,
card,
},
data() {
return {
// 热门
hot: [{
name: "领劵中心",
id: 1
},
{
name: "Redmi K20",
id: 2
},
{
name: "RedmiBook 14",
id: 3
},
{
name: "智能积木,越野四驱车",
id: 4
},
{
name: "手环 腕带",
id: 5
}
],
// 常用分类
cate: [{
name: '耳机',
id: 1
}, {
name: '手机',
id: 2
},
{
name: '音箱',
id: 3
},
{
name: '手表',
id: 4
},
{
name: '配件',
id: 5
},
{
name: '网关/传感器',
id: 6
},
{
name: '健康',
id: 7
},
{
name: '酷玩',
id: 8
}
],
// 搜索历史
historyList: [],
// 搜索关键字
keyword: "",
}
},
// 监听顶部搜索按钮
onNavigationBarButtonTap(e) {
if (e.index === 0) {
this.search();
}
},
// 监听原生搜索框的变化
onNavigationBarSearchInputChanged(e) {
this.keyword = e.text;
},
// 监听原生搜索框的提交事件
onNavigationBarSearchInputConfirmed() {
this.search();
},
onLoad() {
// 加載搜索历史记录
let history = uni.getStorageSync('searchHistory');
this.historyList = history ? JSON.parse(history) : [];
},
methods: {
// 搜索方法
search() {
if (this.keyword === '') {
return uni.showToast({
icon: 'none',
title: '关键词不能为空'
})
}
// 在手机上点击搜索的时候隐藏键盘
// #ifdef APP-PLUS
plus.key.hideSoftKeybord(); // APP端隐藏键盘
// #endif
// #ifndef APP-PLUS
uni.hideKeyboard();
// #endif
// 搜索逻辑
this.addHistory();
},
// 加入搜索记录的方法
addHistory() {
let index = this.historyList.indexOf(this.keyword);
// 判断当前搜索的关键词是否已经存在
if(index === -1){
this.historyList.unshift(this.keyword);
} else {
// 若当前搜索的关键词已经存在,那么就将在搜索历史数组里的
// 关键词删除掉,将当前的放在头部--置顶效果
this.historyList.unshift(this.historyList.splice(index,1)[0]);
}
// 本地存储
uni.setStorageSync('searchHistory', JSON.stringify(this.historyList));
},
// 清除搜索记录
clearHistory() {
uni.showModal({
title: '提示',
content: '是否要清除搜索历史',
cancelText: '取消',
confirmText: '清除',
success: res => {
if(res.confirm) {
uni.clearStorageSync('searchHistory');
this.historyList = [];
}
}
})
},
}
}
</script>
最终效果: