子组件(字母A/B/C)
Alphabet.vue
<template>
<ul class="list">
<!-- <li class="item"
v-for="(item,key) of cities"
:key="key"
@click="handleLetterClick"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
>{{key}}</li> -->
<li class="item"
v-for="item of letters"
:key="item"
:ref="item"
@click="handleLetterClick"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
>{{item}}</li>
</ul>
</template>
<script>
// 引入better-scroll插件
import Bscroll from ‘better-scroll‘
export default{
name:‘CityAlphabet‘,
props:{
cities:Object
},
// 计算属性
computed:{
// 先定义一个数组。letters=[‘A‘,‘B‘,‘C‘]
letters(){
const letters = []
for(let i in this.cities){
letters.push(i)
}
return letters
// [‘A‘,‘B‘,‘C‘]
}
},
data(){
return {
touchStart:false
}
},
methods:{
handleLetterClick(e){
console.log(e.target.innerText); // 打印点击的字母
// 子组件传值给父组件。向外触发事件。父组件监听。
this.$emit(‘change‘,e.target.innerText)
},
// 监听左边城市的滚动。
handleTouchStart (){
// 手指触摸
this.touchStart=true
},
handleTouchMove (e){
/*
1.a到顶部的高度.
2.当前滑动到哪的位置与顶部的高度。注意:要减去header的高度.
3.算出两个值之间的差值。除以每个字母的高度。算出当前是第几个字母。
4.获取到字母,触发自定义事件。传值给父级,父级再传值给兄弟组件。
*/
const startY = this.$refs[‘A‘][0].offsetTop; // 1.a到顶部的高度
// console.log(startY);
const touchY = e.touches[0].clientY - 79; // 2.当前滑动到哪的位置与顶部的高度。注意:要减去header的高度.
// console.log(touchY);
const index = Math.floor((touchY - startY)/20); // 3.算出两个值之间的差值。除以每个字母的高度。算出当前是第几个字母。
// console.log(index);
if(index >= 0 && index < this.letters.length){
this.$emit(‘change‘, this.letters[index]);
}
},
handleTouchEnd (){
// 结束滑动
this.touchStatus = false;
}
}
}
</script>
<style lang="stylus" scoped>
@import ‘~styles/varibles.styl‘
.list
display:flex
flex-direction:column
justify-content:center
position:absolute
top:1.58rem
right:0
bottom:0
width:.4rem
.item
line-height:.4rem
text-align:center
color:$bgColor
</style>
父组件
City.vue
<template>
<div>
<city-header></city-header>
<city-search></city-search>
<city-list
:hotCities="hotCities"
:cities="cities"
:letter="letter"
>
</city-list>
<city-alphabet
:cities="cities"
@change="handleLetterChange"
>
</city-alphabet>
</div>
</template>
<script>
// ajax工具
import axios from ‘axios‘
// 引入子组件
import CityHeader from ‘./components/Header‘
import CitySearch from ‘./components/Search‘
import CityList from ‘./components/List‘
import CityAlphabet from ‘./components/Alphabet‘
export default{
name:‘City‘,
// 组件
components:{
CityHeader,
CitySearch,
CityList,
CityAlphabet
},
data(){
return {
// 热门城市
hotCities:[],
// 城市
cities:{},
letter:‘‘
}
},
// 函数
methods:{
getCityInfo(){
axios.get(‘/api/city.json‘)
.then(this.handleGetCityInfoSucc)
},
handleGetCityInfoSucc(res){
console.log(res);
res = res.data;
if (res.ret && res.data){
const data = res.data
this.hotCities = data.hotCities
this.cities = data.cities
}
},
// 父组件监听子组件自定义事件。
handleLetterChange(letter){
console.log(‘父组件接收到了letter:‘,letter); // 父组件接收到子组件接收到的数据。
// 父组件再通过属性传递给另一个子组件。
this.letter = letter
}
},
//dom加载完成
mounted (){
this.getCityInfo()
}
}
</script>
<style lang="stylus" scopend>
</style>
兄弟组件(展示城市)
List.vue
<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 of hotCities" :key="item.id">
<div class="button">{{item.name}}</div>
</div>
</div>
</div>
<div
class="area"
v-for="(item,key) of cities"
:key="key"
:ref="key"
>
<div class="title border-topbottom">{{key}}</div>
<div class="item-list">
<div
class="item border-bottom"
v-for="innerItem of item"
:key="innerItem.id"
>{{innerItem.name}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
// 引入better-scroll插件
import Bscroll from ‘better-scroll‘
export default{
name:‘CityList‘,
props:{
hotCities:Array,
cities:Object,
letter: String
},
// dom挂载完毕之后执行.
mounted(){
// ref="wrapper" ref可以帮我们获取dom.
this.scroll = new Bscroll(this.$refs.wrapper)
},
// 侦听器
watch:{
// 监听letter的变化。
letter(){
// console.log(‘兄弟组件收到了letter:‘,this.letter)
if(this.letter){
// 点击到哪个字母,div区域就显示哪一块内容。$refs[key]
const element = this.$refs[this.letter][0]; // 注意:这是一个数组。不是一个元素。不能直接传给滚动对象。后面加一个0就好了。
console.log(element);
this.scroll.scrollToElement(element); // 传的参数必须是dom元素。
}
}
}
}
</script>
<style lang="stylus" scoped>
.border-topbottom
&:before
border-color:#ccc
&:after
border-color:#ccc
.border-bottom
&:before
border-color:#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
padding-left:.2rem
</style>
原文:https://www.cnblogs.com/c-x-m/p/10047014.html