仿美团pc,koa+ssr(四)
一,城市服务功能
components-->新建changeCity目录--》新建isselect.vue组件
<template> <div class="m-iselect"> <span class="name">按省份选择:</span> <el-select v-model="pvalue" placeholder="省份"> <el-option v-for="item in province" :key="item.value" :label="item.label" :value="item.value"/> </el-select> <el-select v-model="cvalue" :disabled="!city.length" placeholder="城市"> <el-option v-for="item in city" :key="item.value" :label="item.label" :value="item.value"/> </el-select> <el-autocomplete v-model="input" :fetch-suggestions="querySearchAsync" placeholder="请输入城市中文或拼音" @select="handleSelect" /> </div> </template> <script> import _ from 'lodash'; export default { data(){ return { province:[], pvalue:'', city:[], cvalue:'', input:'', // 全国城市 cities:[] } }, watch:{ // 省份数据改变,立刻获取对应的市级数据 pvalue:async function(newPvalue){ let self=this; let {status,data:{city}}=await self.$axios.get(`/geo/province/${newPvalue}`) if(status===200){ self.city=city.map(item=>{ return { value:item.id, label:item.name } }) self.cvalue='' } } }, // 刚加载页面,把所有的省份数据获取 mounted:async function(){ let self=this; let {status,data:{province}}=await self.$axios.get('/geo/province') if(status===200){ self.province=province.map(item=>{ return { value:item.id, label:item.name } }) } }, methods:{ // 远端搜索,只要输入关键字,触发该函数,防抖优化,query为输入的关键字 querySearchAsync:_.debounce(async function(query,cb){ let self=this; if(self.cities.length){ // cb回调函数,搜索符合条件的城市 cb(self.cities.filter(item => item.value.indexOf(query)>-1)) }else{ // 没有全国城市数据,请求接口获取 let {status,data:{city}}=await self.$axios.get('/geo/city') if(status===200){ self.cities=city.map(item=>{return { value:item.name }}) cb(self.cities.filter(item => item.value.indexOf(query)>-1)) }else{ cb([]) } } },200), // 选中城市触发 handleSelect:function(item){ console.log(item.value); } } } </script> <style lang="scss"> @import "@/assets/css/changeCity/iselect.scss"; </style>
components-->新建changeCity目录--》新建hot.vue热门城市组件
<template> <div class="m-hcity"> <dl> <dt>热门城市:</dt> <dd v-for="item in list" :key="item.id">{{ item.name==='市辖区'?item.province:item.name }}</dd> </dl> </div> </template> <script> export default { data(){ return { list:[] } }, async mounted(){ let {status,data:{hots}}=await this.$axios.get('/geo/hotCity') if(status===200){ this.list=hots } } } </script> <style lang="scss"> @import "@/assets/css/changeCity/hot.scss"; </style>
components-->新建changeCity目录--》新建categrory.vue排序城市组件
注,用很少的dom节点完成,多看看,
还有用了一个pinyin库,拼音code值
根据a标签的瞄点,跳转到固定位置
<template> <div class=""> <dl class="m-categroy"> <dt>按拼音首字母选择:</dt> <dd v-for="item in list" :key="item"> <a :href="'#city-'+item">{{ item }}</a> </dd> </dl> <dl v-for="item in block" :key="item.title" class="m-categroy-section"> <dt :id="'city-'+item.title">{{ item.title }}</dt> <dd> <span v-for="c in item.city" :key="c">{{ c }}</span> </dd> </dl> </div> </template> <script> import pyjs from 'js-pinyin' export default { data(){ return { list:'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), // 每个对象包含拼音以及对应的数组 block:[] } }, async mounted(){ let self=this; let blocks=[] let {status,data:{city}}=await self.$axios.get('/geo/city'); if(status===200){ let p let c let d={} city.forEach(item=>{ // 将汉语转化拼音,并截取首字母 p=pyjs.getFullChars(item.name).toLocaleLowerCase().slice(0,1) // 获取字母的code值 c=p.charCodeAt(0) // 小写a-z if(c>96&&c<123){ if(!d[p]){ d[p]=[] } // 每个拼音对应的数组 d[p].push(item.name) } }) // Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组 for(let [k,v] of Object.entries(d)){ blocks.push({ title:k.toUpperCase(), city:v }) } // 字母排序 blocks.sort((a,b)=>a.title.charCodeAt(0)-b.title.charCodeAt(0)) self.block=blocks } } } </script> <style lang="scss"> @import "@/assets/css/changeCity/categroy.scss"; </style>
pages-->changeCity.vue组件,将hot,isselsect,categrory组件全部导入该组件
默认引入了公共组件layout-->default.vue,<nuxt/>相当于一个slot插槽,将changeCity的结构插入进去
<template> <el-container class="layout-default"> <el-header height="197px"> <my-header/> </el-header> <el-main> <nuxt/> </el-main> <el-footer height="100%"> <my-footer/> </el-footer> </el-container> </template> <script> import MyHeader from '@/components/public/header/index.vue' import MyFooter from '@/components/public/footer/index.vue' export default { components:{ MyHeader, MyFooter } } </script>
<template> <div class="page-changeCity"> <el-row> <el-col :span="24"> <iSelect/> </el-col> </el-row> <el-row> <el-col :span="24"> <hot/> </el-col> </el-row> <el-row> <el-col :span="24"> <categroy/> </el-col> </el-row> </div> </template> <script> import iSelect from '@/components/changeCity/iselect.vue' import Hot from '@/components/changeCity/hot.vue' import Categroy from '@/components/changeCity/categroy.vue' export default { components:{ iSelect, Hot, Categroy } } </script> <style lang="css"> </style>