23 搜索相关
23.1 首页的头部
<template> <div class="box"> <header class="header"> <div class="mynav"> <router-link to="/kind" tag="div" class="left"> <van-icon name="wap-nav" size="18"/> </router-link> <div class="title"> <router-link to="/search" tag="div" class="search"> <van-icon name="search" size="18"/> <p>移动硬盘500g</p> </router-link> </div> <div class="right"> <van-icon v-if="loginState" name="user-o" size="18"/> <router-link to="/login" tag="p" v-else>登录</router-link> </div> </div> </header> ... </div> </template> <script> import { mapState } from 'vuex' export default { computed: { ...mapState({ loginState: state => state.user.loginState }) }, ..... } </script> <style lang="stylus" scoped> .... .mynav background-color #f66 display flex height 0.44rem color #fff .left width 50px display flex justify-content center align-items center .title flex 1 display flex justify-content center align-items center .search width 100% height 0.32rem background-color #fff border-radius 16px display flex line-height 0.32rem color #999 .van-icon width 26px margin 7px 4px 7px 20px p flex 1 .right width 50px display flex justify-content center align-items center </style>
23.2 定义搜索页面以及注册路由
<template> <div class="box"> <div class="header"> <van-search v-model="keyword" show-action placeholder="请输入搜索关键词" @search="onSearch" > <template #action> <div @click="onSearch">搜索</div> </template> </van-search> </div> <div class="content"> <h3>最近搜索</h3> <h3>热门搜索</h3> </div> </div> </template> <script> import Vue from 'vue' import { Search } from 'vant' Vue.use(Search) export default { data () { return { keyword: '' } }, methods: { onSearch () {} } } </script> <style lang="stylus" scoped> .van-search padding 5px 12px </style>
{ path: '/search', name: 'search', component: () => import('../views/search/index.vue') }, { path: '**', component: () => import('../views/home/index.vue') }
23.3 搜索结果页面
// src/views/search/result.vue
<template> <div class="box"> <div class="header"> <van-search v-model="keyword" show-action placeholder="请输入搜索关键词" @search="onSearch" > <template #left> <van-icon name="arrow-left" size="18"/> </template> <template #action> <div @click="onSearch">搜索</div> </template> </van-search> </div> <div class="content"> </div> </div> </template> <script> import Vue from 'vue' import { Search, Icon } from 'vant' Vue.use(Search) Vue.use(Icon) export default { data () { return { keyword: '' } }, methods: { onSearch () {} } } </script> <style lang="stylus" scoped> .van-search padding 5px 12px .van-search__content margin-left 12px </style>
{ path: '/searchresult', // /searchresult?keyword=111 name: 'searchresult', component: () => import('../views/search/result.vue') }, { path: '**', component: () => import('../views/home/index.vue') }
请求渲染数据
/ api/search.js
import request from '@/utils/request' export function search (params) { return request.get('/pro/search', { params }) }
<!--search/result.vue--> <template> <div class="box"> <div class="header"> <van-search v-model="keyword" show-action placeholder="请输入搜索关键词" @search="onSearch" > <template #left> <van-icon name="arrow-left" size="18"/> </template> <template #action> <div @click="onSearch">搜索</div> </template> </van-search> </div> <div class="content"> <van-dropdown-menu> <van-dropdown-item v-model="priceVal" :options="priceOption" /> <van-dropdown-item v-model="salesVal" :options="salesOption" /> <van-dropdown-item title="筛选" ref="item"> <van-cell center title="包邮"> <template #right-icon> <van-switch v-model="switch1" size="24" active-color="#ee0a24" /> </template> </van-cell> <van-cell center title="团购"> <template #right-icon> <van-switch v-model="switch2" size="24" active-color="#ee0a24" /> </template> </van-cell> <div style="padding: 5px 16px;"> <van-button type="danger" block round @click="onConfirm"> 确认 </van-button> </div> </van-dropdown-item> </van-dropdown-menu> <van-card v-for="item of list" :key="item.proid" :price="item.originprice" :desc="item.desc" :title="item.proname" :thumb="item.img1" /> </div> </div> </template> <script> import Vue from 'vue' import { Search, Icon, Toast, Card, DropdownMenu, DropdownItem, Cell, Switch, Button } from 'vant' import { search } from '@/api/search' Vue.use(Search) Vue.use(Icon) Vue.use(Toast) Vue.use(Card) Vue.use(DropdownMenu) Vue.use(DropdownItem) Vue.use(Cell) Vue.use(Switch) Vue.use(Button) export default { data () { return { list: [], keyword: '', priceVal: 0, salesVal: 0, switch1: false, switch2: false, priceOption: [ { text: '默认排序', value: 0 }, { text: '价格升序', value: 1 }, { text: '价格降序', value: 2 } ], salesOption: [ { text: '销量排序', value: 0 }, { text: '销量升序', value: 1 }, { text: '销量降序', value: 2 } ] } }, mounted () { search({ keyword: this.$route.query.keyword }).then(res => { if (res.data.code === '10002') { Toast('暂未找到相关商品') } else { this.list = res.data.data } }) }, methods: { onConfirm () { this.$refs.item.toggle() }, onSearch () {} } } </script> <style lang="stylus" scoped> .van-search padding 5px 12px .van-search__content margin-left 12px </style>
排序以及筛选关联. ---- 深拷贝 备份数据
<template> <div class="box"> <div class="header"> <van-search v-model="keyword" show-action placeholder="请输入搜索关键词" @search="onSearch" > <template #left> <van-icon name="arrow-left" size="18"/> </template> <template #action> <div @click="onSearch">搜索</div> </template> </van-search> </div> <div class="content"> <van-sticky :offset-top="44"> <van-dropdown-menu> <van-dropdown-item v-model="priceVal" @change="priceChange" :options="priceOption" /> <van-dropdown-item v-model="salesVal" @change="salesChange" :options="salesOption" /> <van-dropdown-item title="筛选" ref="item"> <h3>价格区间</h3> <van-cell center> <template #right-icon> <van-field v-model="min" placeholder="最低价" /> - <van-field v-model="max" placeholder="最高价" /> </template> </van-cell> <div style="padding: 5px 16px;"> <van-button type="danger" block round @click="onConfirm"> 确认 </van-button> </div> </van-dropdown-item> </van-dropdown-menu> </van-sticky> <van-card v-for="item of list" :key="item.proid" :num="item.sales" :price="item.originprice" :desc="item.desc" :title="item.proname" :thumb="item.img1" /> </div> </div> </template> <script> import Vue from 'vue' import { Search, Icon, Toast, Sticky, Field, Card, DropdownMenu, DropdownItem, Cell, Switch, Button } from 'vant' import { search } from '@/api/search' Vue.use(Search) Vue.use(Icon) Vue.use(Field) Vue.use(Toast) Vue.use(Card) Vue.use(DropdownMenu) Vue.use(DropdownItem) Vue.use(Cell) Vue.use(Sticky) Vue.use(Switch) Vue.use(Button) export default { data () { return { list: [], readyList: [], min: '', max: '', keyword: '', priceVal: 0, salesVal: 0, switch1: false, switch2: false, priceOption: [ { text: '默认排序', value: 0 }, { text: '价格升序', value: 1 }, { text: '价格降序', value: 2 } ], salesOption: [ { text: '销量排序', value: 0 }, { text: '销量升序', value: 1 }, { text: '销量降序', value: 2 } ] } }, mounted () { this.keyword = this.$route.query.keyword search({ keyword: this.$route.query.keyword }).then(res => { if (res.data.code === '10002') { Toast('暂未找到相关商品') } else { this.list = res.data.data // 深拷贝 this.readyList = JSON.parse(JSON.stringify(res.data.data)) } }) }, methods: { priceChange (value) { console.log(value) if (value === 0) { // 深拷贝 this.list = JSON.parse(JSON.stringify(this.readyList)) } else if (value === 1) { this.list.sort((a, b) => { return a.originprice - b.originprice }) } else if (value === 2) { this.list.sort((a, b) => { return b.originprice - a.originprice }) } else { } }, salesChange (value) { console.log(value) if (value === 0) { // 深拷贝 this.list = JSON.parse(JSON.stringify(this.readyList)) } else if (value === 1) { this.list.sort((a, b) => { return a.sales - b.sales }) } else if (value === 2) { this.list.sort((a, b) => { return b.sales - a.sales }) } else { } }, onConfirm () { // 只写最低价 // 深拷贝 this.list = JSON.parse(JSON.stringify(this.readyList)) const arr = this.list.filter(item => { // 既有最小值也有最大值 if (this.min !== '' && this.max !== '') { return item.originprice > this.min && item.originprice < this.max } else if (this.min === '' && this.max !== '') { // 没有最小值有最大值 return item.originprice > 0 && item.originprice < this.max } else { // 只有最小值 return item.originprice > this.min } }) this.list = arr // this.min = '' // this.max = '' this.$refs.item.toggle() }, onSearch () {} } } </script> <style lang="stylus" scoped> .van-search padding 5px 12px .van-search__content margin-left 12px </style>
23.4 搜索继续搜索
Views/search/result.vue
..... export default { .... watch: { $route (newVal) { this.keyword = newVal.query.keyword search({ keyword: newVal.query.keyword }).then(res => { if (res.data.code === '10002') { Toast('暂未找到相关商品') } else { this.list = res.data.data // 深拷贝 this.readyList = JSON.parse(JSON.stringify(res.data.data)) } }) } } } </script>
23.4 搜索页面跳转
如果输入框为空,不可以跳转
23.5 记录搜索信息
vie w s/search/result.vue
mounted () { this.keyword = this.$route.query.keyword search({ keyword: this.$route.query.keyword }).then(res => { if (res.data.code === '10002') { Toast('暂未找到相关商品') } else { this.list = res.data.data // 深拷贝 this.readyList = JSON.parse(JSON.stringify(res.data.data)) // ************************ const arr = JSON.parse(localStorage.getItem('search')) || [] const index = arr.indexOf(this.keyword) if (index > -1) { arr.splice(index, 1) } arr.unshift(this.keyword) console.log(arr) localStorage.setItem('search', JSON.stringify(arr)) } }) }, watch: { $route (newVal) { this.keyword = newVal.query.keyword search({ keyword: newVal.query.keyword }).then(res => { if (res.data.code === '10002') { Toast('暂未找到相关商品') } else { this.list = res.data.data // 深拷贝 this.readyList = JSON.parse(JSON.stringify(res.data.data)) // ************************ const arr = JSON.parse(localStorage.getItem('search')) || [] const index = arr.indexOf(this.keyword) if (index > -1) { arr.splice(index, 1) } arr.unshift(this.keyword) console.log(arr) localStorage.setItem('search', JSON.stringify(arr)) } }) } }