美团项目 --- 切换城市 7

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

切换城市

1.1 实现图

在这里插入图片描述

1.2 组件化结构,使用多组件页进行合并拼凑

在这里插入图片描述

1.3 省市二级联动如何做?

在这里插入图片描述
在这里插入图片描述
依靠E-UI完成界面后,我们开始写逻辑交互

最后完成的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>
    <span class="name">&nbsp;&nbsp;&nbsp;&nbsp;中文搜索:</span>
    <el-autocomplete
      v-model="input"
      :fetch-suggestions="querySearchAsync"
      placeholder="请输入城市中文或拼音"
      @select="handleSelect"
    ></el-autocomplete>
  </div>

首先明确一载入切换城市界面,哪个是要进行请求的,那就是省份(第一级),此时可以使用ssr进行服务端渲染,页面载入后也跟着进行载入,但这里就直接使用vue中的Mouted生命函数完成这里的axios请求 ↓

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
        };
      });
    }
  }

这样一来就完成了一级的就绪,然后二级市区的选择在没有选择省份时是不会触发的,所以可以使用E-UI中的disable进行禁选;

好了我们开始做联动逻辑,使用watch监听用户选择了什么省份 ↓

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 = "";
      }
    }
  }

这种数据(由用户决定的数据),就需要使用watch监听,只要写在里面的函数发生了改变就会执行,而这里恰恰可以用v-model绑定的值作为监听的值,当用户选择省份时就会异步请求接口,注意这里传入的值跟监听的pvalue是一样的,根据mounted的请求可以知道pvalue就是对应省级的id,你可能会问,那我v-model绑定的是输入框的值,明显这里的请求参数不是中文地名呀,注意了这里就是select下拉框的设计,如果你不设置label显示的还是value的值,但是如果你设置了label那输入框显示的就是label的值,但是你v-model拿的还是你value的值,所以在省份中复制也是将id赋值给value的,所以参数正确!
会二级联动,三级联动还会难吗?毕竟现在你只需要重点思考逻辑上的代码,而DOM结构E-UI已经随随便便完成了,只剩下你关联他们的代码而已

1.4 如何利用Element-UI完成项目中的远程搜索?

分析:
凡是涉及地区的项目,肯定都是有远程搜索之说,一旦提到用户搜索务必都使用延迟节流处理,一般实时搜索的节流处理,目前就我知道可以使用lodash里的延迟函数debounce

远程搜索参数解析:
首先来解释一下E-UI中的远程搜索的DOM属性,只有你了解他上面的函数节点属性的意思你才能去写逻辑,首先v-model="input"绑定的是谁,不就是输入框咯;`querySearchAsync`当用户输入后触发,这里就可以写请求参数的接口;handleSelect选中时触发

重要点点讲:
① 延迟函数就是异步,反正异步函数就给我写返回值,所以参数很明确,必须有返回值(这里一参为搜索项,二参为回调也就是返回值)

② 凡是数组中还带条件筛选的就给我写filter就完事了,还有filter不写成es6的都是耍流氓!

③ 如果数组中不带条件筛选的还需要遍历的,map+箭头函数 了解一下

④ 关于根据用户中文或者英文搜索都可以搜索对应的数据出来(升级可拼音)

methods: {
    querySearchAsync: _.debounce(async function(query, callback) {
      let self = this;
      if (self.cities.length) {
        callback(self.cities.filter(item => item.value.indexOf(query) > -1 || item.charValue.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,
              charValue: pyjs.getFullChars(item.name).toLocaleLowerCase()
            };
          });
          callback(self.cities.filter(item => item.value.indexOf(query) > -1 || item.charValue.indexOf(query) > -1));
        } else {
          callback([]);
        }
      }
    }, 200),

关于展示热门城市的那栏逻辑和DOM结构都很简单,简述复习一下:

