vue实现城市列表选择功能
程序员文章站
2022-06-08 22:22:16
成果展示
最后的成果就是下面所展示的内容,因为gif图没有做,只能截图所展示,接下来,会带着大家一步一步的完成下面功能,脚手架搭建和node安装在本次案例不会讲解,如果了...
成果展示
最后的成果就是下面所展示的内容,因为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实现城市列表选择功能,希望对大家有所帮助