vue实现城市列表选择功能

成果展示

最后的成果就是下面所展示的内容,因为gif图没有做,只能截图所展示,接下来,会带着大家一步一步的完成下面功能,脚手架搭建和node安装在本次案例不会讲解,如果了解,可以在我的博客园找到有详细介绍

准备工作:

 引入axios插件,调用better-scroll第三方插件,本地json文件,可以参考目录中的city.json,有条件的也可以自己去扒

功能分析

1.获取json数据展示城市列表 。

2.侧边字母定位滚动到相应的位置。

3.实现搜索城市

接下来我们开始对组件进行划分:本次案例中,总共划分为五个组件,下面就是组件的划分图

创建city组件,通过父组件获取数据,传递给子组件

<template>

<div class="city">

<CityHeader></CityHeader> //头部

<Search :list="cities"></Search> //搜索

<List :hot="hotCity" :letter="letter" :list="cities"></List> //城市列表

<Alphabet @chang="handleLetterChang" :list="cities"></Alphabet> //A-Z

</div>

</template>

<script>

import axios from 'axios'

import CityHeader from './components/Header'

import Search from './components/Search'

import List from './components/List'

import Alphabet from './components/Alphabet'

export default {

data () {

return {

cities:{}, // 城市列表

hotCity:[], //热门城市

letter: '' // A-Z

}

},

components: {

CityHeader,

Search,

List,

Alphabet

},

methods:{

getCityInfo () {

axios.get('/api/city.json').then(this.getCityInfoSucc)

},

getCityInfoSucc(res){

res = res.data

if (res.ret && res.data) {

const data = res.data

this.hotCity = data.hotCities

this.cities = data.cities

}

console.log(this.cities)

},

handleLetterChang(letter) { //接受子组件传过来的

// console.log(letter)

this.letter = letter

}

},

mounted () {

this.getCityInfo ()

}

}

</script>

<style scoped lang="stylus">

</style>

把得到的数据分次传递个对应的子组件,这样有利于网站优化,不用频繁的请数据

<template>

<div class="city">

<CityHeader></CityHeader>

<Search :list="cities"></Search>

<List :hot="hotCity" :letter="letter" :list="cities"></List>

<Alphabet @chang="handleLetterChang" :list="cities"></Alphabet>

</div>

</template>

export default {

data () {

return {

cities:{}, // 城市列表

hotCity:[], //热门城市

letter: '' // A-Z

}

},

components: {

CityHeader,

Search,

List,

Alphabet

},

methods:{

getCityInfo () {

axios.get('/api/city.json').then(this.getCityInfoSucc) //请求本地配置的mock数据

},

getCityInfoSucc(res){

res = res.data

if (res.ret && res.data) {

const data = res.data

this.hotCity = data.hotCities

this.cities = data.cities

}

}

},

mounted () {

this.getCityInfo ()

}

}

创建头部组件,

<template>

<div class="header">

城市选择

<router-link to="/">

<div class="iconfont back-icon">&#xe624;</div>

</router-link>

</div>

</template>

<script>

export default {

}

</script>

<style scoped lang="stylus">

@import '~styles/varibles.styl';

@import '~styles/mixins.styl';

.header

overflow: hidden

height $headerHeight

line-height: $headerHeight

text-align: center

color: #fff

background: $bgColor

font-size: .4rem

.back-icon

position: absolute

left: 0

top: 0

width: .64rem

font-size: .4rem

text-align: center

color: #fff

</style>

创建搜索组件页面,接受父组件传递的数据,引入better-scroll第三方插件,实现列表滚动

<template>

<div>

<div class="search">

<input v-model="keyword" class="search-input" type="text" placeholder="输入城市名或者拼音" />

</div>

<div class="search-content" ref="search" v-show="keyword">

<ul>

<li class="serach-item border-bottom" v-for="item in listItem" :key="item.id">{{item.name}}</li>

<li v-show="hasNoData" class="serach-item border-bottom">没有搜索到匹配的数据</li>

</ul>

</div>

</div>

</template>

<script>

import BScroll from 'better-scroll'

export default {

props: {

list: Object,

},

data() {

return {

keyword:'',

listItem:[],

timer:null

}

},

computed: {

hasNoData() {

return !this.listItem.length //没有搜索的条件是否显示

}

},

watch: {

keyword () {

if (this.timer) {

clearTimeout(this.timer)

}

if(!this.keyword) { //清空

this.listItem = ""

return

}

this.timer = setTimeout(() => {

const result = []

for (let i in this.list) {

this.list[i].forEach((value) => { //匹配搜索的条件

if (value.spell.indexOf(this.keyword) > -1 || value.name.indexOf(this.keyword) > -1) {

result.push(value)

}

})

}

this.listItem= result

},100)

}

},

mounted () {

this.scroll = new BScroll(this.$refs.search)

}

}

