• Vuex入门简单示例(三)


    前言

    我想写一系列关于Vuex的入门文章,我是看着vuex官网文档,结合自己从零搭建的vue项目来实践vuex的知识。

    Vuex入门系列:

    本文涉及知识点:

    1. vuex之mapState
    2. 独立store.js文件
    3. vuex之getter
    4. vuex之mapGetters

     

    这一篇我们学习下如何使用mapState

    给首页(Home.vue)添加一些内容,显示登录状态、用户名和密码这三个状态。

    先看下vuex文档对mapState的说明:

    mapState辅助函数

    当一个组件需要获取多个状态时,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用mapState辅助函数帮助我们生成计算属性。

     

    把这个知识点结合到本示例中

    首先,在需要的页面导入mapState

    src/components/Home.vue

    import { mapState } from 'vuex'

    在vue计算属性computed里面使用mapState函数

      computed: mapState({
        isLogin: state => state.isLogin,
        username: state => state.username,
        password: state => state.password
      })

    还要修改下<template>模板的代码

    src/components/Home.vue完整代码如下:

    <template>
      <div class="home">
        登录状态:{{isLogin}} <br>
        用户名:{{username}}<br>
        密码:{{password}} <br>
        首页 
      </div>
    </template>
    
    <script>
    import { mapState } from 'vuex'
    
    export default {
      name: 'Home',
      computed: mapState({
        isLogin: state => state.isLogin,
        username: state => state.username,
        password: state => state.password
      })
    }
    </script>

    刷新浏览器回到登录页(登录页内容不变)

    点登录按钮进入首页后,效果如下:

    等等,我发现一个问题,这里的computed好像被mapState独用了,如果我们想写一个普通的(非mapState里面的)计算属性怎么办?

    假设data里面有两个变量,我们需要计算出它们的相加的结果并显示出来。

    // ...
      data () {
        return {
          a: 10,
          b: 20
        }
      },
    // ...

    这时computed需要改变一下,这就要用到对象展开运算符[...]

    // ...
      computed: {
        sum () {
          return this.a + this.b
        },
        ...mapState({
          isLogin: state => state.isLogin,
          username: state => state.username,
          password: state => state.password
        })
      }
    // ...

    src/components/Home.vue完整代码如下:

    <template>
      <div class="home">
        登录状态:{{isLogin}} <br>
        用户名:{{username}}<br>
        密码:{{password}} <br>
        a + b = {{sum}} <br>
        首页 
      </div>
    </template>
    
    <script>
    import { mapState } from 'vuex'
    
    export default {
      name: 'Home',
      data () {
        return {
          a: 10,
          b: 20
        }
      },
      computed: {
        sum () {
          return this.a + this.b
        },
        ...mapState({
          isLogin: state => state.isLogin,
          username: state => state.username,
          password: state => state.password
        })
      }
    }
    </script>

    独立store.js

    随着示例内容的增加,store的代码会越来越多,导致main.js太长,不利于维护。现在把store单独放一个js文件。

    在src目录下新建一个js文件store.js

    src/store.js

    // 导入vue和vuex
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引用Vuex
    Vue.use(Vuex)
    
    // 从main.js拷贝过来即可
    const store = new Vuex.Store({
        state: {
          isLogin: false, //登录状态
          username: '', //用户名
          password: '' //密码
        },
        mutations: {
          // 修改登录状态
          changeLogin(state, data) {
            state.isLogin = data
          },
          // 修改用户名状态
          changeUsername(state, data) {
            state.username = data
          },
          // 修改密码状态
          changePassword(state, data) {
            state.password = data
          }
        }
    })
    
    // 暴露(导出)store
    export default store

    main.js需要删掉一些代码

    src/main.js

    import Vue from 'vue'
    import App from './App.vue'
    import VueRouter from 'vue-router'
    // import Vuex from 'vuex' (-)
    import store from './store' // (+)
    
    Vue.config.productionTip = false
    
    Vue.use(VueRouter)
    //- Vue.use(Vuex) (-)
    
    // 页面组件
    import Home from '@/components/Home'
    import Login from '@/components/Login'
    
    const router = new VueRouter({
      routes: [
        {
          path: '/',
          name: 'home',
          component: Home,
          meta: { auth: true }
        },
        {
          path: '/login',
          name: 'login',
          component: Login,
          meta: { auth: true }
        }
      ]
    })
    
    // 一下store对象剪切到store.js
    // const store = new Vuex.Store({
    //   state: {
    //     isLogin: false, //登录状态
    //     username: '', //用户名
    //     password: '' //密码
    //   },
    //   mutations: {
    //     // 修改登录状态
    //     changeLogin(state, data) {
    //       state.isLogin = data
    //     },
    //     // 修改用户名状态
    //     changeUsername(state, data) {
    //       state.username = data
    //     },
    //     // 修改密码状态
    //     changePassword(state, data) {
    //       state.password = data
    //     }
    //   }
    // })
    
    /* 路由拦截:检查是否登录,未登录则跳到登录页 */
    router.beforeEach((to, _, next) => {
      console.log(to);
      if (to.matched.some( m => m.meta.auth)) {
        if (to.name == 'login') {
          next()
        } else {
          if (store.state.isLogin == true) {
            next()
          } else {
            next('/login')
          }
        }
      } else {
        next()
      }
    })
    
    new Vue({
      router,
      store,
      render: h => h(App),
    }).$mount('#app')

    运行刷新一下,看下效果应该和之前一样。

    Vuex之Getter

    为了学习Getter,我们做一个签到列表页。

    在store.js的store对象的state里面的password下面添加一个表示签到列表的状态字段list

    // ...
        state: {
          isLogin: false, //登录状态
          username: '', //用户名
          password: '', //密码
          list: [
              { name: '张三', checked: true },
              { name: '李四', checked: false },
              { name: '哪吒', checked: true },
              { name: '敖丙', checked: false },
              { name: '申公豹', checked: true },
              { name: '太乙真人', checked: true },
          ]
        },
    // ...

    目的是显示checked为true的人员

    给store对象添加getters属性

    // ...
        getters: {
            showChecked: state => {
                return state.list.filter(item => item.checked)
            }
        },
    // ...

    src/store.js的完整代码如下:

    // 导入vue和vuex
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引用Vuex
    Vue.use(Vuex)
    
    // 从main.js拷贝过来即可
    const store = new Vuex.Store({
        state: {
          isLogin: false, //登录状态
          username: '', //用户名
          password: '', //密码
          list: [
              { name: '张三', checked: true },
              { name: '李四', checked: false },
              { name: '哪吒', checked: true },
              { name: '敖丙', checked: false },
              { name: '申公豹', checked: true },
              { name: '太乙真人', checked: true },
          ]
        },
        getters: {
            showChecked: state => {
                return state.list.filter(item => item.checked)
            }
        },
        mutations: {
          // 修改登录状态
          changeLogin(state, data) {
            state.isLogin = data
          },
          // 修改用户名状态
          changeUsername(state, data) {
            state.username = data
          },
          // 修改密码状态
          changePassword(state, data) {
            state.password = data
          }
        }
    })
    
    // 暴露(导出)store
    export default store

    回到Home.vue,看看如何使用getters

    在vue实例的计算属性中增加一个属性

      computed: {
        // 其他代码省略...
        showChecked () {
          return this.$store.getters.showChecked
        }
      }

    在template模板里面增加一段代码显示签到人员

        <hr>
        <div>
          已签到人员:<br>
          <ul>
            <li v-for="(item, index) in showChecked" :key="index">
              {{item.name}}
            </li>
          </ul>
        </div>

    src/components/Home.vue完整代码如下:

    <template>
      <div class="home">
        登录状态:{{isLogin}} <br>
        <hr>
        用户名:{{username}}<br>
        密码:{{password}} <br>
        <hr>
        a + b = {{sum}} <br>
        <hr>
        <div>
          已签到人员:<br>
          <ul>
            <li v-for="(item, index) in showChecked" :key="index">
              {{item.name}}
            </li>
          </ul>
        </div>
        首页 
      </div>
    </template>
    
    <script>
    import { mapState } from 'vuex'
    
    export default {
      name: 'Home',
      data () {
        return {
          a: 10,
          b: 20
        }
      },
      computed: {
        sum () {
          return this.a + this.b
        },
        ...mapState({
          isLogin: state => state.isLogin,
          username: state => state.username,
          password: state => state.password
        }),
        showChecked () {
          return this.$store.getters.showChecked
        }
      }
    }
    </script>

    此时首页效果如下:

    说明:

    • 加了一些<hr>分割内容
    • 教程中所有.vue文件都省略了<style></style>,这个自行加上

    通过方法访问

    通过让getter返回一个函数,来实现给getter传参。在你对store里的数组进行查询时非常有用

    为了练习这一知识点,我们实现一个已签到和未签到的切换。

    点击已签到显示已签到的人员,点击未签到显示未签到的人员。

    改造一下store.js里的getters里的showChecked,根据传入的参数checked来返回数据。

        getters: {
            showChecked: (state) => (checked) => {
                return state.list.filter(item => item.checked === checked)
            }
        },

    回到Home.vue页面,这里我们不在计算属性中获取数据了。在methods中写一个方法来获取。

    现在data里添加一个空数组,来存放签到列表的初始值。再利用方法修改这个数组的值。

    src/components/Home.vue

      data () {
        return {
          a: 10,
          b: 20,
          checkList: []
        }
      },
      methods: {
        getChecked (checked) {
          console.log(this.$store.getters.showChecked(checked))
          this.checkList = this.$store.getters.showChecked(checked);
        }
      }

    修改template代码,原来的‘已签到人员:’改成两个切换标签,渲染列表的showChecked改成checkList:

        <div>
          <div><a href="javascript:;" @click="getChecked(true)">已签到</a> | <a href="javascript:;" @click="getChecked(false)">未签到</a></div>
          <ul>
            <li v-for="(item, index) in checkList" :key="index">
              {{item.name}}
            </li>
          </ul>
        </div>

    在vue实例created钩子函数里调用一次this.getChecked(true),为了默认显示已签到数据。否则一打开就是空空的。

    src/components/Home.vue完整代码:

    <template>
      <div class="home">
        登录状态:{{isLogin}} <br>
        <hr>
        用户名:{{username}}<br>
        密码:{{password}} <br>
        <hr>
        a + b = {{sum}} <br>
        <hr>
        <div>
          <div><a href="javascript:;" @click="getChecked(true)">已签到</a> | <a href="javascript:;" @click="getChecked(false)">未签到</a></div>
          <ul>
            <li v-for="(item, index) in checkList" :key="index">
              {{item.name}}
            </li>
          </ul>
        </div>
        首页 
      </div>
    </template>
    
    <script>
    import { mapState } from 'vuex'
    
    export default {
      name: 'Home',
      data () {
        return {
          a: 10,
          b: 20,
          checkList: []
        }
      },
      computed: {
        sum () {
          return this.a + this.b
        },
        ...mapState({
          isLogin: state => state.isLogin,
          username: state => state.username,
          password: state => state.password
        }),
        // showChecked () {
        //   return this.$store.getters.showChecked(0)
        // }
      },
      created () {
        this.getChecked(true);
      },
      methods: {
        getChecked (checked) {
          console.log(this.$store.getters.showChecked(checked))
          this.checkList = this.$store.getters.showChecked(checked);
        }
      }
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
    </style>

    mapGetters辅助函数

    看下vuex官方文档的描述:

    mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性

     为了应用mapGetters,我们得改变一下之前的代码。

    在store.js添加一个歌单(songs)状态,目的是根据条件显示其中一部分歌名。

    // ...
          songs: [
            { name: '黑色毛衣', singer: '周杰伦' },
            { name: '烟花易冷', singer: '周杰伦' },
            { name: '爱笑的眼睛', singer: '林俊杰' },
            { name: '美人鱼', singer: '林俊杰' },
            { name: '不能说的秘密', singer: '周杰伦' },
            { name: '一千年以后', singer: '林俊杰' },
            { name: '七里香', singer: '周杰伦' },
            { name: '修炼爱情', singer: '林俊杰' },
          ]
    // ...

    把getters里的showChecked改成简单版的,只返回checked=true的人员;再添加一个方法showSongs,返回周杰伦的歌。

    // ...
        getters: {
            showChecked: state => {
                return state.list.filter(item => item.checked)
            },
            showSongs: state => {
              return state.songs.filter(item => item.singer == '周杰伦')
            },
        },
    
    // ...

    回到Home.vue,改动蛮大的。

    首先,导入mapGetters:

    import { mapState, mapGetters } from 'vuex'

    计算属性调用mapGetters:

        ...mapGetters([
          'showChecked',
          'showSongs'
        ])

    template模板修改:

        <div>
          <div>已签到</div>
          <ul>
            <li v-for="(item, index) in showChecked" :key="index">
              {{item.name}}
            </li>
          </ul>
        </div>
        <hr>    
        <div>
          <div>周杰伦的歌</div>
          <ul>
            <li v-for="(item, index) in showSongs" :key="index">
              {{item.name}} - {{item.singer}}
            </li>
          </ul>
        </div>

    src/components/Home.vue完整代码:

    <template>
      <div class="home">
        登录状态:{{isLogin}} <br>
        <hr>
        用户名:{{username}}<br>
        密码:{{password}} <br>
        <hr>
        a + b = {{sum}} <br>
        <hr>
        <div>
          <div>已签到</div>
          <ul>
            <li v-for="(item, index) in showChecked" :key="index">
              {{item.name}}
            </li>
          </ul>
        </div>
        <hr>    
        <div>
          <div>周杰伦的歌</div>
          <ul>
            <li v-for="(item, index) in showSongs" :key="index">
              {{item.name}} - {{item.singer}}
            </li>
          </ul>
        </div>
        首页 
      </div>
    </template>
    
    <script>
    import { mapState, mapGetters } from 'vuex'
    
    export default {
      name: 'Home',
      data () {
        return {
          a: 10,
          b: 20
        }
      },
      computed: {
        sum () {
          return this.a + this.b
        },
        ...mapState({
          isLogin: state => state.isLogin,
          username: state => state.username,
          password: state => state.password
        }),
        ...mapGetters([
          'showChecked',
          'showSongs'
        ])
    
      },
      methods: {
      }
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
    </style>

    效果如下:

    参考文档:Vuex官方中文文档 

  • 相关阅读:
    android的UriMatcher类
    学习Scanner类
    android应用开发 listview
    EditText 和 TextView 的属性详解
    Android适配器Adapter学习
    AlertDialog.Builder对话框类的用法
    Android ArrayAdapter 详解
    ThreadPoolExecutor线程池大小设置与BlockingQueue的三种实现区别
    【Android】滑动屏幕效果GestureDetector、OnGestureListener、ViewFlipper
    Windows Phone 7常用的开发技巧&学习总结
  • 原文地址:https://www.cnblogs.com/cathy1024/p/11357454.html
Copyright © 2020-2023  润新知