Vue2.5 旅游项目实例17 城市选择页-使用Vuex实现数据共享

vue

创建分支:city-vuex

拉取到本地并切换分支:

git pull

git checkout city-vuex

我们要做的功能是在城市列表页,选择某一个城市后,首页右上角的城市也跟着变化。

安装Vuex:

npm install vuex --save

在src目录下,创建store文件夹,新建index.js文件:

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({

state: {

city: '北京'

}

})

然后打开main.js文件,添加:

import Store from './store'

new Vue({

el: '#app',

router,

store,

components: { App },

template: '<App/>'

})

打开Home.vue文件,可以看到给 home-hander 组件传递了一个city,现在我们改为:

<home-header></home-header>

现在刷新首页,右上角的北京没有了,只有一个下箭头。

然后打开Header.vue文件:

<div class="header-right">{{this.$store.state.city}} <i class="iconfont arrow-icon">&#xe64a;</i></div>

<script>

export default {

name: 'HomeHeader'

}

</script>

这时首页右上角的北京又显示出来了。this.$store.state.city 取的是store里存储的默认值:北京

再打开city下的List.vue文件,把当前城市改为读取stroe:

<div class="button">{{this.$store.state.city}}</div>

这时候我们可以把store/index.js中 state.city 的默认值改为:上海

然后可以看到首页和列表也中的当前城市,都变为了上海。

下面我们希望点击热门城市,可以跟着变化,给每个热门城市添加点击事件:

<div class="button-wrapper" v-for="item in hotCity" :key="item.id"

@click="handleCityClick(item.name)">

<script>

export default {

methods: {

// 热门城市点击事件

handleCityClick (city) {

this.$store.dispatch('changeCity', city)

}

},

}

</script>

然后打开store/index.js文件:

根据上图,首先组件调用 actions,actions 调用 mutations, mutations 去改变数据。

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({

state: {

city: '北京'

},

actions: {

changeCity (context, city) {

context.commit('changeCity', city)

}

},

mutations: {

changeCity (state, city) {

state.city = city

}

}

})

这时候点击热门城市,当前城市跟着变化,首页右上角的城市也变化。这就实现了首页和城市列表页的数据共享。

但是我们刚才这个过程里没有任何的异步操作,而且操作也很简单,不是一些批量的数据操作,所以组件没必要去调用acions,可以直接去调用 mutations,所以我们可以修改为:

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({

state: {

city: '北京'

},

// actions: {

// changeCity (context, city) {

// context.commit('changeCity', city)

// }

// },

mutations: {

changeCity (state, city) {

state.city = city

}

}

})

然后Lits.vue修改为:

// 热门城市点击事件

handleCityClick (city) {

// this.$store.dispatch('changeCity', city)

this.$store.commit('changeCity', city)

}

OK,功能一样可以实现。

下面把城市列表也添加上点击事件:

<div class="item border-bottom" v-for="v in item" :key="v.id" @click="handleCityClick(v.name)">

{{v.name}}

</div>

当然搜索的时候点击城市也要添加点击事件,打开Search.vue:

<li class="search-item border-bottom" @click="handleCityClick(item.name)"

v-for="item in list" :key="item.id">

<script>

export default {

methods: {

// 切换城市点击事件

handleCityClick (city) {

this.$store.commit('changeCity', city)

}

},

}

</script>

OK,功能实现了。

下面就是在点击切换城市后,直接跳回到首页:

handleCityClick (city) {

this.$store.commit('changeCity', city)

this.$router.push('/')

}

现在点击城市后,可以切换当前城市并且返回到首页。

Vuex的高级使用和localStorage

继续上面的代码,当我们点击城市切换,并返回到首页时,这时候都没问题,但是我们刷新页面,这时候右上角的城市又变为了默认值北京。这时候我们就需要用到 localStorage 本地存储。

打开stroe/index.js文件:

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({

state: {

city: localStorage.city || '北京'

},

mutations: {

changeCity (state, city) {

state.city = city

localStorage.city = city

}

}

})

这时切换城市后,在怎么刷新,也不会变了。

