在上篇中,我们通过Vuex 中保存的数据,完成了组件间的数据传递。通过Vuex 中的states 保存 当前城市。但这样会有一个问题,当刷新的时候,这个值,还是会回到代码中赋的初值。
本篇解决这个问题。解决这个问题,要使用localStorage。
localStorage 是html5 提供的API,它可以实现类似cookie 的功能,实现本地存储。
改起来也非常简单,只需要改store 目录下的 index.js 文件即可。如下。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
city: localStorage.city || '上海'
},
actions: {
changeCity (ctx, city) {
ctx.commit('changeCity', city)
}
},
mutations: {
changeCity (state, city) {
state.city = city
localStorage.city = city
}
}
})
【建议】在使用localStorage 时,使用try catch 包裹它。因为在用户关闭了本地存储或者使用隐身模式时,使用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: defaultCity
},
actions: {
changeCity (ctx, city) {
ctx.commit('changeCity', city)
}
},
mutations: {
changeCity (state, city) {
state.city = city
try {
localStorage.city = city
} catch (e) {}
}
}
})
上文的代码,看起来有点儿复杂。实际在项目中,会进行拆分。
一个index.js 拆分成了同一目录下的:index.js, actions.js, mutation.js, state.js。
actions.js 代码
export default {
changeCity (ctx, city) {
ctx.commit('changeCity', city)
}
}
mutation.js 代码
export default {
changeCity (state, city) {
state.city = city
try {
localStorage.city = city
} catch (e) {}
}
}
state.js 代码
let defaultCity = '北京'
try {
if (localStorage.city) {
defaultCity = localStorage.city
}
} catch (e) {}
export default {
city: defaultCity
}
index.js 代码
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
Vue.use(Vuex)
export default new Vuex.Store({
state: state,
actions: actions,
mutations: mutations
})
好啦。
下面,稍微优化一个Vuex 的一个使用。使用vuex state 中的数据,可以不用那么麻烦写 this.$store.state.city
Header.vue 代码。mapState 函数,会将vuex state 中的数据,映射到computed 中的数据,数据的名字叫 ‘city’
<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 {
name: 'HomeHeader',
computed: {
...mapState(['city'])
}
}
</script>
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-wraper">
<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-wraper"
v-for="item of hot"
:key="item.id"
@click="handleCityClick(item.name)"
>
<div class="button">{{item.name}}</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>
</div>
</div>
</div>
</template>
<script>
import {mapState, mapActions} from 'vuex'
import Bscroll from 'better-scroll'
export default {
name: 'CityList',
props: {
cities: Object,
hot: Array,
letter: String
},
computed: {
...mapState({
currentCity: 'city'
})
},
methods: {
handleCityClick (city) {
this.changeCity(city)
this.$router.push('/')
},
...mapActions(['changeCity'])
},
mounted () {
this.scroll = new Bscroll(this.$refs.wrapper)
},
watch: {
letter () {
if (this.letter) {
const element = this.$refs[this.letter][0]
this.scroll.scrollToElement(element)
}
}
}
}
</script>
Done!
提交合并吧!