</script>

<style scoped lang="stylus">

@import '~styles/varibles.styl'

@import '~styles/mixins.styl'

.search

height: .72rem

padding: 0 .1rem

background:$bgColor

.search-input

box-sizing: border-box

width:100%

height: .62rem

line-height: .62rem

text-align: center

border-radius: .06rem

padding: 0 .1rem

color: #666

.search-content

z-index: 1

overflow:hidden

position:absolute

top: 1.58rem

left: 0

right: 0

bottom: 0

background: #eee

.serach-item

line-height: .62rem

padding-left:.2rem

color:#666

background: #fff

</style>

创建城市列表组件,引入better-scroll插件,实现列表滚动,通过watch监听letter,实现字母与城市列表滚动

<template>

<div class="list" ref="wrapper">

<div>

<div class="area">

<div class="title border-topbottom">当前城市</div>

<div class="button-list">

<div class="button-wrapper">

<div class="button">郑州</div>

</div>

</div>

</div>

<div class="area">

<div class="title border-topbottom">热门城市</div>

<div class="button-list">

<div class="button-wrapper" v-for="item in hot" :key="item.id">

<div class="button">{{item.name}}</div>

</div>

</div>

</div>

<div class="area"

v-for="(item,key) in list"

:ref="key"

:key="key">

<div class="title border-topbottom">{{key}}</div>

<ul class="item-list">

<li class="item border-bottom"

v-for="listInner in item"

:key="listInner.id"

>{{listInner.name}}</li>

</ul>

</div>

</div>

</div>

</template>

<script>

import BScroll from 'better-scroll'

export default {

props: {

hot: Array,

list: Object,

letter:String

},

mounted () {

this.scroll = new BScroll(this.$refs.wrapper)

},

watch:{

letter () { //监听列表滚动事件 A-Z

if(this.letter) {

const element = this.$refs[this.letter][0]

this.scroll.scrollToElement(element)

}

}

}

}

</script>

<style scoped lang="stylus">

@import '~styles/varibles.styl';

@import '~styles/mixins.styl';

.border-topbottom

&:before

background: #ccc

&:after

background:#ccc

.border-bottom

&:before

background: #ccc

.list

overflow: hidden

position:absolute

top:1.58rem

left:0

right:0

bottom:0

.title

line-height: .54rem;

background: #eee;

padding-left: .2rem;

color: #666;

font-size: .26rem;

.button-list

overflow:hidden

padding: .1rem .6rem .1rem .1rem

.button-wrapper

float:left

width:33.33%

.button

margin: .1rem

padding: .1rem 0

text-align: center

border: .02rem solid #ccc

border-radius: .06rem

.item-list

.item

line-height: .76rem

color:#212121

padding-left: .2rem

font-size: .28rem

text-overflow: ellipsis

white-space: nowrap

</style>

创建字母组件,点击字母,左边列表城市想对应,通过this.$emit事件,子组件在触发的事件传递给父组件,父组件通过子组件传递的事件,在传递给List组件,

<template>

<div class="list">

<li class="item"

:ref="item"

@click="handeClick"

@touchstart="handleTouchStart"

@touchmove="handleTouchMove"

@touchend= "handleTouchEnd"

v-for="item of letter"

:key="item">{{item}}</li>

</div>

</template>

<script>

export default {

props: {

list: Object

},

data () {

return {

touchstart:false,

startY:0,

timer: null

}

},

updated () {

this.startY = this.$refs['A'][0].offsetTop

},

computed: {

letter () {

const letter =[]

for (let i in this.list) { //循环A-Z

letter.push(i)

}

return letter

}

},

methods: {

handeClick(e) {

this.$emit('chang',e.target.innerText) //传给父组件City

},

handleTouchStart () {

// 手指放上

this.touchstart = true

},

handleTouchMove (e) {

// 手指移动

if(this.touchstart) {

if(this.timer) {

clearInterval(this.timer)

}

this.timer = setTimeout(() => {

const touchY = e.touches[0].clientY -79 //到蓝色头部的距离

const index = Math.floor((touchY - this.startY ) / 20)

if(index >=0 && index < this.letter.length) {

this.$emit('chang',this.letter[index])

}

},16)

}

},

handleTouchEnd () {

// 手指离开

this.touchstart = false

}

}

}

</script>

<style scoped lang="stylus">

@import '~styles/varibles.styl';

@import '~styles/mixins.styl';

.list

display: flex

flex-direction:column

justify-content: center

position:absolute

top: 1.58rem

right: 0

bottom: 0

width: .4rem

.item

line-height:.44rem

text-align: center

color: $bgColor

list-style:none

</style>

总结

以上所述是小编给大家介绍的vue实现城市列表选择功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

以上是 vue实现城市列表选择功能 的全部内容, 来源链接: utcz.com/z/352064.html

回到顶部