建议:

当使用 localStorage 的时候,建议大家在外层包裹一个try catch,因为在某些浏览器,如果用户关闭了本地存储功能或者使用了隐身模式时,使用 localStorage 有可能会导致浏览器抛出异常,代码就运行不了了。所以修改为:

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

},

mutations: {

changeCity (state, city) {

state.city = city

try {

localStorage.city = city

} catch (e) {

}

}

}

})

刷新,功能还是一样的。

这时候我们发现store/index.js的文件开始复杂起来了,这时候我们可以进行拆分,新创建一个state.js文件,我们把一部分代码复制到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) {

}

}

}

store/index.js改为:

import Vue from 'vue'

import Vuex from 'vuex'

import state from './state'

import mutations from './mutations'

Vue.use(Vuex)

export default new Vuex.Store({

state: state,

mutations: mutations

})

这样我们就拆分为了几个部分。

小bug:当我们在城市列表中,点击文字多的城市,比如“阿拉善盟”,这时首页的样式有点变形了。

打开home下的Header.vue文件,修改下样式:

.header-right

padding:0 .1rem

min-width: 1.04rem

float:right

text-align: center

color: #fff

这时候选几个字的城市都可以了。

下面进行代码优化

home文件夹下的Header.vue代码优化:

<div class="header-right">{{this.city}} <i class="iconfont arrow-icon">&#xe64a;</i></div>

<script>

import { mapState } from 'vuex'

export default {

name: 'HomeHeader',

computed: {

// 展开运行符

// 把city这个公用数据映射到名字叫做city的计算属性之中

...mapState(['city'])

}

}

</script>

city文件夹下的list.vue代码优化:

<div class="button">{{this.city}}</div>

<script>

import Bscroll from 'better-scroll'

import { mapState, mapMutations } from 'vuex'

export default {

computed: {

// 把vuex里面的city这个公用的数据映射到这个组件的计算属性里,映射过来的名字叫做currentCity

...mapState({

currentCity: 'city'

})

},

methods: {

// 热门城市点击事件

handleCityClick (city) {

// this.$store.commit('changeCity', city) 改为下面代码

this.changeCity(city)

this.$router.push('/')

},

// 有一个mutations叫changeCity,然后把这个mutations映射到组件里一个名字叫changeCity的方法里

...mapMutations(['changeCity'])

},

}

</script>

然后是Search.vue页面:

import { mapMutations } from 'vuex'

export default {

methods: {

// 切换城市点击事件

handleCityClick (city) {

// this.$store.commit('changeCity', city) 改为下面代码

this.changeCity(city)

this.$router.push('/')

},

...mapMutations(['changeCity'])

},

}

Vuex核心概念:

State:存放的是公用的数据

Action:一些异步的方法可以写在Action里

Mutation:放的是同步的一些对数据的改变

Getter:当我们需要根据state里的数据,计算出一些新的数据时,我们可以用Getter。有点类似于组件中的computed计算属性的作用。

Module:可以把 store的代码进行分割成模块

例如:Getter例子:首页右上角显示:城市 城市

store/index.js文件:

import Vue from 'vue'

import Vuex from 'vuex'

import state from './state'

import mutations from './mutations'

Vue.use(Vuex)

export default new Vuex.Store({

state: state,

mutations: mutations,

getters: {

doubleCity (state) {

return state.city + ' ' + state.city

}

}

})

home下的Header.vue文件:

<div class="header-right">{{this.doubleCity}} <i class="iconfont arrow-icon">&#xe64a;</i></div>

<script>

import { mapState, mapGetters } from 'vuex'

export default {

name: 'HomeHeader',

computed: {

...mapState(['city']),

...mapGetters(['doubleCity'])

}

}

</script>

这时页面效果图:

提交代码并进行合并:

git add .

git commit -m "vuex实现数据共享和localStorage"

git push

git checkout master

git merge city-vuex

git push

以上是 Vue2.5 旅游项目实例17 城市选择页-使用Vuex实现数据共享 的全部内容, 来源链接: utcz.com/z/376460.html

回到顶部