Vuex是什么?

267 篇文章 1 订阅
36 篇文章 0 订阅

      记得去年公司招聘前端工程师的时候,我要负责准备面试题去考验面试者,让我记忆深刻的有一件事,我看大多数面试者简历上都写了熟练掌握Vuex,然而当我问起的时候,大部分回答都支支吾吾,解释不清,而当我提起与Vuex书写相似的Vux的时候,偶尔会被面试者反问到:“这不是一个东西吗?”,和我一同负责面试的技术总监(python,负责后台)也会充满疑惑,也会小声问道:“不是一样的吗?”,我就只好解释完全不是一个东西,一个是状态管理模式,一个是移动端UI组件库等等,说得我口干舌燥......

        

       过了这么久,怎么才突然想起写一篇这样的博客呢,还是因为上上篇博客所提到的那个朋友,也问过我Vuex究竟是什么?正好趁公司项目上线后的这段修整期,有点无聊,写点博客加深一下印象,也希望能帮助更多人理解通Vuex的用法,话不多说,开始步入正题吧......

 

一.Vuex是什么?

介绍:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

理解:核心就是 store(仓库),仓库是用来干什么的?你就当它用来储存东西的。

 

二.上方介绍提到的状态管理模式是什么?

     首先我们先看一张图:

     

     图中的状态管理的各部分含义为: 

  • state,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。

     在代码中的体现位置为:

复制代码

new Vue({
  // state
  data () {
    return {
      count: 0
    }
  },
  // view
  template: `
    <div>{{ count }}</div>
  `,
  // actions
  methods: {
    increment () {
      this.count++
    }
  }
})

复制代码

 

三.我们什么时候应该用到Vuex呢?

1.小应用不建议使用Vuex,因为小项目使用 Vuex 可能会比较繁琐冗余;

2.中大型单页应用,因为要考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择;

 

四.对于使用Vuex的理解是什么?

       由于Vue是单向数据流,子组件内部不能直接修改从父级传递过来的数据,子组件与子组件之间无法相互传递数据。如果我们想让两个子组件之间进行通信的话,可以借助子组件 A 向父组件传值,父组件接收子组件 A 的数据后再传给 B 组件这样的方式进行通信。

       但是这样会有一个问题,就是如果子组件 A 的父组件上面还有一层爷爷组件,或者还有更多祖父类型的层级,那么是不是会很麻烦。

       因此,我们会想到能不能我们将一个共有的数据存在一个特定的地方,用的时候自己去拿,这样就不需要一层层传值,于是乎 Vuex 就应运而生了。

 

五.创建项目,开始实战

创建项目:我的第二篇博客介绍到了怎么创建项目,这里就不多说了,传送门:https://www.cnblogs.com/hejun26/p/8540404.html

安装vuex:

npm install vuex --save

项目目录(具体处已用箭头标注):

目录我们可以看到有一个父组件HelloWorld和两个子组件JobList和JobTop,我们接下来就在这几个父子组件里面来介绍传值方法;

HelloWorld.vue

我们在父组件里面引入两个子组件,并呈现出数据,方便接下来我们继续传值操作:

复制代码

<template>
  <div>
       <job-top :job="job"></job-top>
       <job-list :jobs="jobs"></job-list>
  </div>
</template>

<script>
import JobTop from './component/JobTop';
import JobList from './component/JobList';

export default {
  name: 'HelloWorld',
  props: {},
  data () {
    return {
        job:'',
        jobs:[]
    }
  },
  components:{
     JobTop,
     JobList,
  },
  methods: {
     getListInfo() {
       //这里模拟的接口数据
       this.getListInfoSucc({
            "code":true,
            "job":"web",
            "data":{
                "jobs":[
                    {
                        "id":1,
                        "name":"web"
                    },
                    {
                        "id":2,
                        "name":"C++"
                    },
                    {
                        "id":3,
                        "name":"python"
                    },
                    {
                        "id":4,
                        "name":"java"
                    }
                ]
            }
        })
     },
     getListInfoSucc(res){
       if(res.code){
          this.job=res.job;
          this.jobs=res.data.jobs;
       }
     },
  },
  mounted() {
     this.getListInfo();
  },
}
</script>

<style scoped>
</style>

