56 - 综合案例 - 智慧商城-08 - 搜索

一. 搜索 -历史记录管理

目标:构建搜索页的静态布局,完成历史记录的管理

需求:
        (1). 搜索历史基本渲染      

        (2). 点击搜索(添加历史)
                点击 搜索按钮 或 底下历史记录,都能进行搜索
                ①. 若之前 没有 相同搜索关键字,则直接 追加到最前面

                ②. 若之前 已有 相同搜索关键字,将该原有关键字移除,再追加

        (3). 清空历史:添加清空图标,可以清空历史记录

        (4). 持久化:搜索历史需要持久化,刷新历史不丢失

                

1. 搜索历史基本渲染

        search / index.vue

<template>
  <div class="search">
    <van-nav-bar title="商品搜索" left-arrow @click-left="$router.go(-1)" />
    <van-search show-action shape="round" placeholder="请输入搜索关键词" clearable>
      <template #action>
        <div>搜索</div>
      </template>
    </van-search>

    <!-- 搜索历史 -->
    <div class="search-history">
      <div class="title">
        <span>最近搜索</span>
        <van-icon name="delete-o" size="16" />
      </div>
      <div class="list">
        <div class="list-item">手机</div>
        <div class="list-item">电视</div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'SearchtailIndex',
  data () {
    return {
      history: ['手机', '白酒', '电视'] // 历史记录
    }
  }

}
</script>
<style lang="less" scoped>
.search {
  .searchBtn {
    background-color: #fa2209;
    color: #fff
  }

  ::v-deep .van-search__action {
    background-color: #c21401;
    color: #fff;
    padding: 0 20px;
    border-radius: 0 5px 5px 0;
    margin-right: 10px;
  }

  ::v-deep .van-icon-arrow-left {
    color: #333;
  }

  .title {
    height: 40px;
    line-height: 40px;
    font-size: 14px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 15px;
  }

  .list {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    padding: 0 10px;
    gap: 5%
  }

  .list-item {
    width: 30%;
    text-align: center;
    padding: 7px;
    line-height: 15px;
    border-radius: 50px;
    background: #fff;
    font-size: 13px;
    border: 1px solid #efefef;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    margin-bottom: 10px;

  }

}
</style>
2. 注册Icon组件

        utils / vant-ui.js

// 按需导入
import Vue from 'vue'
import {Icon} from 'vant'

Vue.use(Icon)
3. 添加操作历史记录

        search / index.vue

<template>
    <!-- 双向绑定获取输入框的值 -->
    <van-search v-model="search" show-action shape="round" placeholder="请输入搜索关键词" clearable>

    <!-- 将输入框中的search传入 -->
    <div @click="goSearch(search)">搜索</div>

    <!--判断是否有数据-->
    <div class="search-history" v-if="history.length > 0">

    <!--点击清空-->
    <van-icon @click="clear" name="delete-o" size="16" />
     
    <!-- 将循环出的数据名传入 -->
     <div v-for="item in history" :key="item" class="list-item" @click="goSearch(item)">{{item}}</div>
      
</template>

<script>
export default {
  name: 'SearchtailIndex',
  data () {
    return {
      search: '', // 输入框的内容
      history: ['手机', '白酒', '电视'] // 历史记录
    }
  },
  methods: {
    goSearch (key) {
      // console.log('进行了搜索,搜索历史要更新', key)
      // indexOf: 查询key在this.history中的下标,不存在返回-1
      const index = this.history.indexOf(key)
      if (index !== -1) {
        // 存在相同的项,将原有关键字移除
        // splice(从哪开始,删几个,项1,项2)
        this.history.splice(index, 1)
      }
      // 将数据追加到第一个
      this.history.unshift(key)
    },
    // 清空搜索记录
    clear () {
      this.history = []
    }
  }
}
</script>
4. 持久化
        (1). 封装持久化工具

                utils / storage.js


// 约定一个通用键名
...
const HISTORY_KEY = 'cc_history_list'

// 获取个人信息
...

// 获取搜索历史
export const getHistoryList = () => {
  const result = localStorage.getItem(HISTORY_KEY)
  return result ? JSON.parse(result) : []
}

