页面包括三个部分,当前城市,热门城市和城市滚动栏。城市的信息都是通过axios请求json文件再渲染的。滚动部分和字母表部分用到了一个插件,这部分也是我感觉最困难的地方。
1.axios请求数据
跟之前一样,在city.vue里发送总请求,得到的数据可以传给子组件,避免了每个组件都要发送请求,减少请求数量。
mounted
钩子在挂载好后自动调用函数getCityInfo()
,成功后调用函数handleGetCityInfoSucc
,函数接收res
参数,一开始我还不太明白这段代码意思,后来在控制台输出了一下res就明白了。
getCityInfo(){
axios.get('/api/city.json')
.then(this.handleGetCityInfoSucc)
},
handleGetCityInfoSucc(res){
res=res.data
if(res.ret && res.data){
const data=res.data
this.cities=data.cities
this.hotCities=data.hotCities
}
},
看一下控制台中res输出:
首先
res=res.data
将res指向res.data部分,此时的res包括data、ret和--proto--三部分,如果res.ret==true并且res.data不为空,将data指向res中的data部分。同样获取到data中的cities和hotCities部分。
2.父子组件数据传递
给子组件绑定属性,子组件通过props接收 ,懂自懂,不多说=。=
有一个地方需要注意 Cities是对象 hotCities是数组,在列表渲染的时候,对于数组可以(item,index)这样取属性,对于对象需要(item,key)取属性,key代表“A、B、C...”等地区首字母,对象啊 是以键值对存储的
<div class="area"
v-for="(item,key) of cities"
:key="key" :ref="key">
<div class="title border-top-bottom">{{key}}</div>
......
3. 组件数据传递——字母列表部分【难点-逻辑比较绕】
3.1 点击字母列表中字母,列表滚动到相应位置
先搞清楚,Alphabet.vue和 List.vue是兄弟组件关系,都属于City.vue的子组件。
要完成点击字母表,列表跟着滚动的功能,需要组件之间通信。
在父组件City中定义的数据有cities hotCities和letter,前两个数据都通过axios获取到了,而letter在这里定义,通过Alphabet接收,传给List使用。
data(){
return {
cities:{},
hotCities:[],
letter:''
}
},
Alphabet组件给字母表中每个字母都绑定了一个点击事件@click="handleLetterClick"
。当点击li,通过$emit向外发送该字母到父组件,实现子组件向父组件传递数据。
handleLetterClick(e){
this.$emit('change',e.target.innerText)
},
父组件通过 @change="handleLetterChange">
事件接收,在函数里接收到点击的字母,赋值给letter
handleLetterChange(letter){
this.letter=letter
}
父组件得到letter后,传给List,List里定义一个watch函数,随时监听letter的变化,当letter非空时,使用better-scroll将列表滚动到相应的位置
letter() {
// 如果字符非空,会自动滚到字符开头的位置
if(this.letter){
// better-scroll参数需要使用dom
const element=this.$refs[this.letter][0] //dom形式
this.scroll.scrollToElement(element)
}
}
刚开始觉得有点复杂,但是多想几遍流程就想清楚了
3.2 滑动字母列表中字母,列表滚动到相应位置
在Alphabet组件中绑定几个函数 ,在move中先计算A到顶部的距离,再计算手指点到顶部距离,相减得到与A的相对距离,除以每个li的高度,得到index,发送letters[index]到change事件。
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick">
handleTouchMove(e){
// 当状态等于true时才对执行move事件
if(this.touchStatus){
const startY=this.$refs["A"][0].offsetTop //dom元素
const touchY= e.touches[0].clientY-80
const index=Math.floor((touchY-startY)/20)
if(index >= 0 && index < this.letters.length){
this.$emit("change",this.letters[index])
}
}
3.3 offsetTop和ClientY区别 以及其他滚动代码的常用属性
【坑 等填】