使用Vuex实现(首页和城市选择页面的)数据共享

1. 创建新分支city-vuex并拉到线下,切换到新分支上:
在这里插入图片描述
然后重启服务器。

2. 我们要实现的功能是点击城市选择页面的城市时,首页右上角的城市会随之切换到相同的城市:
在这里插入图片描述
这就意味着首页和城市选择页面要共享一些数据,或者说城市选择页面要传送一些数据给首页,即City.vueHome.vue要共用一些数据,但是这两个组件没有一个共用的父子组件,就不能用之前的方法:
在这里插入图片描述
3. Vuex
Vuex是一个vue官方推荐的数据框架,在vue的大型项目开发之中,vue只能承担视图层的内容,当我们涉及到大量数据传递的时候,往往都需要一个数据框架进行辅助,在vue之中,这个数据框架就是vuex是一个vue官方推荐的数据框架,在vue的大型项目开发之中,vue只能承担视图层的内容,当我们涉及到大量数据传递的时候,往往都需要一个数据框架进行辅助,在vue之中,这个数据框架就是vuex

  • Vuex的设计理念:
    当我们的项目之中各个页面或者是各个组件之中之间进行复杂的数据传值很困难的时候,我们希望能把这些公用的数据放在一个公共的存储空间去存储,然后某一个组件改变了这个公共的数据,其他的组件就能感知到。
    在这里插入图片描述
    Vuex是指右侧绿色的虚线区域,所有公共的数据都是放在state里的,组件想用一个公用的数据,直接去调用state就可以了。有的时候我们希望去改变公用数据,但是不能直接用组件改变,要走左侧这个流程,如果我有一些异步操作,那么我把这些异步操作放在actions这里,或者是一些复杂的批量的同步操作,也可以放在actions里。组件先去调用actions,紧接着再去调用mutationsmutations放的是一个一个同步的对state的修改。有的时候我们也可以越过actions,直接让组件调用mutations修改state里面的数据。要注意的是,组件通过一个dispatch方法调用actions,通过方法commit来调用mutations
    在这里插入图片描述

4. 步骤

  • 先要安装vuex:先要安装vuex:
    在这里插入图片描述
    然后重启服务器。
  • main.js中引入vuex这样做有些不合适,因为后面要做的vuex文件夹还是比较复杂的。一般做法是我们在src下面创建一个store的文件夹,然后在store中创建一个index.js文件:
  • index.js中引入VueVuex,在Vue中使用插件都是通过Vue.use(),然后我们带出一个由vuex创建的一个仓库,仓库里面一般有一个state的内容,存放的是全局共用的数据:
    在这里插入图片描述
    然后在main.js中导入store这个文件夹,vue会自动找到index.js
    在这里插入图片描述
  • 然后创建根Vue实例的时候,把Store传入进去:
    在这里插入图片描述
  • 哪一个组件要用到这个公用的数据呢,首页Header组件中要用到,打开Home.vue这个组件,以前Headercity数据是由外部传递进去的,我们现在希望city是前端存储的,不需要后端告诉当前是哪一个城市,下面是代码的一些改动:
    在这里插入图片描述
  • 打开staticmock里的index.json,去掉“city”:“北京”:
    在这里插入图片描述
  • 这时候回到首页,home-header就不会接受到任何的内容了,右上角的北京不显示了:
    在这里插入图片描述
  • 进入header.vue,子组件也就不接收了:
  • 然后修改对应的模板,将之前渲染的this.city修改为this.$store.state.city。其中$store即我们创建的index.js文件中导出的vuex.Store,然后我们在main.js当中创建根实例的时候,把Store传递进去了,所以vuex创建的这个Store会被派发到每一个子组件里面,所以在每一个子组件里面我们都可以通过this.$store获取到这个Store。这个时候,公用数据里面的北京就会被显示在页面上了:
    在这里插入图片描述
  • 我们进入到城市选择页面,这是当前城市显示的也应该是北京,进入对应的组件List.vue,一开始当前城市显示的北京是被写死的:
    在这里插入图片描述
    把北京也改为this.$store.state.city
    在这里插入图片描述
  • 接下来实现逻辑功能,希望点击热门城市里的城市的时候,公用数据发生变化,简单来说,就是我们现在要改变state了,要走的流程是,首先要调用actions,然后是mutations:
    首先我们给List组件中的每一个热门城市都绑定一个点击事件,调用这个方法的时候,我们首先要把item.name传进来:
    在这里插入图片描述
    然后在methods里面的定义这个方法,接收一个city,然后alert一下:
    在这里插入图片描述
  • 接下来在这个组件中我们会去调用vuex里的actions,调用dispatch然后触发一个changeCitycity作为第二个参数传过来:
    在这里插入图片描述
    当然仅仅这样做是没有任何效果的,这句话的意思是我要派发一个changeCityaction,然后把city传过去。所以我们需要在store中添加一个和changeCity名字一样的actionchangeCity是个方法,会接受两个参数:上下文ctx,另一个就是传递过来的数据city,就可以实现点击城市时打印出城市名了:
    在这里插入图片描述
    当点击的时候,changeCity会被派发,然后actions就会接收到对应传递过来的city,然后就会打印出数据了。此时actionsindex.js中的)已经接收到了传递过来的city,然后它需要调用mutations来改变state里公用的数据。
  • 接下来要在index.js中创建一个mutations,也可以有一个changeCity方法,接收两个数据:一个是state,第二个是外部传来的city,我们先要actions执行的时候通过commit来调用mutations,而我们可以借助ctx拿到commit这个方法去执行“changeCity”这个mutations,传过去的内容为city,这样就转到mutationschangeCity的执行了:
    在这里插入图片描述
  • 然后我们让state里的city等于传进来的city就可以了,然后回到浏览器,就可以实现点击变化了。
  • 我们可以看到,我们改变state不是异步操作,而且也没有涉及到批量的数据转发,所以组件在这里可以跳过调用actions,直接调用mutations,同样methods中也要调用commit而不是dispatch
    在这里插入图片描述
  • 点击列表的时候也要实现城市的切换,给城市列表项加点击属性,修改传进去的内容:
    在这里插入图片描述
  • 城市搜索的时候,点击城市列表项也要实现城市的切换,在Search组件中定义一样的handleCity事件:
    在这里插入图片描述
    接下来我们希望实现的是当我们点击城市列表的城市项的时候,不但当前城市同步,还可以立即返回到首页:
  • 路由的概念,在vue中我们可以通过vue-router创建a标签来实现页面跳转,还可以借助router的实例方法—编程式导航的形式。当城市项被点击的时候,首先改变了城市的内容,然后我们要做页面的跳转:
    在这里插入图片描述
    List组件中,也要加上router.push

