仿美团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>
原文地址:https://www.cnblogs.com/fsg6/p/14429303.html