vue外卖二十三:搜索页:搜索商家列表ajax请求编写+放入vuex+获取、有数据时显示数据,无数据时显示暂无结果、li标签换成店铺访问链接,tag把router-link转Li+to传参2种写法

45 篇文章 2 订阅

一、搜索商家列表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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值