// 设置搜索历史
export const setHistoryList = (arr) => {
  localStorage.setItem(HISTORY_KEY, JSON.stringify(arr))
}
        (2). 页面中直接调用

                search / index.vue

<script>
import { getHistoryList, setHistoryList } from '@/utils/storage'
//export default {
 // name: 'SearchtailIndex',
 // data () {
  //  return {
      //search: '', // 输入框的内容
      history: getHistoryList() // 从本地获取历史记录
//    }
//  },
//  methods: {
 //   goSearch (key) {
      // console.log('进行了搜索,搜索历史要更新', key)
      // indexOf: 查询key在this.history中的下标,不存在返回-1
      //const index = this.history.indexOf(key)
      //if (index !== -1) {
        // 存在相同的项,将原有关键字移除
        // splice(从哪开始,删几个,项1,项2)
       // this.history.splice(index, 1)
      //}
      // 将数据追加到第一个
      //this.history.unshift(key)

      // 往本地存储
      setHistoryList(this.history)

      // 跳转到搜索列表页
      this.$router.push(`/searchlist?search=${key}`)
    },
    // 清空
    //clear () {
      //this.history = []
      setHistoryList([]) // 本地也清空
  //  }
// }
//}
</script>
        5. 代码示例

二. 搜索列表- 静态布局 & 渲染

目标:实现搜索列表页静态结构,封装接口,完成搜索列表页的渲染

        

1. 静态页面渲染

        search / list.vue

<template>
  <div class="search">
    <van-nav-bar fixed title="商品搜索" left-arrow @click-left="$router.go(-1)" />
    <van-search readonly shape="round" background="#ffffff" value="手机" show-action  @click="$router.push('/search')">
      <template>
        <van-icon class="tool" name="apps-o" />
      </template>
    </van-search>

    <!-- 排序选项按钮 -->
    <div class="sort-btns">
      <div class="sort-item">综合</div>
      <div class="sort-item">销量</div>
      <div class="sort-item">价格</div>
    </div>

    <div class="goods-list">
      <GoodsItem v-for="item in 10" :key="item"></GoodsItem>
    </div>
  </div>
</template>
<script>
import GoodsItem from '@/components/GoodsItem.vue'
export default {
  name: 'ListIndex',
  components: {
    GoodsItem
  }
}
</script>

<style lang="less" scoped>
.search {
  padding-top: 46px;

  ::v-deep .van-icon-arrow-left {
    color: #333;
  }

  .tool {
    font-size: 24px;
    height: 40px;
    line-height: 40px;
  }

  .sort-btns {
    display: flex;
    height: 36px;
    line-height: 36px;

    .sort-item {
      text-align: center;
      flex: 1;
      font-size: 16px;
    }
  }

}

// 商品样式
.goods-list {
  background-color: #f6f6f6;
}
</style>
2. 封装请求数据接口

        api / product.js

import request from '@/utils/request'

// 获取搜索商品列表的数据
export const getProList = (obj) => {
  const { categoryId, goodsName, page } = obj
  return request.get('/goods/list', {
    params: {
      categoryId,
      goodsName,
      page

    }
  })
}
3. 调用接口渲染页面

        search / list.vue

<template>
    <!--显示地址栏中的参数-->
    <van-search readonly shape="round" background="#ffffff" :value="querySearch || '搜索商品'" show-action @click="$router.push('/search')">

    <!--向子组件传递参数-->
    <GoodsItem v-for="item in proList" :key="item.goods_id" :item="item"></GoodsItem>
</template>

<script>
import GoodsItem from '@/components/GoodsItem.vue'
import { getProList } from '@/api/product'
export default {
  name: 'ListIndex',
  components: {
    GoodsItem
  },
  computed: {
    // 获取地址栏的搜索关键字
    querySearch() {
      return this.$route.query.search
    }
  },
  data() {
    return {
      page: 1,
      proList: []
    }
  },
  async created() {
    const { data: { list } } = await getProList({
      goodsName: this.querySearch,
      page: this.page
    })
    this.proList = list.data
  }
}
</script>
4. 代码示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值