欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue实现城市列表选择功能

程序员文章站 2022-06-08 22:22:16
成果展示 最后的成果就是下面所展示的内容,因为gif图没有做,只能截图所展示,接下来,会带着大家一步一步的完成下面功能,脚手架搭建和node安装在本次案例不会讲解,如果了...

成果展示

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

vue实现城市列表选择功能vue实现城市列表选择功能vue实现城市列表选择功能

准备工作:

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

功能分析

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

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

3.实现搜索城市

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

vue实现城市列表选择功能

创建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>

vue实现城市列表选择功能

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

<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"></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实现城市列表选择功能,希望对大家有所帮助