接下来我们对城市列表页面进行优化,除了对数据优化,也会进行节流处理
//srcpagescitycomponentsAlphabet.vue
<template>
<ul class="list">
<li class="item"
v-for="item of letters"
@click="handleLetterClick"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
:key="item"
:ref="item"
>{{item}}</li>
<!-- <li class="item">B</li>
<li class="item">C</li>
<li class="item">D</li>
<li class="item">E</li>
<li class="item">F</li>
<li class="item">G</li> -->
</ul>
</template>
<script>
import { clearTimeout, setTimeout } from 'timers'
export default {
name: 'CityAlphabet',
props: {
cities: Object
},
computed: {
letters () {
const letters = []
for (let i in this.cities) {
letters.push(i)
}
return letters
}
},
data () {
return {
touchStatus: false,
startY: 0,
timer: null
}
},
updated () {
this.startY = this.$refs['A'][0].offsetTop
},
methods: {
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
// console.log('e.target.innerText', e.target.innerText)
},
handleTouchStart () {
this.touchStatus = true
},
handleTouchMove (e) {
if (this.touchStatus) {
// const startY = this.$refs['A'][0].offsetTop
// console.log(startY)
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])
}
console.log(touchY)
}, 16)
}
},
handleTouchEnd () {
this.touchStatus = false
}
}
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.list
display:flex
flex-direction:column
justify-content:center
top:1.58rem
right:0
bottom:0
.4rem
position:absolute
.item
text-align:center
line-height:.4rem
text-align:center
color:$bgColor
</style>
接下来我们来进行搜索列表的实现
<template>
<div>
<div class="search">
<input type="text"
v-model="keyword"
class="search-input"
placeholder="请输入城市名或拼音">
</div>
<div class="search-content"
ref="search"
v-show="keyword"
>
<ul>
<li
:key="item.id"
v-for="item of list"
class="search-item border-bottom">
{{item.name}}
</li>
<li
class="search-item border-bottom"
v-show="!list.length"
>
没有找到匹配数据
</li>
</ul>
</div>
</div>
</template>
<script>
import { clearTimeout, setTimeout } from 'timers'
// 解决搜索框内容不能滚动
import Bscroll from 'better-scroll'
export default {
name: 'CitySearch',
props: {
cities: Object
},
data () {
return {
keyword: '',
list: [],
timer: null
}
},
computed: {
hasNoData () {
return !this.list.length
}
},
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)
}
},
mounted () {
this.scroll = new Bscroll(this.$refs.search)
}
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.search
height:.72rem
background:$bgColor
padding:0 .1rem
.search-input
box-sizing:border-box
height:.62rem
100%
line-height:.62rem
text-align:center
border-radius:.06rem
color:#666
.search-content
z-index:1
overflow:hidden
position:absolute
top:1.58rem
left:0
right:0
bottom:0
background:#eee
.search-item
line-height:.62rem
padding-left:.2rem
background:#fff
color:#666
</style>
我们看下效果
接下来我们使用vuex进行城市定位选择,也就是城市选择页面的数据要传递给首页,也就是City组件中的数据要传递给home组件中
安装vuex
cnpm install vuex --save
先看下实现的效果
代码如下
<template>
<div class="list" ref="wrapper">
<div>
<div class="area">
<div class="title border-topbottom">
当前城市
</div>
<div class="button-list">
<div class="button-wrapper">
<div class="button">{{this.$store.state.city}}</div>
</div>
</div>
</div>
<div class="area">
<div class="title border-topbottom">
热门城市
</div>
<div class="button-list">
<div
class="button-wrapper"
v-for="item of hot"
:key="item.id"
@click="handleCityClick(item.name)"
>
<div class="button">{{item.name}}</div>
</div>
<!-- <div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div> -->
</div>
</div>
<div class="area"
v-for="(item,key) of cities"
:key="key"
:ref="key"
>
<div class="title border-topbottom">
{{key}}
</div>
<div class="item-list">
<div class="item border-bottom"
v-for="innerItem of item"
:key="innerItem.id"
@click="handleCityClick(innerItem.name)"
>
{{innerItem.name}}
</div>
<!-- <div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div> -->
</div>
</div>
<!-- <div class="area">
<div class="title border-topbottom">
B
</div>
<div class="item-list">
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
</div>
</div> -->
<!-- <div class="area">
<div class="title border-topbottom">
C
</div>
<div class="item-list">
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
</div>
</div> -->
</div>
</div>
</template>
<script>
import Bscroll from 'better-scroll'
export default {
name: 'CityList',
props: {
hot: Array,
cities: Object,
letter: String
},
methods: {
handleCityClick (city) {
// this.$store.dispatch('changeCity', city)
this.$store.commit('changeCity', city)
this.$router.push('/')
// alert(city)
}
},
watch: {
letter () {
// console.log('this.letter', this.letter)
if (this.letter) {
const element = this.$refs[this.letter][0]
console.log('element', element)
this.scroll.scrollToElement(element)
}
}
},
mounted () {
this.scroll = new Bscroll(this.$refs.wrapper)
}
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.border-topbottom
&:before
border-color:#ccc
&:after
border-color:#ccc
.list
overflow:hidden
position:absolute
top:1.58rem
left:0
right:0
bottom:0
.title
line-height:.54rem
background:#eee
padding-left:.2rem
color:#666
font-size:.26rem
.button-list
padding:.1rem .6rem .1rem .1rem
overflow:hidden
.button-wrapper
33.33%
float:left
.button
margin:.1rem
text-align:center
border:.02rem solid #ccc
border-radius:.06rem
padding:.1rem 0
.item-list
.item
line-height:.76rem
color:#666
padding-left:.2rem
</style>
接下来我们使用localstorage存储数据,使刷新的时候,也能记住我们选择的城市,另外代码还做了隐身模式或者浏览器不能保存数据的处理
//index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let defaultCity = '上海'
try {
if (localStorage.city) {
defaultCity = localStorage.city
}
} catch (e) {
}
export default new Vuex.Store({
state: {
// city: localStorage.city || '上海'
city: defaultCity
},
// actions: {
// changeCity (ctx, city) {
// ctx.commit('changeCity', city)
// }
// },
mutations: {
changeCity (state, city) {
state.city = city
try {
localStorage.city = city
} catch (e) {
}
// localStorage.city = city
}
}
})
接下来我们来拆分index.js文件,将store中的内容按照state,mutation等进行处理
//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.city = city
} catch (e) {
}
// localStorage.city = city
}
}
//index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex)
// let defaultCity = '上海'
// try {
// if (localStorage.city) {
// defaultCity = localStorage.city
// }
// } catch (e) {
// }
export default new Vuex.Store({
state,
// actions: {
// changeCity (ctx, city) {
// ctx.commit('changeCity', city)
// }
// },
mutations
})
//header.vue
<template>
<div class="header">
<div class="header-left">
<div class="iconfont back-icon"></div>
</div>
<div class="header-input">
<span class="iconfont"></span>
输入城市/游玩主题</div>
<router-link to="/city">
<div class="header-right">
{{this.city}}
<span class="iconfont arrow-icon"></span>
</div>
</router-link>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
// 1rem = html font-size=50px
name: 'HomeHeader',
computed: {
...mapState(
[
'city'
]
)
},
props: {
// city: String
}
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.header
line-height:$headerHeight
background:$bgColor
color:#fff
display:flex
.header-left
0.64rem
float:left
.back-icon
text-align:center
font-size:0.4rem
.header-input
margin-top: 0.12rem;
line-height: 0.64rem;
-webkit-box-flex: 1;
-ms-flex: 1;
margin-bottom: 0.12rem;
flex: 1;
background: #fff;
padding-left: 0.1rem;
border-radius: 0.1rem;
color: #ccc;
.header-right
min-1.04rem
padding:0 .1rem
float:right
text-align:center
color:#fff
.arrow-icon
margin-left:-.04rem
font-size:.24rem
</style>
//list.vue
<template>
<div class="list" ref="wrapper">
<div>
<div class="area">
<div class="title border-topbottom">
当前城市
</div>
<div class="button-list">
<div class="button-wrapper">
<div class="button">{{this.currentCity}}</div>
</div>
</div>
</div>
<div class="area">
<div class="title border-topbottom">
热门城市
</div>
<div class="button-list">
<div
class="button-wrapper"
v-for="item of hot"
:key="item.id"
@click="handleCityClick(item.name)"
>
<div class="button">{{item.name}}</div>
</div>
<!-- <div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div>
<div class="button-wrapper">
<div class="button">北京</div>
</div> -->
</div>
</div>
<div class="area"
v-for="(item,key) of cities"
:key="key"
:ref="key"
>
<div class="title border-topbottom">
{{key}}
</div>
<div class="item-list">
<div class="item border-bottom"
v-for="innerItem of item"
:key="innerItem.id"
@click="handleCityClick(innerItem.name)"
>
{{innerItem.name}}
</div>
<!-- <div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div> -->
</div>
</div>
<!-- <div class="area">
<div class="title border-topbottom">
B
</div>
<div class="item-list">
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
</div>
</div> -->
<!-- <div class="area">
<div class="title border-topbottom">
C
</div>
<div class="item-list">
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
<div class="item border-bottom">阿拉尔</div>
</div>
</div> -->
</div>
</div>
</template>
<script>
import Bscroll from 'better-scroll'
import {mapState, mapMutations} from 'vuex'
export default {
name: 'CityList',
props: {
hot: Array,
cities: Object,
letter: String
},
computed: {
...mapState({
currentCity: 'city'
})
},
methods: {
handleCityClick (city) {
// this.$store.dispatch('changeCity', city)
// this.$store.commit('changeCity', city)
this.changeCity(city)
this.$router.push('/')
// alert(city)
},
...mapMutations(['changeCity'])
},
watch: {
letter () {
// console.log('this.letter', this.letter)
if (this.letter) {
const element = this.$refs[this.letter][0]
console.log('element', element)
this.scroll.scrollToElement(element)
}
}
},
mounted () {
this.scroll = new Bscroll(this.$refs.wrapper)
}
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.border-topbottom
&:before
border-color:#ccc
&:after
border-color:#ccc
.list
overflow:hidden
position:absolute
top:1.58rem
left:0
right:0
bottom:0
.title
line-height:.54rem
background:#eee
padding-left:.2rem
color:#666
font-size:.26rem
.button-list
padding:.1rem .6rem .1rem .1rem
overflow:hidden
.button-wrapper
33.33%
float:left
.button
margin:.1rem
text-align:center
border:.02rem solid #ccc
border-radius:.06rem
padding:.1rem 0
.item-list
.item
line-height:.76rem
color:#666
padding-left:.2rem
</style>
接下来我们使用keep-alive优化网页性能
路由发生改变,请求就会进行多次
keep-alive进行缓存
//app.vue 请求之后就放内存中 从内存中取数据,不用再去请求
<template>
<div id="app">
<!-- 当前路由地址所对应的内容 -->
<keep-alive>
<!-- 缓存 -->
<router-view/>
</keep-alive>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
使用keep-alive的时候,我们会增加生命周期函数activated
//Home.vue
<template>
<div>
<home-header ></home-header>
<home-swiper :list="swiperList"></home-swiper>
<home-icons :list="iconList"></home-icons>
<home-recommend :list="recommendList"></home-recommend>
<home-weekend :list="weekendList"></home-weekend>
</div>
</template>
<script>
import HomeHeader from './components/Header'
import HomeSwiper from './components/Swiper'
import HomeIcons from './components/Icons'
import HomeRecommend from './components/Recommend'
import HomeWeekend from './components/Weekend'
import {mapState} from 'vuex'
import axios from 'axios'
export default {
name: 'Home',
components: {
HomeHeader,
HomeSwiper,
HomeIcons,
HomeRecommend,
HomeWeekend
},
computed: {
...mapState(['city'])
},
data () {
return {
swiperList: [],
iconList: [],
recommendList: [],
weekendList: [],
lastCity: null
}
},
methods: {
getHomeInfo () {
axios.get('/api/index.json?city=' + this.city)
.then(this.getHomeInfoSucc)
},
getHomeInfoSucc (res) {
res = res.data
if (res.ret && res.data) {
const data = res.data
this.swiperList = data.swiperList
this.iconList = data.iconList
this.recommendList = data.recommendList
this.weekendList = data.weekendList
}
}
},
mounted () {
this.lastCity = this.city
this.getHomeInfo()
},
activated () {
// 页面重新显示再执行
if (this.lastCity !== this.city) {
this.lastCity = this.city
this.getHomeInfo()
}
}
}
</script>
<style>
</style>