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


    创建分支: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- 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
  • 相关阅读:
    Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Multiple representations of the same entity解决方法
    基于注释配置bean和装饰bean
    Oracle 11g+oracle客户端(32位)+PL/SQL develepment的安装配置
    SpringData JPA的学习笔记之环境搭建
    Maven+struts2+spring4+hibernate4的环境搭建
    springmvc集成Ueditor插件实现图片上传2、
    c博客作业函数
    C语言博客作业2循环结构
    C语言第0份作业
    c博客作业分支、顺序结构
  • 原文地址:https://www.cnblogs.com/joe235/p/12502466.html
Copyright © 2020-2023  润新知