5. Vuex的高级使用及localStorage

  • 我们在state中改变了公共数据,但是实际使用中,当我们点击一个城市的时候,即使再次刷新了页面,首页会显示之前选择的城市,而不是我们默认的state里面的“上海”。
  • 解决:引入一个新的概念,localStorageHTML5中提供了一个新的APIlocalStorage,可以帮助我们实现类似cookie的功能,做到本地存储,而比cookie更加简单。
  • 步骤:
    当用户尝试改变城市的时候,我们不但把state里的城市给改了,而且还存一个localStorage
    在这里插入图片描述
    State的默认值为以下,并且优先取localStorage,取不到才用默认的“上海”:
    在这里插入图片描述
    这样就实现了我们想要的效果。刷新也不会改变上次选择的城市。
  • 强烈建议,只要使用localStorage,就在外层包裹一层try-catch
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 = citytry {localStorage.city = city} catch(e) {}}}
})
  • 这个时候会发现,我们的index.js的代码变得复杂起来了,实际情况下我们会对这些代码进行一个拆分,比如在store文件夹找那个创建一个文件state.js,然后将默认部分剪切到state.js文件中:
    在这里插入图片描述
    紧接着在index.js中导入并注册:
    在这里插入图片描述
    然后再在store文件夹之下创建一个mutations.js,同样将indecx.jsmutations的内容剪切到mutation.js中,并在mutations中导出(export default):
    在这里插入图片描述
    并进一步在index.js中导入:
    在这里插入图片描述
    Index.js中键和值一样就可以简化注册时的代码,直接写成:‘
    在这里插入图片描述
  • Bug:
    点击较长的城市名的时候,样式会出现问题:
    在这里插入图片描述
    解决:打开Header.vue组件,改变宽度:
    在这里插入图片描述

6. 对vuex使用的代码做一个优化

  • Home/Header.vue的优化,vuex提供了一个高级的API,代码可以改写为:
    在这里插入图片描述
    MapState是指我把vuex里的数据映射到我这个组件的computed计算属性里,把city这个数据映射到名叫city的计算属性之中。做好映射之后,模板中就不用之前的写法了,直接可以改为this.city
  • City/List.vue的优化:
    引入,我们在mapState中传递的内容可以是一个数组,也可以是一个对象,即我想把公用数据里的city这个数据映射到当前这个组件的计算属性中,映射过来的名字叫做currentCity
    在这里插入图片描述
    使用:
    在这里插入图片描述
    当我们点击的时候,会向外派发一个mutations
    在这里插入图片描述
    vuex同样提供了一个mapMutations方法:
    在这里插入图片描述
    然后在methods中我们应用mapMutations,同样可以传一个数组,这句代码的意思是我们有一个mutation,叫做changeCity,然后我把这个mutation映射到我的组件里一个叫做changeCity的方法里,这样,要调这个mutation的时候,就可以写成:
    在这里插入图片描述
    同样做Search.vue中的修改,和上面的一样。

7. Vuex中的Getter

他的作用有点儿像组件中computed计算属性的作用,当我们需要以state里的数据计算出一些新的数据时,就可以借助Getter这样的一个工具来提供新的数据,可以避免数据的冗余,举个例子,想要在header-right显示两个城市名称的组合:

  • store下面index.js里写一个getters,对应的是一个对象,我们可以写一个方法叫做doubleCity,会接收一个参数,叫做state
    在这里插入图片描述
  • 在首页Header.vue中,我们原本显示的是this.city,只显示一个城市的名字。现在我们想要实现我们的要求,首先引入mapGetters,然后映射到doubleCity这个方法:
    在这里插入图片描述
    这样在渲染模板中就可以直接用doubleCity了:
    在这里插入图片描述

8. Vuex中的Module
比如我们在管理后台系统的时候,经常会有很多公用的数据在vuex中进行存储,所有的mutation放在一个mutations文件里,这个文件慢慢的会变得非常庞大,这时候,我们可以借助module对复杂的mutationsactionsstate进行拆分,创建Store的时候,可以通过模块来进行创建,各个模块存储和各个模块相关的数据和对数据的操作,对各个模块的数据进行一个整合:
在这里插入图片描述
在这个项目中操作比较简单就不用分模块创建了。

9. 提交到线上


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部