视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
vue实现城市列表选择功能
2020-11-27 22:11:26 责编:小采
文档


成果展示

最后的成果就是下面所展示的内容,因为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: .rem
 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实现城市列表选择功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

下载本文
显示全文
专题