vue | 基于vue的城市选择器和搜索城市对应的小区

vue

城市选择器应该是比较常用的一个组件,用户可以去选择自己的城市,选择城市后返回,又根据自己选择的城市搜索小区。

功能展示

 这是选择结果

这是选择城市

这是搜索小区

这是搜索小区接口,key为城市名字,id是城市的id

假如切换城市

搜索接口也会相应变化,id=0997 就是指定的搜索城市id

技术栈

 vue2.0+vue-router+webpack+vuex+less+better-scroll+axios

webpack

resolve: {

extensions: [\'.js\', \'.vue\', \'.json\'],

alias: {

\'vue$\': \'vue/dist/vue.esm.js\',

\'src\': resolve(\'src\'),

\'common\' : resolve(\'src/common\'),

\'components\': resolve(\'src/components\'),

\'base\': resolve(\'src/base\'),

"api":resolve(\'src/api\')

}

},

用less需要引入less和less-loader,但是不需要在webpack操作,webpack已经操作好了

技术栈介绍

所有城市是本地维护的,在city.js中

1、axios封装

import {ajaxUrl} from "./config"

import axios from \'axios\'

export function getSearchData(key,id){

var obj = {

op:"search",

key,

id

}

return axios.get(ajaxUrl.searcUrl,{

params: obj

}).then((res)=>{

return Promise.resolve(res.data);

}).catch((err)=>{

return Promise.resolve(err);

})

}

2、axios调用,因为目前没有接口,所以只是模拟演示接口,但不影响逻辑

import {getSearchData} from "api/search"

_getDiscList(key,id){

this.searchList=["八方城","西溪北苑北区","西溪北苑西区","西溪北苑东区","万科城","恒大城","西溪科技园","未来科技城","智慧城","春天家园","茶张新苑","双水磨小区","小区1","小区2","小区3","小区4","小区5","小区6","小区7"];

getSearchData(key,id).then((res)=>{

},(err)=>{})

},

3、vuex状态管理,vuex我就不介绍了,具体可以去看官网

4、主要介绍一下state中变量的含义

import {initial} from "common/js/config"

const state = {

selectCity:initial.city,

selectCommunity:initial.community,

hasSelCityID:-1

}

export default state

5、config.js

export const initial = {

city:"杭州",

community:"八方城"

}

selectCity是选择的城市

selectCommunity是选择的小区

hasSelCityID是选择城市的id,根据此id选择对应小区

6、better-scroll

better-scroll 是之前封装好的一个页面滚动组件

7、vue-router

8、页面滑动对应title也变化原理

首先需要记住变量scrollY,这是记录页面滚动到哪个title

data(){

return{

city:[],

scrollY: -1,

currentIndex:0,

diff:-1,

}

},

初始化的时候初始化这三个变量,probetype=3是better-scroll可支持touchmove事件的参数

created(){

this.touch = {};

this.listenScroll = true;

this.listenHeight = [];

this.probetype = 3;

},

时刻计算高度,并检测页面滚动到哪个位置

watch:{

city(){

setTimeout(()=>{

this._calculateHeight()

},20)

},

scrollY(newY){

// 滚动到中间部分

const listenHeight = this.listenHeight;

// 滚动到头部以上

if (newY>=-25) {

this.currentIndex = 0;

return;

}

for(let i=0;i<listenHeight.length-1;i++){

let height1 = listenHeight[i];

let height2 = listenHeight[i+1];

// 如果没在下限,且在height1和height2之间

if (-newY>=height1 && -newY<=height2) {

this.currentIndex = i;

this.diff = height2 + newY;

return;

}

}

},

diff(newVal){

let fixedTop = (newVal>0 && newVal<TITLE_HEIGHT)?newVal-TITLE_HEIGHT:0;

if (this.fixedTop === fixedTop) {

return

}

this.fixedTop = fixedTop;

this.$refs.fixed.style.transform = `translate3d(0,${fixedTop}px,0)`

}

}

_calculateHeight(){

this.listenHeight = [];

const list = this.$refs.listGroup;

let height = 0;

this.listenHeight.push(height);

for(let i =0;i<list.length;i++){

let item = list[i];

height +=item.clientHeight;

this.listenHeight.push(height);

}

},

滚动指定位置

    _scrollTo(index){

if (!index && index!=0) {

return

}

// 点击右边字母跳到指定位置并高亮

this.scrollY = -this.listenHeight[index]-1;

this.$refs.cityList.scrollToElement(this.$refs.listGroup[index],0);

},

改变标题

fixedTitle(){

if (this.scrollY>0) {

return ""

}

return this.city[this.currentIndex]?this.city[this.currentIndex].initial:""

}

点击字右边索引跳转指定位置

onShortcutTouchStart(e){

let anchorIndex = getData(e.target,\'index\');

console.log(anchorIndex);

let firstTouch = e.touches[0];

this.touch.y1 = firstTouch.pageY;

this.touch.anchorIndex = anchorIndex;

// this.$refs.singerlist.scrollToElement(this.$refs.listGroup[anchorIndex],0);

this._scrollTo(anchorIndex)

},

9、搜索组件

搜索输入框是一个组件,组件负责监听input的model变化,只要变化就派发事件,引用该组件的组件,只需要监听派发的事件即可

created(){

this.$watch(\'query\',(newQuery)=>{

this.$emit(\'query\',newQuery)

})

}

11、城市搜索,支持首字母(不区分大小写)搜索

首先给城市加首字母

_addFirstLetter(citylist){

for(var i=0;i<citylist.length;i++){

for(var j=0;j<citylist[i].list.length;j++){

citylist[i].list[j][\'firstLetter\'] = citylist[i].initial;

}

}

this._formatCityList(citylist);

},

序列化数组

// 序列化数组

_formatCityList(arr){

var letterArr = {};

for (var i = 0; i < arr.length; i++) {

if (!(arr[i][\'initial\'] in letterArr)) {

letterArr[arr[i][\'initial\']] = [];

for(var j=0;j<arr[i].list.length;j++){

letterArr[arr[i][\'initial\']].push(arr[i].list[j]);

}

}else{

for(var j=0;j<arr[i].list.length;j++){

letterArr[arr[i][\'initial\']].push(arr[i].list[j]);

}

}

}

this.letterList = letterArr;

},

搜索

正则 var reg = new RegExp(newVal == \'\' ? \'xxyy\' :newVal, \'ig\');   ig是不区分大小写

// 搜索

_search(newVal){

var reg = new RegExp(newVal == \'\' ? \'xxyy\' :newVal, \'ig\');

var _arr = [];

for(var i in this.letterList){

for(var j = 0; j < this.letterList[i].length; j++){

if(

reg.test(this.letterList[i][j][

\'name\'

]) ||

reg.test(this.letterList[i][j][

\'firstLetter\'

])

){

_arr.push(this.letterList[i][j]);

}

}

}

this.searchList = _arr;

},

因为引入的搜索框组件,所以只需要监听input内容改变后派发的事件即可

 this._search(newVal);

this.queryCity = newVal;

data 搜索结果会放在searchList里面,只需要v-for即可,但是需要边缘处理,没有搜索结果,有一个UI上的一个展示

data(){

return{

city:[],

letterList:[],

searchList: [], //搜索结果

queryCity:"",

placeholder:"输入城市名称"

}

},

 10、每次点击搜索城市后触发mutation,修改state

selectItem(item){

this.afterSelect(item)

},

selectSearchItem(item){

this.afterSelect(item)

},

// 选择之后的操作

afterSelect(item){

this.$router.back();

this.setCity(item.name);

this.setCityId(item.zip);

},

...mapMutations({

setCity:"SET_CITY",

setCityId:"SET_CITYID"

})

推荐使用vuex钩子,具体如何使用可去看官网

import {mapMutations} from "vuex"

import {mapGetters} from "vuex"

业务功能模板

 1、select.vue

<template lang="html">

<!-- <transition name="slide"> -->

<div>

<div @click="city" class="city clearfix">

<i>所在城市</i>

<em></em>

<span>{{selCity}}</span>

</div>

<div @click="community" class="community clearfix">

<i>小区名称</i>

<em></em>

<span>{{selCommunity}}</span>

</div>

</div>

<!-- </transition> -->

</template>

2、city.vue

<transition name="slide">

<div class="xin-widget-citys animated">

<SearchBox class="search" @query="query" :placeholder="placeholder"></SearchBox>

<div class="currentCity" v-if="queryCity===\'\'">

<ul>

<h2>当前定位城市</h2>

<li>杭州</li>

</ul>

</div>

<Scroll :data="searchList" class="searchlist" v-if="queryCity !== \'\'" :class="{\'bg\':searchList.length === 0}">

<div>

<ul v-if="searchList.length!==0">

<li class="bdb" v-for="item in searchList" @click="selectSearchItem(item)">{{item.name}}</li>

</ul>

<img v-else src="../../common/img/404.png" class="nomatch"/>

</div>

</Scroll>

<CityList class="city" v-if="queryCity===\'\'" @selectItem="selectItem"></CityList>

</div>

</transition>

3、search.vue

<transition name="slide">

<div class="xin-widget-citys animated">

<SearchBox class="search" @query="query" :placeholder="placeholder"></SearchBox>

<Scroll :data="searchList" class="searchlist" v-if="queryCity !== \'\'" :class="{\'bg\':searchList.length === 0}">

<div>

<ul v-if="searchList.length!==0">

<li v-for="item in searchList" @click="selectSearchItem(item)">{{item}}</li>

</ul>

<img v-else src="../../common/img/404.png" class="nomatch"/>

</div>

</Scroll>

</div>

</transition>

基础组件模板

1、city-list.vue

<Scroll class="citylist" :data="city" ref="cityList" :listenScroll="listenScroll" @scroll="scroll" :probetype="probetype">

<div>

<div v-for="(item,index) in city" class="allCity" ref="listGroup">

<h2>{{item.initial}}</h2>

<ul>

<li v-for="city in item.list" @click="selectItem(city)">

{{city.name}}

</li>

</ul>

</div>

</div>

<div class="list-shortcut" @touchstart="onShortcutTouchStart">

<ul>

<li class="starCity"></li>

<li v-for="(item,index) in city" class="item" :data-index="index">

{{item.initial}}

</li>

</ul>

</div>

<div class="list-fixed" v-show="fixedTitle" ref="fixed">

<h1 class="fixed-title">{{fixedTitle}}</h1>

</div>

</Scroll>

2、search-box.vue

<template>

<div class="search-box">

<i class="icon-search"></i>

<input ref="query" class="box" :placeholder="placeholder" v-model="query"/>

</div>

</template>

总结

 以上就是城市选择器的大概介绍,源码我已经放在了我的github上了,有需要可去下载,如果有帮助,麻烦给个star,鼓励我继续努力,谢谢!

 代码地址:https://github.com/dirkhe1051931999/writeBlog

以上是 vue | 基于vue的城市选择器和搜索城市对应的小区 的全部内容, 来源链接: utcz.com/z/375979.html

回到顶部