复制代码

JobTop.vue

这里我们继续单个数据呈现,到时候方便显示切换后的数据:

复制代码

<template>
      <p>{{job}}</p>
</template>
 
<script>
export default {
    name:'JobTop',
    props:{
        job:String,
    },
    data(){
        return{
            
        }
    },
}
</script>

<style>
</style>

复制代码

JobList.vue

这里是父组件里面通过接口获取的数组,进行遍历所呈现出列表形式,我们之后再进行点击传值

复制代码

<template>
     <div>
         <button v-for="item of jobs" :key="item.id">{{item.name}}</button>
     </div>
</template>
 
<script>
export default {
    name:'JobList',
    props:{
        jobs:Array,
    },
    data(){
        return{    
        }
    },
}
</script>

<style>
</style>

复制代码

页面呈现效果如下:

好,现在页面呈现出来了,我接着要写点击事件来进行传值,我们会想到三种传值方式:

 

1.父子组件传值

在 jobList.vue 中定义 jobClick 方法,将 changeJob 方法注入,并将所选中的 job 值传入

复制代码

<template>
     <div>
         <button v-for="item of jobs" :key="item.id" @click="jobClick(item.name)">{{item.name}}</button>
     </div>
</template>
 
<script>
export default {
    name:'JobList',
    props:{
        jobs:Array,
    },
    data(){
        return{   
        }
    },
    methods:{
        //父组件传值
        jobClick(name){
            this.$emit("changeJob",name)
        }
    }
}
</script>

<style>
</style>

复制代码

在父组件 HelloWorld.vue 中接收

复制代码

<template>
  <div>
       <job-top :job="job"></job-top>
       <job-list :jobs="jobs" @changeJob="ChangeJobClick"></job-list>
  </div>
</template>

<script>
import JobTop from './component/JobTop';
import JobList from './component/JobList';

export default {
  name: 'HelloWorld',
  props: {},
  data () {
    return {
        job:'',
        jobs:[]
    }
  },
  components:{
     JobTop,
     JobList,
  },
  methods: {
     getListInfo() {
       this.getListInfoSucc({
            "code":true,
            "job":"web",
            "data":{
                "jobs":[
                    {
                        "id":1,
                        "name":"web"
                    },
                    {
                        "id":2,
                        "name":"C++"
                    },
                    {
                        "id":3,
                        "name":"python"
                    },
                    {
                        "id":4,
                        "name":"java"
                    }
                ]
            }
        })
     },
     getListInfoSucc(res){
       if(res.code){
          this.job=res.job;
          this.jobs=res.data.jobs;
       }
     },
     ChangeJobClick(name){
       console.log("选中的岗位",name);
       this.job=name;
     }
  },
  mounted() {
     this.getListInfo();
  },
}
</script>

<style scoped>
</style>

复制代码

在父组件的的 job-list 标签中写上子组件 JobLict.vue注入的 changeJob方法,并指向ChangeJobClick 方法,ChangeJobClick 方法中接收传过来的选中的 job 值,并将该值传递给子组件 JobTop.vue,JobTop页面无需改动,页面效果如下:

 

 

2.原型链继承

正好之前一篇博客讲过 javascript 的原型链继承,vue 其实就是 js 的一种框架,它也有prototype 属性,我们叫做 Bus总线方法。如下:

JobList.vue

复制代码

<template>
     <div>
         <button v-for="item of jobs" :key="item.id" @click="jobClick(item.name)">{{item.name}}</button>
     </div>
</template>
 
<script>
import Vue from 'vue'
Vue.prototype.bus=new Vue();
export default {
    name:'JobList',
    props:{
        jobs:Array,
    },
    data(){
        return{  
        }
    },
    methods:{
        //原型链继承
        jobClick(name){
            console.log("点击某个岗位:",name)
            this.bus.$emit("changeJob",name)
        }
    }
}
</script>

<style>
</style>

复制代码

我们现在 Vue 的 prototype 属性中引入 bus ,然后在 button 按钮上绑定 jobClick 点击事件,并传入点击的 job ,然后在 bus总线上注入 changeJob 方法,并将点击的 job 值传入,我们再来看一下 

JobTop.vue

复制代码

<template>
      <p>{{jobself}}</p>
