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

城市页面开发中的重难点

    • 使用router-link实现页面的跳转
    • 使用Better-scroll第三方包实现拖动
    • 使用axios实现页面数据的动态渲染
    • 实现点击字母表某个字母,跳转到相应字母的城市列表项(兄弟组件间联动)
    • 实现拖拽字母表时,城市列表项跟着滚动
    • 使用updated生命钩子存储startY的值
    • 使用函数节流,限制move方法的频率
    • 城市搜索功能的实现
    • 使用Vuex实现城市列表页面与首页的数据共享,并且实现点击热门城市/城市列表/搜索城市列表事,相应的当前城市以及首页城市发生改变
    • 使用Vue Router中的编程式导航,导航到不同的URL
    • 使用LocalStorage实现本地存储
    • 对Vuex代码进行优化,并使用其提供的API
    • 使用keep-alive优化网页性能

使用router-link实现页面的跳转

复制代码
1
2
3
4
<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属性:
复制代码
1
2
<div class="list" ref="wrapper">
  1. 使用mounted()函数,在页面DOM挂载完毕的时候,创建better-scroll实例属性,并将wrapper传进去:
复制代码
1
2
3
4
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)事件函数:
复制代码
1
2
3
4
handleLetterClick (e) { this.$emit('change', e.target.innerText) },
  1. 父组件City.vue中,在data中定义letter属性,并设值为空,在change事件所绑定的函数中,接收letter值,并设置为自定义的letter值,最后将自定义的letter值传递给子组件List.vue:
    (1)change事件绑定函数:
复制代码
1
2
<city-alphabet :cities='cities' @change="handleLetterChange"></city-alphabet>

(2)data中定义letter值:

复制代码
1
2
3
4
5
6
data () { return { letter: '' } },

(3)事件函数:

复制代码
1
2
3
4
handleLetterChange (letter) { this.letter = letter }

(4)将自定义的letter值传递给子组件List.vue:

复制代码
1
2
<city-list :hot='hotCities' :cities='cities' :letter="letter"></city-list>
  1. 子组件List.vue中,接收父组件传来的letter值,借助监听器,当letter值改变时,调用better-scroll提供的接口:scrollToElement():让better-scroll自动滚到某个元素上。
    (1)在props接收父组件的值:
复制代码
1
2
3
4
props: { letter: String },

(2)借助监听器,监听letter值的改变:只要letter发生变化,就会执行该函数。
首先,在列表区域通过ref属性获取相应字母列表DOM元素:

复制代码
1
2
<div class="area" v-for="(item,key) of cities" :key="key" :ref="key">

接着,在watch监听器中,获取当前字母的城市列表,调用better-scroll提供的接口:scrollToElement():让better-scroll自动滚到字母对应的城市列表上:

复制代码
1
2
3
4
5
6
7
8
9
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对象的数组:
复制代码
1
2
<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事件,携带这个字母就可以了。三个事件的代码如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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里绿色框的距离:
复制代码
1
2
3
4
updated () { this.startY = this.$refs['A'][0].offsetTop },

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

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

  1. 首先,在data中定义timer=null
  2. 在handleTouchMove ()方法中,当timer不为空时,清除timer;若为空,则定义定时器:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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设为空。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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数组长度是否为空。
复制代码
1
2
<div class="search-content" ref="search" v-show="keyword">
复制代码
1
2
3
4
<li class="search-item border-bottom" v-show="hasNoData"> 没有找到匹配数据 </li>

计算属性:

复制代码
1
2
3
4
5
6
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。

在绑定的点击事件中,添加以下代码,实现点击后跳转到首页的功能:

复制代码
1
2
this.$router.push('/')this.$router.push('/')

使用LocalStorage实现本地存储

使用H5提供的LocalStorage,存储当前城市,下次刷新页面时,仍然显示选择的城市。

复制代码
1
2
localStorage.city = city

对Vuex代码进行优化,并使用其提供的API

  1. 将vuex代码进行拆分成state.js、mutations.js来使用,代码维护性得到提升。
    拆分后的代码如下:
    index.js:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
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:

复制代码
1
2
3
4
5
6
7
8
9
10
let defaultCity = '北京' try { if (localStorage.city) { defaultCity = localStorage.city } } catch (e) {} export default { city: defaultCity }

mutations.js:

复制代码
1
2
3
4
5
6
7
8
9
10
export default { changeCity (state, city) { state.city = city try { // 使用localStorage本地存储数据 localStorage.city = city } catch (e) {} } }
  1. 使用Vuex提供的API:mapState、mapMutations,引入并使用的代码如下:
    引入:
复制代码
1
2
import { mapState, mapMutations } from 'vuex'

使用:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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请求),只需要从内存将内容取出显示
复制代码
1
2
3
4
<keep-alive exclude="Detail"> <router-view/> </keep-alive>
  1. 在使用keep-alive之后,重新刷新页面时,mounted()函数都不会再次执行,导致如果改变城市后,首页其他数据没有相应的重新获取以及改变。
    因此,要使用activated()生命钩子,查看城市是否有变化,若变化,则重新发送ajax请求。
复制代码
1
2
3
4
5
6
7
activated () { if (this.lastCity !== this.city) { this.lastCity = this.city this.getHomeInfo() } }

最后

以上就是疯狂大白最近收集整理的关于【Vue项目】三、去哪儿网APP——城市列表页面开发的全部内容,更多相关【Vue项目】三、去哪儿网APP——城市列表页面开发内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部