一、搜索商家列表ajax请求编写+放入vuex+获取
1)准备及获取state page/search/search.vue
<!-- 【3】阻止默认提交事件,用search方法代替 -->
<form class="search_form" @submit.prevent="search">
<!--【1】绑定数据 -->
<input type="search" placeholder="请输入商家名称" class="search_input" v-model="searchWord">
<input type="submit" class="search_submit">
</form>
import {mapState} from 'vuex'
export default{
data(){
return{
searchWord:'',//【2】搜索关键词
}
},
computed:{
...mapState(['searchShops'])
},
methods:{
//【4】提交搜索并保存数据到state里
search(){
//【4】提交搜索并保存数据到state里
search(){
// 得到搜索词并去除空格
const searchWord=this.searchWord.trim()
if(searchWord){//不为空再触发actions的searchSHops()方法
this.$store.dispatch('searchSHops',this.searchWord)
}
}
}
}
2)ajax请求api/index.js
/*
包含n个接口请求函数的模块
函数的返回值: promise对象
*/
import ajax from './ajax.js'
const BASE_URL='/api'
// 4、根据经纬度和关键字搜索商铺列表
export const reqSearchShop = (geohash, keyword) => ajax(BASE_URL+'/search_shops', {geohash, keyword})
3)store/state.js 相关状态
// 所有要管理的状态数据:从页面需求分析出来,最好和api/index.js里的命名相同
export default{
latitude: 40.10038, // 纬度
longitude: 116.36867, // 经度
...略过
searchShops: [], // 搜索得到的商家列表
}
4)mutation-types.js 类型
export const RECEIVE_SEARCH_SHOPS = 'receive_search_shops' // 接收搜索的商家数组
5)mutations.js 保存action请求到的数据放入state
// 用于把actions请求到的数据传到state中
import {
略过……
RECEIVE_SEARCH_SHOPS, //【1】搜索得到的店铺列表
} from './mutation-types.js'
export default{
// 【2】保存搜索店铺列表到状态
[RECEIVE_SEARCH_SHOPS](state,{shops}){
console.log('mutation:',shops)
state.searchShops=shops
}
}
6)actions.js发起ajax请求 把数据传入mutations
// 控制mutations
import {
略过……
RECEIVE_SEARCH_SHOPS//【0】搜索得到的商家列表类型
} from './mutation-types.js'
import {
略过……
reqSearchShop,//【1】搜索得到的商家列表api
} from '../api/index.js'
export default{
略过……
//【2】异步请求带关键词的搜索结果,传入mutations
async searchSHops({commit,state},searchWord){
//拼接参数1:纬度,经度
const geohash=state.latitude+','+state.longitude
const result = await reqSearchShop(geohash,searchWord)
if(result.code===0){
/*【注意】此处的shops命名不能为searchShops
否则mutations将不能正常取到数据*/
const shops=result.data
console.log(shops)
//【3】提交到mutations
commit(RECEIVE_SEARCH_SHOPS,{shops})
}
}
}
结果:http://localhost:8080/#/search
数据正常传入state及组件
vuex中
二、有数据时显示数据,无数据时显示暂无结果
<!--【2】v-if判断data为false则显示列表-->
<section class="list" v-if="!noSearchShops">
<ul class="list_container">
...
<!--否则显示抱歉-->
<div class="search_none" v-else>很抱歉!无搜索结果</div>
</section>
</template>
data(){
return{
...略过
noSearchShops: false //【1】是否没有搜索到符合要求的店铺
}
},
watch:{
//【3】监视state的数据searchShop如果值变化则执行:
searchShops(value){
if(!value.length){//没有数据
this.noSearchShops=true
}else{//有数据
this.noSearchShops=false
}
}
}
效果:要么显示搜索好的商家列表,要么显示没数据!
三、li标签换成店铺访问链接,用tag把router-link在编译时转化为Li+to传带参数2种写法
知识点,router-link传参数两种写法:
<router-link :to="{path:'/shop', query:{id:shop.id}}" tag="li">
或:
<router-link :to=:to="'/shop?id='+item.id" tag="li">
<ul class="list_container">
<!--to也可写成 :to="'/shop?id='+item.id" -->
<router-link :to="{path:'/shop', query:{id:shop.id}}"
tag="li" v-for="shop in searchShops"
:key="shop.id" class="list_li">
略过……
</router-link>
附件:ajax.js axios写的请求
/*
ajax请求函数模块
返回值: promise对象(异步返回的数据是: response.data)
*/
import axios from 'axios'
export default function ajax (url, data={}, type='GET') {
return new Promise(function (resolve, reject) {
// 执行异步ajax请求
let promise
if (type === 'GET') {
// 准备url query参数数据
let dataStr = '' //数据拼接字符串
Object.keys(data).forEach(key => {
dataStr += key + '=' + data[key] + '&'
})
if (dataStr !== '') {
dataStr = dataStr.substring(0, dataStr.lastIndexOf('&'))
url = url + '?' + dataStr
}
// 发送get请求
promise = axios.get(url)
} else {
// 发送post请求
promise = axios.post(url, data)
}
promise.then(function (response) {
// 成功了调用resolve()
resolve(response.data)
}).catch(function (error) {
//失败了调用reject()
reject(error)
})
})
}
附件:search.vue完整代码
<template>
<section class="search">
<TopHeader title="搜索"/>
<!-- 【3】阻止默认提交事件,用search方法代替 -->
<form class="search_form" @submit.prevent="search">
<!--【1】绑定数据 -->
<input type="search" placeholder="请输入商家名称" class="search_input" v-model="searchWord">
<input type="submit" class="search_submit">
</form>
<section class="list" v-if="!noSearchShops">
<ul class="list_container">
<!--:to="'/shop?id='+item.id"-->
<router-link :to="{path:'/shop', query:{id:shop.id}}" tag="li"
v-for="shop in searchShops" :key="shop.id" class="list_li">
<section class="item_left">
<img src="http://localhost:8080/static/img/4.48fe00b.jpg"
class="restaurant_img">
</section>
<section class="item_right">
<div class="item_right_text">
<p>
<span>{{shop.name}}</span>
</p>
<p>月售 {{shop.recent_order_num}} 单</p>
<p>{{shop.float_minimum_order_amount}} 元起送 / 距离{{shop.distance}}</p>
</div>
</section>
</router-link>
</ul>
</section>
<div class="search_none" v-else>很抱歉!无搜索结果</div>
</section>
</template>
<script>
import TopHeader from '../../components/TopHeader/TopHeader.vue'
import {mapState} from 'vuex'
export default{
data(){
return{
searchWord:'',//【2】搜索关键词
noSearchShops: false //是否没有搜索到符合要求的店铺
}
},
computed:{
...mapState(['searchShops'])
},
methods:{
//【4】提交搜索并保存数据到state里
search(){
// 得到搜索词并去除空格
const searchWord=this.searchWord.trim()
if(searchWord){//不为空再触发actions的searchSHops()方法
this.$store.dispatch('searchSHops',this.searchWord)
}
}
},
watch:{
//监视state的数据searchShop如果值变化则执行:
searchShops(value){
if(!value.length){//没有数据
this.noSearchShops=true
}else{//有数据
this.noSearchShops=false
}
}
},
components:{
TopHeader,
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus" scoped>
@import "../../common/stylus/mixins.styl"
.search
width 100%
height 100%
overflow hidden
.search_form
clearFix()
margin-top 45px
background-color #fff
padding 12px 8px
input
height 35px
padding 0 4px
border-radius 2px
font-weight bold
outline none
&.search_input
float left
width 79%
border 4px solid #f2f2f2
font-size 14px
color #333
background-color #f2f2f2
&.search_submit
float right
width 18%
border 4px solid #02a774
font-size 16px
color #fff
background-color #02a774
.list
.list_container
background-color: #fff;
.list_li
display: flex;
justify-content: center;
padding: 10px
border-bottom: 1px solid $bc;
.item_left
margin-right: 10px
.restaurant_img
width 50px
height 50px
display block
.item_right
font-size 12px
flex 1
.item_right_text
p
line-height 12px
margin-bottom 6px
&:last-child
margin-bottom 0
.search_none
margin: 0 auto
color: #333
background-color: #fff
text-align: center
margin-top: 0.125rem
</style>