组件结构
CityHeader
- 路由的配置
(1)使用标签做页面跳转
(2)元素外加上router-link标签,默认为将div变成了a标签,使元素颜色发生改变。<router-link to="/"> <div class="iconfont back-icon"></div> </router-link>
解决办法: css设置元素颜色
或者:<router-link tag="div" to="/" class="iconfont back-icon">  </router-link>
- js形式的页面跳转
this.$router.push(’/’)
CityList
- 使用better-scroll插件,让list区域可滚动
import Bscroll from 'better-scroll' mounted () { this.scroll = new Bscroll(this.$refs.wrapper) //通过this.$refs.wrapper获取list区域的dom结构 }
CityAlphabet
-
右侧字母指定时,左侧list会自动跳转到对应的字母:CityAlphabet和CityList之间进行兄弟组件间的数据联动(右侧导航栏导到左侧城市)
CityAlohabet的数据传到父组件City,City再将数据传到子组件CityList
List获取到letter数据后,要(用watch)监听letter的变化,当接受到的数据发生变化,那么list对应的也要变化。watch: { letter () { //console.log(this.letter) if(this.letter) { //通过ref获取dom结构,this.$refs[this.letter]获取到的是一个数组 const element = this.$refs[this.letter][0] //better-scroll提供的一个可以自动跳转到element的功能。 this.scroll.scrollToElement(element) } } }
-
右侧字母滚动,左侧list相应变化
重点在于: 右侧字母滚动的监听,将变化的letter数据传递给City.vue<script> export default { name: 'CityAlphabet', data () { return { touchStatus: false } }, props: { cities: Object }, computed: { letters () { const letters = [] for( let i in this.cities) { letters.push(i) } return letters // lettters: ['A','B','C','D'] } }, methods: { handleLetterClick (e) { // console.log(this.key)什么也没有 // console.log(e.target.innerText) this.$emit('change',e.target.innerText) }, handleTouchStart () { this.touchStatus = true }, handleTouchMove (e) { if(this.touchStatus) { const startY = this.$refs['A'][0].offsetTop const touchY = e.touches[0].clientY - 82 const index = Math.floor((touchY - startY)/20) if(index>=0 && index<=this.letters.length) { this.$emit('change',this.letters[index]) } } }, handleTouchEnd () { this.touchStatus = false } } } </script>
-
代码性能优化
(1)startY是一个固定值,原来定义在handleTouchMove函数中,每次调用这个函数都会执行,性能较低,所以将startY定义在updated钩子函数中。updated () { this.startY = this.$refs['A'][0].offsetTop } //初次渲染CityAlphabet.vue时,City.vue中cities是空对象,所以CityAlphabet.vue中什么东西都不会显示。 //当City.vue通过ajax获取到数据时,cities发生变化,当CityAlphabet.vue中传递的数据发生变化,CityAlphabet.vue会重新渲染, //重新渲染结束后,updated这个生命周期钩子会执行,这时,页面已展示右侧字母列表。
(2)函数节流
通过节流限制handleTouchMove函数执行的频率:handleTouchMove (e) { if(this.touchStatus) { if (this.timer) { clearTimeout(this.timer) } this.timer = setTimeout(() => { const touchY = e.touches[0].clientY - 82 const index = Math.floor((touchY - this.startY)/20) if(index>=0 && index<=this.letters.length) { this.$emit('change',this.letters[index]) } },16) } },
CitySearch
- 搜索逻辑
//监测keyword的变化 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) } }
Vuex
-
使用vuex实现首页和城市选择页面的数据共享(即选择完城市后首页自动更新,城市选择页面的数据传递到首页)
- City和Home不是父子关系,也不是兄弟关系,可以用bus来传递数据,但很麻烦,用vuex最好。vuex是一个数据框架。
//创建一个store导出 import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { city: '杭州' }, mutations: { changeCity (state, city) { state.city = city } }, actions: { changeCity (context, city) { context.commit('changeCity', city) } } })
//vue的实例中引入store,并添加到根实例中,使每个组件都可以使用store import store from './store/index.js' new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
(1)在组件中调用store中内容的普通方法:
组件中调用state
this.$store.state.city组件中调用actions
this.$store.dispatch(‘changeCity’,city)组件中调用mutations
this.$store.commit(‘changeCity’, city)actions调用mutations
context.commit(‘changeCity’, city)(2)如果数据或者方法较多,使用 mapState mapActions mapMutations
import { mapState } from 'vuex' computed: { ...mapState(['city']) //将this.city映射为this.$store.state.city } import {mapMutations } from 'vuex' methods: { ...mapMutations(['changeCity']) 将 `this.changeCity()` 映射为 `this.$store.commit('changeCity')` handleCityClick (city) { this.changeCity(city) } },
-
localstorage的使用
html5提供的新功能,类似于cookie,可以本地存储,api更简单。
localStorage.city = city
但是有的用户会关闭浏览器的本地存储功能,所以要加上try{}catch(e){}try { localStorage.city = city } catch(e) {}
使用keep-alive优化网页性能
没有优化的页面,每一次路由切换到某个组件时,这个组件都会重新渲染,mounted钩子函数会被重新执行,那么ajax数据会被重新获取。每次都获取这样影响性能。
keep-alive是vue的内置标签,放在路由外面。keep-alive的作用: 路由的内容被加载一次后,路由的内容就会被存储在内存中。当再次访问时,直接从内存中取出即可。
但这样逻辑不对。需要加一个逻辑:如果城市选择页面的城市发生变化,首页要重新发ajax请求。
当使用keep-alive时,组件中会多一个生命周期函数activated:当页面重新被显示时被执行。可以在页面重新显示时判断上一次的城市和当前选择的城市是否一样,如果不相同,再发一次ajax请求。
activated () {
if (this.lastCity !== this.city){
this.lastCity = this.city
this.getHomeInfo(); //如果城市选择页面选择的城市和首页中的城市不同,首页要再发一次ajax请求。
}
}
还有一种去掉kepp-alive的方法
<keep-alive exclude="Detail"> //Detail组件中去掉kepp-alive的功能
<!--显示的是当前路由地址所对应的内容。-->
<router-view/>
</keep-alive>