我是靠谱客的博主 疯狂大白,最近开发中收集的这篇文章主要介绍【Vue项目】三、去哪儿网APP——城市列表页面开发,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

城市页面开发中的重难点

    • 使用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第三方包实现拖动

  1. 首先,GitHub上搜索相关资源:better-scroll,了解相关内容。
  2. 安装better-scroll:npm install better-scroll --save
  3. 引入better-scroll:import Bscroll from 'better-scroll'
  4. 使用vue中的ref属性来获取DOM元素。
    在List.vue中,总组件需要有一个div包裹住其他的组件,并且在这个div上加上ref属性:
<div class="list" ref="wrapper">
  1. 使用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. 首先,要实现兄弟组件间的传值,则可以采取以下方法:
    (1)首先,将Alphabet.vue的letter值传递给父组件City.vue;
    (2)接着,父组件接收子组件Alphabet.vue传递过来的值,并将该值传递给子组件List.vue
  2. 在Alphabet.vue中,绑定click事件函数,在事件函数中,使用$e在这里插入代码片mit()函数触发父组件自定义事件,并将letter值传过去:
    (1)div上:@click="handleLetterClick"
    (2)事件函数:
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
},
  1. 父组件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>
  1. 子组件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)
}
}
},

实现拖拽字母表时,城市列表项跟着滚动

  1. 首先,在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">
  1. 在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的值

  1. 首先在data中定义startY: 0
  2. 接着,在updated()中,获取到字母A里绿色框的距离:
updated () {
this.startY = this.$refs['A'][0].offsetTop
},

页面刚加载时,cities为空对象。当通过ajax获取数据后,组件重新渲染,updated被执行,startY获取到数据

使用函数节流,限制move方法的频率

  1. 首先,在data中定义timer=null
  2. 在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)
}
},

城市搜索功能的实现

  1. 首先,使用v-model实现搜索框与keyword双向绑定
  2. 在监听器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)
}
},
  1. 解决搜索得到的城市列表无法拖动的问题,使用better-scroll,引入并在mounted中创建实例属性。
  2. 使用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实现城市列表页面与首页的数据共享,并且实现点击热门城市/城市列表/搜索城市列表事,相应的当前城市以及首页城市发生改变

  1. 查看Vue官网的文档,了解Vuex的使用:Vuex
  2. 安装Vuex:npm install vuex --save
  3. 在src目录下,创建store文件夹,再创建index.js,在该文件中,引入并使用Vuex,在state定义页面共享数据city,mutations中更改该共享数据city。
  4. main.js中引入store:import store from './store'
  5. 由于Store是定义在根组件vue中的,所以所有子组件可以直接使用,因此页面通过this.$store.state.city调用共享数据
  6. 城市列表以及搜索城市列表添加点击绑定事件,当城市变化时,改变对应的共享数据。

使用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

  1. 将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) {}
}
}
  1. 使用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优化网页性能

  1. 当前页面存在一个问题:每次路由切换,总会发送一次ajax请求(每次切换,页面总会重新渲染,mounted钩子重新执行,ajax数据就会重新获取)。
    为了优化网页的性能,使用keep-alive:实现路由加载一次过后,会将加载内容放入内存之中。下一次进去,不需要重新渲染这个组件,mounted()函数也不再执行(即不再发送ajax请求),只需要从内存将内容取出显示
<keep-alive exclude="Detail">
<router-view/>
</keep-alive>
  1. 在使用keep-alive之后,重新刷新页面时,mounted()函数都不会再次执行,导致如果改变城市后,首页其他数据没有相应的重新获取以及改变。
    因此,要使用activated()生命钩子,查看城市是否有变化,若变化,则重新发送ajax请求。
activated () {
if (this.lastCity !== this.city) {
this.lastCity = this.city
this.getHomeInfo()
}
}

最后

以上就是疯狂大白为你收集整理的【Vue项目】三、去哪儿网APP——城市列表页面开发的全部内容,希望文章能够帮你解决【Vue项目】三、去哪儿网APP——城市列表页面开发所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部