首先说一下这种结构的DOM结构只需要几个DOM节点就完成:
dl>dd+dt

  <div class="m-hcity">
    <dl>
      <dd>热门城市:</dd>
      <dt 
        v-for="item in list" 
        :key="item.id"
      >{{item.name === '市辖区'? item.province: item.name}}</dt>
    </dl>
  </div>

其次就是逻辑,既然使用nuxt就好好利用async和await配合请求接口:
这里强调两点:
① async mounted(){ } 和 mounted: async function(){ } 是一样的

② 用了那么多次解构赋值版的请求接口,你应该知道state{}花括号了是什么了把,看下面的图,如果还不知道翻翻之前的请求~!
在这里插入图片描述

1.5 城市根据首字母分类

重点:关于将城市按拼音首字母分类 ,两种一种就是后端给个标识给你帮你分类(一般不多,靠后端还不如靠自己),第二种就是前端怎么自己去做(重点学习!!!)

重要的几点 :

① 使用第三方插件库,目前唯一最方便的做法 npm install js-pinyin,在需要使用该插件的地方导入即可 import pyjs from 'js-pinyin'

② 关于循环26个字母你会怎么做?数组中一个一个写吗,首先DOM结构中使用循环肯定是必须的,这是就是如何设计你的循环的数组 ↓ 整个字符串写好A-Z然后用split分割成数组

    <div>
   		 <!-- 字母导航栏 -->
        <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-catagroy-section">
            <dt :id="'city-' + item.title">{{item.title}}</dt>
            <dd>
                <span
                  v-for="c in item.city"
                  :key="c"
                >
                {{ c }}
                </span>
            </dd>
        </dl>
    </div>
 data(){
        return{
            list:'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
        }
    }

③ 如何结合js-pinyin插件库拿到中文数据的全拼

插件库中就有一个方法为getFullChars,它接受的参数就是中文数据,返回值就是该中文数据对应的全拼
PS:注意getFullChars拿到的是一种如(北京:BeiJing)的首字母大写,所以可以根据需求全转大写或小写,亦可以通过Ascll值配合split拿到首字母大写,总之根据需求去写逻辑即可

pyjs.getFullChars(item.name).toLocaleLowerCase().slice(0,1);

④ 如何将对应的城市放进对应的字母数组中?

只需要这样一段if判断就完事了,怎么实现?

首先简单的做一下a-z小写字母的Ascrll码值的判断(怎么来的? 通过string.charCodeAt(0)拿到了首个字符的ASCLL值)

然后通过判断cityCharAll对象中是否有该键名 → 如果没有则在空对象中创建储存一个键值对 | OR | 如果有则直接push进去已有的数组

这里就巧在对象中存储的是带有名字的键值对,然后让同一个开头字母的城市Push进对应的字母数组中!完美

if(cityAscll >= 97 && cityAscll <= 124){
     if(!cityCharAll[cityChar]){
         cityCharAll[cityChar] = []
     }
     cityCharAll[cityChar].push(item.name)
 }

在这里插入图片描述
⑤ 通过上面的对号入座,但却还没有排序,如何排列成a-z呢?

为什么突然这样写,这是根据DOM结构去设计的数组,反正页面的元素要循环的,一律放进数组中去给他们循环

 for(let [key,value] of Object.entries(cityCharAll)){
     blocks.push({
         title: key.toUpperCase(),
         city: value
     })
 }

结果如下:
在这里插入图片描述
排序:

 blocks.sort((x,y) => x.title.charCodeAt(0) - y.title.charCodeAt(0));
 self.block = blocks;

直接通过ASCLL码来拍就行,sort()自动会从小到大进行升序排列

Vue中的跳转(根据字母的跳转):

之前用scroll高度去做,其实不必用JS完成,直接使用DOM就可以

加个#锚点就行!还不清楚就去看上面的DOM。这里因为涉及动态数据,所以要加上v-bind:href='xxx' ```→```→```→```→```→```:id='xxx'

<a href="#city-A">A</a>

<div id="city-A">A字母</div>

这样点击字母A就可以跳转到对应的A开头的城市列表

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

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

猜你喜欢

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