概述
城市页面开发中的重难点
- 使用router-link实现页面的跳转
- 使用Better-scroll第三方包实现拖动
- 使用axios实现页面数据的动态渲染
- 实现点击字母表某个字母,跳转到相应字母的城市列表项(兄弟组件间联动)
- 实现拖拽字母表时,城市列表项跟着滚动
- 使用updated生命钩子存储startY的值
- 使用函数节流,限制move方法的频率
- 城市搜索功能的实现
- 使用Vuex实现城市列表页面与首页的数据共享,并且实现点击热门城市/城市列表/搜索城市列表事,相应的当前城市以及首页城市发生改变
- 使用Vue Router中的编程式导航,导航到不同的URL
- 使用LocalStorage实现本地存储
- 对Vuex代码进行优化,并使用其提供的API
- 使用keep-alive优化网页性能
使用router-link实现页面的跳转
<router-link to='/city'>
//点击后跳转的控件
</router-link>
注意:加了这个组件之后,需要重新设置字体颜色,因为组件中包含一个链接,链接本身设置了字体颜色。
使用Better-scroll第三方包实现拖动
- 首先,GitHub上搜索相关资源:better-scroll,了解相关内容。
- 安装better-scroll:
npm install better-scroll --save
- 引入better-scroll:
import Bscroll from 'better-scroll'
- 使用vue中的ref属性来获取DOM元素。
在List.vue中,总组件需要有一个div包裹住其他的组件,并且在这个div上加上ref属性:
<div class="list" ref="wrapper">
- 使用mounted()函数,在页面DOM挂载完毕的时候,创建better-scroll实例属性,并将wrapper传进去:
mounted () {
this.scroll = new Bscroll(this.$refs.wrapper, {click: true})
}
注意:在使用better-scroll时,会使click事件失效
原因:better-scroll 默认会阻止浏览器的原生 click 事件。
因此,需要我们在创建实例属性时,将click属性设置为true。
使用axios实现页面数据的动态渲染
通过axios来动态获取数据,做法与前一部分的首页开发一样,不再赘述。
实现点击字母表某个字母,跳转到相应字母的城市列表项(兄弟组件间联动)
- 首先,要实现兄弟组件间的传值,则可以采取以下方法:
(1)首先,将Alphabet.vue的letter值传递给父组件City.vue;
(2)接着,父组件接收子组件Alphabet.vue传递过来的值,并将该值传递给子组件List.vue - 在Alphabet.vue中,绑定click事件函数,在事件函数中,使用$e
在这里插入代码片
mit()函数触发父组件自定义事件,并将letter值传过去:
(1)div上:@click="handleLetterClick"
(2)事件函数:
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
},
- 父组件City.vue中,在data中定义letter属性,并设值为空,在change事件所绑定的函数中,接收letter值,并设置为自定义的letter值,最后将自定义的letter值传递给子组件List.vue:
(1)change事件绑定函数:
<city-alphabet :cities='cities' @change="handleLetterChange"></city-alphabet>
(2)data中定义letter值:
data () {
return {
letter: ''
}
},
(3)事件函数:
handleLetterChange (letter) {
this.letter = letter
}
(4)将自定义的letter值传递给子组件List.vue:
<city-list :hot='hotCities' :cities='cities' :letter="letter"></city-list>
- 子组件List.vue中,接收父组件传来的letter值,借助监听器,当letter值改变时,调用better-scroll提供的接口:scrollToElement():让better-scroll自动滚到某个元素上。
(1)在props接收父组件的值:
props: {
letter: String
},
(2)借助监听器,监听letter值的改变:只要letter发生变化,就会执行该函数。
首先,在列表区域通过ref属性获取相应字母列表DOM元素:
<div class="area" v-for="(item,key) of cities" :key="key" :ref="key">
接着,在watch监听器中,获取当前字母的城市列表,调用better-scroll提供的接口:scrollToElement():让better-scroll自动滚到字母对应的城市列表上:
watch: {
letter () {
if (this.letter) {
const element = this.$refs[this.letter][0]
this.scroll.scrollToElement(element)
}
}
},
实现拖拽字母表时,城市列表项跟着滚动
- 首先,在Alphabet.vue组件中循环元素在Alphabet组件中循环元素绑定3个事件然后在计算属性中定义一个letters,用它来把cityes这个对象转换成数组,所以letters是26个字母组成的一个数组,ref绑定item,使$refs成为26个DOM对象的数组:
<li class="item" v-for="item of letters" :key="item" :ref="item" @touchstart="handleTouchStart" @touchmove.prevent="handleTouchMove" @touchend="handleTouchEnd" @click="handleLetterClick">
- 在data中定义一个状态标识touchStatus,当开始按住时touchStatus=true,结束按住时=false;
在Move事件中求出A元素到绿色框的距离,还有手指按住时某元素到绿色框的距离,然后就可以取得手指滑动时字母的下标index,index等于两者相减后除以字母高度的值,然后向外发出一个change事件,携带这个字母就可以了。三个事件的代码如下:
handleTouchStart () {
this.touchStatus = true
},
handleTouchMove (e) {
if (this.touchStatus) {
if (this.timer) {
clearTimeout(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.letters.length) {
this.$emit('change', this.letters[index])
}
}, 10)
}
},
handleTouchEnd () {
this.touchStatus = false
}
使用updated生命钩子存储startY的值
- 首先在data中定义
startY: 0
- 接着,在updated()中,获取到字母A里绿色框的距离:
updated () {
this.startY = this.$refs['A'][0].offsetTop
},
页面刚加载时,cities为空对象。当通过ajax获取数据后,组件重新渲染,updated被执行,startY获取到数据
使用函数节流,限制move方法的频率
- 首先,在data中定义
timer=null
- 在handleTouchMove ()方法中,当timer不为空时,清除timer;若为空,则定义定时器:
handleTouchMove (e) {
if (this.touchStatus) {
if (this.timer) {
clearTimeout(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.letters.length) {
this.$emit('change', this.letters[index])
}
}, 10)
}
},
城市搜索功能的实现
- 首先,使用
v-model
实现搜索框与keyword双向绑定 - 在监听器watch中监听keyword的改变,首先在监听中使用节流函数;接着在城市数据中,根据keyword搜索数据项中的spell和name,若出现对应项,则添加至result数组中,最后将数组的值赋给list;并且当keyword不存在时,将list设为空。
watch: {
keyword () {
if (this.timer) {
clearTimeout(this.timer)
}
if (!this.keyword) {
this.list = []
return
}
this.timer = setTimeout(() => {
const result = []
for (let i in this.cities) {
this.cities[i].forEach((value) => {
if (value.spell.indexOf(this.keyword) > -1 || value.name.indexOf(this.keyword) > -1) {
result.push(value)
}
})
}
this.list = result
}, 100)
}
},
- 解决搜索得到的城市列表无法拖动的问题,使用better-scroll,引入并在mounted中创建实例属性。
- 使用
v-show
来决定搜索得到的城市列表以及“没有找到匹配数据”提示是否出现。
注意:应该尽量少地在模板中使用逻辑,将逻辑部分放至逻辑块中。因此使用了计算属性来计算list数组长度是否为空。
<div class="search-content" ref="search" v-show="keyword">
<li class="search-item border-bottom" v-show="hasNoData">
没有找到匹配数据
</li>
计算属性:
computed: {
hasNoData () {
return !this.list.length
}
},
使用Vuex实现城市列表页面与首页的数据共享,并且实现点击热门城市/城市列表/搜索城市列表事,相应的当前城市以及首页城市发生改变
- 查看Vue官网的文档,了解Vuex的使用:Vuex
- 安装Vuex:
npm install vuex --save
- 在src目录下,创建store文件夹,再创建index.js,在该文件中,引入并使用Vuex,在state定义页面共享数据city,mutations中更改该共享数据city。
- main.js中引入store:
import store from './store'
- 由于Store是定义在根组件vue中的,所以所有子组件可以直接使用,因此页面通过
this.$store.state.city
调用共享数据 - 城市列表以及搜索城市列表添加点击绑定事件,当城市变化时,改变对应的共享数据。
使用Vue Router中的编程式导航,导航到不同的URL
当选择好城市后,希望实现跳转到首页的功能,这一实现接住了Vue Router的push方法来实现。
在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this. $router.push。
在绑定的点击事件中,添加以下代码,实现点击后跳转到首页的功能:
this.$router.push('/')this.$router.push('/')
使用LocalStorage实现本地存储
使用H5提供的LocalStorage,存储当前城市,下次刷新页面时,仍然显示选择的城市。
localStorage.city = city
对Vuex代码进行优化,并使用其提供的API
- 将vuex代码进行拆分成state.js、mutations.js来使用,代码维护性得到提升。
拆分后的代码如下:
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex)
// 导出vuex创建的仓库
export default new Vuex.Store({
// state用来存储公用的数据
state,
mutations
})
state.js:
let defaultCity = '北京'
try {
if (localStorage.city) {
defaultCity = localStorage.city
}
} catch (e) {}
export default {
city: defaultCity
}
mutations.js:
export default {
changeCity (state, city) {
state.city = city
try {
// 使用localStorage本地存储数据
localStorage.city = city
} catch (e) {}
}
}
- 使用Vuex提供的API:mapState、mapMutations,引入并使用的代码如下:
引入:
import { mapState, mapMutations } from 'vuex'
使用:
computed: {
...mapState({
currentCity: 'city'
})
},
methods: {
handleCityClick (city) {
this.changeCity(city)
// 跳转到首页
this.$router.push('/')
},
...mapMutations(['changeCity'])
},
使用keep-alive优化网页性能
- 当前页面存在一个问题:每次路由切换,总会发送一次ajax请求(每次切换,页面总会重新渲染,mounted钩子重新执行,ajax数据就会重新获取)。
为了优化网页的性能,使用keep-alive:实现路由加载一次过后,会将加载内容放入内存之中。下一次进去,不需要重新渲染这个组件,mounted()函数也不再执行(即不再发送ajax请求),只需要从内存将内容取出显示
<keep-alive exclude="Detail">
<router-view/>
</keep-alive>
- 在使用keep-alive之后,重新刷新页面时,mounted()函数都不会再次执行,导致如果改变城市后,首页其他数据没有相应的重新获取以及改变。
因此,要使用activated()生命钩子,查看城市是否有变化,若变化,则重新发送ajax请求。
activated () {
if (this.lastCity !== this.city) {
this.lastCity = this.city
this.getHomeInfo()
}
}
最后
以上就是疯狂大白为你收集整理的【Vue项目】三、去哪儿网APP——城市列表页面开发的全部内容,希望文章能够帮你解决【Vue项目】三、去哪儿网APP——城市列表页面开发所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复