</template>
 
<script>
export default {
    name:'JobTop',
    props:{
        job:String,
    },
    data(){
        return{
            jobself:this.job
        }
    },
    mounted () {
        //原型链继承
        var that=this;
        this.bus.$on("changeJob",function(name){
             console.log("点击后传过来的job",name)
             that.jobself=name;
        })
    }
}
</script>

<style>
</style>

复制代码

HelloWorld页面无需更改,最终效果图如下:

 

3.Vuex

接下来介绍今天的主角 Vuex ,Vuex 说白了就像是开辟了一个组件共有的内存空间,组件都可以去取去用;

我们在src创建 store 文件夹,里面添加一个 index.js 来存储共享数据,在 main.js 中引入 store文件,并在 Vue 实例中注入 store 。

main.js

复制代码

import Vue from 'vue'
import App from './App'
import router from './router'

import Vuex from 'vuex'
import store from './store'

Vue.use(VueRouter)
Vue.use(Vuex)

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

复制代码

JobList.vue

复制代码

<template>
     <div>
         <button v-for="item of jobs" :key="item.id" @click="jobClick(item.name)">{{item.name}}</button>
     </div>
</template>
 
<script>
export default {
    name:'JobList',
    props:{
        jobs:Array,
    },
    data(){
        return{   
        }
    },
    methods:{
        //vuex
        jobClick(name){
            this.$store.dispatch("changeJob",name)
        },
    }
}
</script>

<style>
</style>

复制代码

在 JobList.vue 中添加 jobClick 点击方法,根据上面说的流程将一个 changJob 事件通过 dispatch 方法注入,并将所选的 job 值传入。

store文件夹下的index.js

复制代码

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

export default new Vuex.Store({
     state: {
        job:"web"
     },
     actions: {
        changeJob(ctx,name){
            console.log("action",ctx,name);
            ctx.commit("changeJob",name);
        }
     },
     mutations: {
         changeJob(state,name){
             console.log("mutation",state,name);
             state.job=name;
         }
     }
})

复制代码

JobTop.vue

获取到job的值,渲染出来

复制代码

<template>
     <p>{{this.$store.state.job}}</p>
</template>
 
<script>
export default {
    name:'JobTop',
    props:{
        job:String,
    },
    data(){
        return{
        }
    },
}
</script>

<style>
</style>

复制代码

HelloWorld页面不需要改动,页面效果如下:

 

以上就是vue的几种组件传参方式,大家想了解的更加官方,请阅览官方地址:https://vuex.vuejs.org/zh/

 

根据官方 Vuex 目录,我们再深一步讲解一下核心概念,对上面的代码进行一下重构。

JobList.vue

复制代码

<template>
     <div>
         <button v-for="item of jobs" :key="item.id" @click="jobClick(item.name)">{{item.name}}</button>
     </div>
</template>
 
<script>
import { mapMutations } from 'vuex'
export default {
    name:'JobList',
    props:{
        jobs:Array,
    },
    data(){
        return{  
        }
    },
    methods:{
        //vuex
        jobClick(name){
            this.changeJob(name)
        },
        ...mapMutations(['changeJob'])
    }
}
</script>

<style>
</style>

复制代码

尤大大为我们提供了封装好的一些方法,如上面的 ...mapMutations() ,意思是 mutations 里有一个 changeJob ,我们将其映射到该组件的一个 changeJob的方法里,这样就可以直接调用 changeJob 方法并传值了

JobTop.vue

复制代码

<template>   
      <p>{{this.job}}</p>
</template>
 
<script>
import { mapState } from 'vuex'
export default {
    name:'JobTop',
    props:{
    },
    data(){
        return{
        }
    },
    computed:{
       ...mapState(['job'])
    },
}
</script>

<style>
</style>

复制代码

在 mapState 里有一个 city 属性,将该属性映射到该组件的 city 属性里,

 效果图如下:

 

总结:Vuex的介绍就先到这里了,希望大家真的理解了,不会在面试的时候被面试官问Vuex是什么,还在支支吾吾就不好了,还有什么问题或者不理解的地方欢迎在下方留言,我有什么做错的地方也可以提出,我会进行修改,谢谢大家了。

 

  • 54
    点赞
  • 187
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值