Vuex是什么?


       記得去年公司招聘前端工程師的時候,我要負責准備面試題去考驗面試者,讓我記憶深刻的有一件事,我看大多數面試者簡歷上都寫了熟練掌握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.vueJobTop頁面無需改動,頁面效果如下:

 

 

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 里有一個 job 屬性,將該屬性映射到該組件的 job 屬性里,

 效果圖如下:

 

總結:Vuex的介紹就先到這里了,希望大家真的理解了,不會在面試的時候被面試官問Vuex是什么,還在支支吾吾就不好了,還有什么問題或者不理解的地方歡迎在下方留言,我有什么做錯的地方也可以提出,我會進行修改,謝謝大家了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM