美团项目 --- 搜索栏及推荐 6

都是类比巩固 …

↓ 在server/interface中创建接口search.js来搭建关于搜索推荐的接口

/**
 * descripe: 搜索栏及推荐列表的接口设置
 * author: umbrella
 * date: 2018-6-28PM21:39:01
 * --------------------说明-----------------------
 * --koa-router路由 || 引入封装的axios数据通讯 || 引入相对应的线下数据表Poi
 * --定义路由主体的前缀
 * --定义接口  获取搜索时显示的内容接口top || 根据定位获取推荐景点接口hotPlace
 * --导出路由router  
 */
import Router from 'koa-router'
import axios from './utils/axios'
import Poi from '../dbs/models/poi'

// 请求页面接口请求前缀
let router = new Router({
    prefix: '/search'
})

// 获取搜索时显示的内容接口
router.get('/top',async (ctx) =>{
    let{status,data:{top}} = await axios.get('http://cp-tools.cn/search/top?sign',{
        params:{
            input: ctx.query.input,
            city: ctx.query.city
        }
    })
    ctx.body = {
        top: status === 200 ? top : []
    }
})

// 根据定位获取推荐景点接口
router.get('/hotPlace', async(ctx) =>{
    let city = ctx.store ? ctx.store.geo.position.city : ctx.query.city;
    let{status,data:{result}} = await axios.get('http://cp-tools.cn/search/hotPlace?sign',{
        params:{
            city
        }
    })
    ctx.body = {
        result: status === 200 ? result : []
    }
})
export default router

从此有关search中需要涉及的接口就写在search.js

↓ 之后记得index.js配置导入的search的路由

import search from './interface/search'
app.use(search.routes()).use(search.allowedMethods())

如果需要操作数据库的话(操作线下),就要设计对应的数据库表pois对应数据的表结构
在这里插入图片描述
然后项目中进行代码调用:

import mongoose from 'mongoose'
const Schema = mongoose.Schema
const Poi = new Schema({
    name: {
        type: String   // 景点名称
    },
    province: {
        type: String   // 景点所在省份
    },
    city: {
        type: String   // 景点所在城市
    },
    county: {
        type: String   // 景点所在市级
    },
    areaCode: {
        type: String   // 景点所在区域代码
    },
    tel: {
        type: String   // 景点联系电话
    },
    area: {
        type: String   // 景点区域名称
    },
    addr: {
        type: String   // 景点具体地址
    },
    type: {
        type: String   // 景点类型名
    },
    module: {
        type: String   // 景点具体详情
    },
    longtide:{
        type: Number   // 景点经度
    },
    latitude:{
        type: Number   // 景点纬度
    }
})

export default mongoose.model('Poi', Poi)

最后记得如果要使用Poi的话就要在search路由中进行导入

这里说一下两种使用koa-router请求数据的写法

router.get('/top',async(ctx) => {
	let{status,data:{top}} = await $axios.get(`http://cp-tools/search/top?input=${ctx.query.input}&city=${ctx.query.city}&sign`)
})

router.get('/top', async(ctx) => {
	let{status,data:{top}} = await $axios.get('http://cp-tools/search/top?sign',{
		params:{
			input: ctx.query.input,
			city: ctx.query.city
		}
	})
)

说一点(重要):ctx.query 是get请求拿页面数据的方式 || ctx.request.body则是post

这样就配置好了一个线上的请求接口,那么我们可以根据我们写的接口params去使用postman测试一下接口是否可以返回值:
在这里插入图片描述
能返回值就说明请求成功啦

↓ 配置vuex中的store三者关系:

const state = () => ({
    menu: [],
    hotPlace: []
})

const mutations = {
    setMenu(state, val) {
        state.menu = val
    },
    setHotPlace(state, val) {
        state.hotPlace = val
    }
}

const actions = {
    setMenu: ({
        commit
    }, menu) => {
        commit('setMenu', menu)
    },
    setHotPlace: ({
        commit
    }, hotPlace) => {
        commit('setHotPlace', hotPlace)
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
}

↓ 对应创建store实例

/**
 * descripe: 创建store实例提供给页面调用Store库中的方法及获取内部的数据
 * author: umbrella
 * data: 2019-6-30AM13:07:48
 * -------------说明--------------
 * -- 导入Vue、Vuex必备包 || 其次导入需要被页面调用的Store库geo、home
 * -- 配置各自管理的模版名称geo、home,之后页面拿state中的数据就是通过modules区分,
 *    例如拿geo中state容器中的数据city → $store.state.geo.position.city
 * -- 使用nuxt中的nuxtServerInit生命周期函数 → 进行页面载入时就已经执行了Store中相关的路由方法
 * -- 注意点:由于页面实例还没渲染到页面,因此只能通过app根节点进行$axios的请求
 */
import Vue from 'vue'
import Vuex from 'vuex'
import geo from './modules/geo'
import home from './modules/home'

Vue.use(Vuex)

const store = () => new Vuex.Store({
    modules: {
        geo,
        home
    },
    actions: {
        async nuxtServerInit({
            commit
        }, {
            req,
            app
        }) {
        const {
                status: status3,
                data: {
                    result
                }
            } = await app.$axios.get('/search/hotPlace', {
                params: {
                    city: app.store.state.geo.position.city.replace('市', '')
                }
            })
            commit('home/setHotPlace', status3 === 200 ? result.slice(0, 4) : [])

        }
    }
})

↓ 既然调试接口成功,那我们就把这个返回的数据写在我们的页面上(这个数据是搜索时请求的数据,那么我们找到搜索栏界面components->public->header->searchbar.vue)
html:

<dl v-if="isHotPlace" class="hotPlace">
   <dt>热门搜索</dt>
   <dd v-for="(item,index) in $store.state.home.hotPlace" :key="index">{{item.name}}</dd>
</dl>

javascript:

input: _.debounce(async function() {
      let self = this;
      let city = self.$store.state.geo.position.city.replace("市", "");
      self.searchList = [];
      let {
        state,
        data: { top }
      } = await self.$axios.get("/search/top", {
        params: {
          input: self.search,
          city
        }
      });
      self.searchList = top.slice(0,10)
    }, 300)

总结一下:
这里页面就直接通过$store.state.home.hotPlace拿到搜索查询接口top的数据,然后input中的逻辑就是要完成输入进行时拿到输入框的字段进行接口的请求,拿到对应查询的数据,这里涉及的是搜索功能,所以要使用一个延迟节流函数插件库lodash中使用debounce完成这部分的逻辑,注意要截取掉city所带的’市’字段,不然请求不到的哦~

同样写推荐图文数据的接口search.js

router.get('/resultsByKeywords', async(ctx)=>{
	const {city,keyword} = ctx.query;
	let {status,data:{count,pois}} = await aixos.get('http://cp-tools.cn/search/resultsByKeyword?sign',{
	params:{
		city,
		keyword
	}		
  })
  ctx.body = {
	count: status === 200 ? count : 0,
	pois: status === 200 ? pois: []
  }
})

小提示:凡是本地服务请求线上数据库的都可以进行postman测试接口

测试完接口后,我们就可以把数据实现在页面中啦,找到对应推荐部分的代码artistic.vue

1、巧用数据源event:进行页面便签元素的获取!
2、前端自己定个字段用于展示自己的页面,如果后端改字段了就直接修改请求接口return中的值即可!

鼠标经过标签时,必须等待请求数据下来并且展示在页面是才展示

  methods: {
    over: async function(e) {
      let dom = e.target;
      let tag = dom.tagName.toLowerCase();
      let self = this;
      if (tag === "dd") {
        this.kind = dom.getAttribute("kind");
        let keyword = dom.getAttribute("keyword");
        let {
          status,
          data: { count, pois }
        } = await self.$axios.get("/search/resultsByKeywords", {
          params: {
            keyword,
            city: self.$store.state.geo.position.city
          }
        });
        if (status === 200 && count > 0) {
          let r = pois
            .filter(item => item.photos.length)
            .map(item => {
              return {
                title: item.name,
                pos: item.type.split(";")[0],
                price: item.biz_ext.cost || "暂无",
                img: item.photos[0].url,
                url: "//abc.com"
              };
            });
          self.list[self.kind] = r.slice(0, 9);
        } else {
          self.list[self.kind] = [];
        }
      }
    }
  }

解决一个BUG实现:加载页面是通过async-await的异步配合mounted加载推荐图文部分的用户体验,不然会出现页面加载完了,推荐的图文还没有展示出来

async mounted() {
    let self = this;
    let {
      status,
      data: { count, pois }
    } = await self.$axios.get("/search/resultsByKeywords", {
      params: {
        keyword: "景点",
        city: self.$store.state.geo.position.city
      }
    });
    if (status === 200 && count > 0) {
      let r = pois
        .filter(item => item.photos.length)
        .map(item => {
          return {
            title: item.name,
            pos: item.type.split(";")[0],
            price: item.biz_ext.cost || "暂无",
            img: item.photos[0].url,
            url: "//abc.com"
          };
        });
      self.list[self.kind] = r.slice(0, 9);
    } else {
      self.list[self.kind] = [];
    }
  }

❤ 项目源码 ❤
GitHub地址:https://github.com/Umbrella001/mtapp

发布了134 篇原创文章 · 获赞 80 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Umbrella_Um/article/details/99892269