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"></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实现城市列表选择功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 基于 Vue 的树形选择组件的示例代码

    本文介绍了基于 Vue 的树形选择组件.分享给大家,具体如下: 系统要求:Vue 2 基本特性 完美的多级联动效果 支持无限多的分级 有 全选.半选.不选 三种状态  截图展示 代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="icon" href="https://v1-c

  • vue与bootstrap实现时间选择器的示例代码

    一.下载bootstrap-datetimepicker时间选择器js,css文件. 1. github地址:bootstrap-datetimepicker 2. 官方网站地址:官网bootstrap-datetimepicker地址,有具体的例子与解释 二.在vue项目文件中引入 import './assets/css/bootstrap.min.css' import "./assets/css/bootstrap-datetimepicker.min.css" import

  • Vue实现选择城市功能

    查看完整的代码请到   我的github地址  https://github.com/qianyinghuanmie/vue2.0-demos 一.结果展示 二.前期准备: 1.引入汉字转拼音的插件,利用NPM安装 代码指令为 npm install pinyin --save ,详细步骤请到pinyin 2.引入vue-resource,调用json文件,可以参考目录中的city.json,有条件的也可以自己去扒 三. 分析 所实现的功能点: 1.获取json数据展示城市列表 . 2.侧边字母

  • 基于vue2.0实现的级联选择器

    基于Vue的级联选择器,可以单项,二级, 三级级联,多级级联 web开发中我们经常会遇到级联选择器的问题,尤其是在表单中,无外乎几种情况: 单个级联 (下拉选择框,单选) 单个级联 (多项选择) 二级联动 (省份和城市联动) 三级联动 (省市区联动) 在jquery中有很多好用的插件,比如select2, 单选,多选的功能都具备. 本文探讨一下在vue中的实现级联选择器,自己在项目中碰到过以下两种情况的后端数据,查阅资料后也证实了这两种数据的合理性: 预览地址 github地址 1 后端处理数

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

    成果展示 最后的成果就是下面所展示的内容,因为gif图没有做,只能截图所展示,接下来,会带着大家一步一步的完成下面功能,脚手架搭建和node安装在本次案例不会讲解,如果了解,可以在我的博客园找到有详细介绍 准备工作: 引入axios插件,调用better-scroll第三方插件,本地json文件,可以参考目录中的city.json,有条件的也可以自己去扒 功能分析 1.获取json数据展示城市列表 . 2.侧边字母定位滚动到相应的位置. 3.实现搜索城市 接下来我们开始对组件进行划分:本次案例中

  • JS基于VUE组件实现城市列表效果

    本文实例为大家分享了基于VUE组件实现城市列表效果的具体代码,供大家参考,具体内容如下 基本思想是,将城市列表数据缓存在本地 然后在页面上用JS实现即时模糊查询和首字母定位查询等 为了保护项目,删除了部分代码 效果 实现 H5: <template> <div id="city"> <div class="search-city-back"> <div class="search-city"> &l

  • 浅谈vue的iview列表table render函数设置DOM属性值的方法

    如下所示: { title: '负责人社保照片', key: 'leaderIdNumber', render: (h, params) => { return h('img',{domProps:{ src:params.row.leaderIdNumber }}) } }, 找了好多,终于找到了原因,如果想要让列表返回的是一个img标签,并且设置img的src,这里不能用props,而是要用domProps就ok了. 以上这篇浅谈vue的iview列表table render函数设置DOM属

  • react native带索引的城市列表组件的实例代码

    城市列表选择是很多app共有的功能,比如典型的美图app.那么对于React Native怎么实现呢? 要实现上面的效果,首先需要对界面的组成简单分析,界面的数据主要由当前城市,历史访问城市和热门城市组成,所以我们在提供Json数据的时候就需要将数据分为至少3部分. const ALL_CITY_LIST = DATA_JSON.allCityList; const HOT_CITY_LIST = DATA_JSON.hotCityList; const LAST_VISIT_CITY_LIST

  • JS实现移动端按首字母检索城市列表附源码下载

    我们常见的手机通讯录或微信通讯录,联系人信息是按字母顺序排列的列表,通过点击右侧的字母,会迅速定位检索到首字母对应的联系人.那么我今天给大家介绍的是按首字母快速定位到城市列表,效果和通讯录一样的.  查看演示 下载源码 准备 查看演示     下载源码 准备 首先我们需要用到全国的城市数据,这些城市数据来源于网络,我已经将数据格式化成JSON形式了,大家可以直接拿去用. 我们还需要用到一个叫better-scroll的滚动插件,它能帮我们将超长的页面原生的滚动条处理掉,优化滚动效果. 接着我们准

  • Android实现简单的城市列表功能

    本文实例为大家分享了Android城市列表简单用法,供大家参考,具体内容如下 步骤: 1. 在app的gradle里面添加依赖: com.github.andyoom:citypicker:v1.0.4 2.在项目的build.gradle中添加 maven {url "https://jitpack.io"} 开始写代码: xml布局: <?xml version="1.0" encoding="utf-8"?> <Linea

  • JS实现带导航城市列表以及输入搜索功能

    本文实例为大家分享了JS实现带导航城市列表以及输入搜索功能展示的具体代码,供大家参考,具体内容如下 实现功能: 1.加载城市列表,并生成索引(没有该索引的城市则无索引) 2.点击索引滚动页面到对应索引城市第一个位置 3.输入搜索 分析: 1.加载城市很容易,生成对应的索引. 首先需要得到所有的城市,然后拿出城市的首字母,放入一个数组中,去重并排序, 得到无重复并有序的索引数组后加入到div中显示 2.根据索引进行页面滚动 需要给索引列表添加事件,由于锚点会在链接产生带#号的地址,以及页面会有刷动

  • Vue.js实现列表清单的操作方法

    一.Vue.js简要说明 Vue.js (读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架.与前端框架Angular一样, Vue.js在设计上采用MVVM模式,当View视图层发生变化时,会自动更新到ViewModel.反之亦然,View与ViewModel之间通过数据双向绑定(data-binding)建立联系,如下图所示 Vue.js通过MVVM模式将视图与数据分成两部分(或者说视图代码与业务逻辑的解耦),因此我们只需关心数据的操作,DOM的视图的更新等一系列事情,V

  • 微信小程序实现城市列表选择

    本文实例为大家分享了小程序实现城市列表选择的具体代码,供大家参考,具体内容如下 实现效果预览   实现功能简介 城市的选择 按中文/拼音/首字母条件搜索 按首字字母快速定位到城市位置 目录结构 主要代码 app.js App({ globalData: { trainBeginCity: '杭州', trainEndCity: '北京' } }) app.json { "pages":[ "pages/index/index", "pages/citys/

  • vue实现动态列表点击各行换色的方法

    只是模拟一练习 v-for v-on v-bind的一个简单demo 代码思路: 遍历出data里面的数据 v-for 给li加点击事件 绑定class样式 怎么控制样式的显示 通过 class的控制 v:bind:class={class:index==变量} 下标和class变量是否相等控制true false 代码: <div id="app"> <ul> <li v-for='(item,index) in arr' v-bind:class='{

随机推荐