欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vuejs全家桶之vuex

程序员文章站 2024-02-28 23:42:16
...

什么是vuex?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
总结一下上面官方给出的解释:

注意1: vuex 只能在vuejs项目使用
注意2:为 vuejs 项目提供统一的数据仓库(我们可以把vuejs项目中所有的模型数据都统一放置在 vuex,为了解决组件间通信的问题)
注意3:vuex 里面管理的数据是单向的数据流(在操作数据的时候,只能按照一个方向去操作,或者换句话说,我们不能直接的操作数据,需要遵循 vuex 规范才可以操作数据。
注意4:提供一个调试的工具,非常方便的查看vuex管理的数据。

vuex状态管理思想

vuejs全家桶之vuex

为什么要使用vuex?

  • 可以方便组件间的通信问题(重点)
  • 可以提供缓存的特性(异步请求浏览器缓存)
  • 可以很好的做调试(vuejs devTools)

同步修改数据和异步修改数据

vuejs全家桶之vuex

vuex的使用

1, vuex 只能在vuejs项目使用,所以我们用vue-cli这个脚手架快速构建一个vue项目

yarn add @vue/cli
npx vue create myapp

2,下载vuex,并在项目的main.js文件中导入并使用


import Vuex from 'vuex'

Vue.use(Vuex)

3,(1)创建一个仓库(store)(2)提供state(3)提供修改数据的mutation

const store = new Vuex.Store({
  state: {
    count: 0,
  },

  mutations: {
  },

(4)注册store

new Vue({
  //store在这里注册,然后渲染到页面上
  store,
  router,
  render: h => h(App)

}).$mount('#app')

4,同步修改数据
(1)在App.vue主组件中的template中,先写一个按钮组,并定义点击事件,加减操作span里面的数据,这里是定义页面触发行为,然后创建一个生命周期函数,然后将函数导出
(2)在生命周期函数里面的methods中提交(commit)加减函数到mutation中
(3)在store的mutation中,定义加减函数应该进行什么操作(修改state),然后渲染页面
(4)将仓库里的state映射到组件的data里面(需要映射成计算属性才行

<1> 在App.vue中引入mapState
import { mapState} from ‘vuex’;
<2>然后在computed里面映射
…mapState({countAias: ‘count’,movieData:‘movieData’})
<3>底层原理
countAias:function(){
return this.$store.state.count
}

(5)把仓库里面的mutations映射到组件中的methods

<1> 在App.vue中引入mapMutations
import { mapState,mapMutations} from ‘vuex’;
<2>然后在methods里面映射
…mapMutations([‘increment’,‘decrement’]),
<3>底层原理
increment:function () {
this.KaTeX parse error: Expected 'EOF', got '}' at position 31: …ncrement') }̲, decrement:fun…store.commit(‘decrement’)
}

5,异步修改数据

(1)在App.vue中定义页面触发行为
(2)页面触发行为,dispatch(分发)在store中的action,在action中完成异步操作,去向服务器请求数据
(3)action请求完成以后,将响应回来的数据commit到mutation中
(4)然后将请求回来的数据保存下来,所以这里向action操作完了之后,要commit action 和payload
(5)我们希望仓库帮我们管理数据,保存数据到仓库
(6)将在仓库里面的数据映射到data里
…mapState({countAias: ‘count’,movieData:‘movieData’})
(7)将action映射到methods里面

…mapActions({clickHandler:‘getMovie’}),
底层原理
clickHandler:function(){
this.$store.dispatch(‘getMovie’)
},

(8)App.vue的template中渲染

(9)筛选(getters专门负责对数据的筛选过滤操作)

<1>在store 中定义一个getter,这里定义是一个方法,按照属性方式使用,和计算属性一样
<2>定义一个方法,筛选信息,将信息返回到页面中
<3>将getters映射到computed中
import {mapState, mapMutations, mapActions, mapGetters} from ‘vuex’;
…mapGetters([‘returnStarBig12w’])

(10)vuex的缓存特性

<1>当第一次向服务器发送网络请求是,浏览器会对数据进行缓存,我们已经有了数据,但是在这里第二次第三次还是会向服务器请求数据,这样太耗费性能
<2> 我们可以在向服务器发送网络请求前,判断一下仓库里面有没有数据,如果没有,发送网络请求,如果有,则不发送

(11)loading效果

由于网络请求所耗费的时间是不确定,意味用户等待的时长也是不确定,为了防止乱点击,烦躁。一般在发送网络请求后,会在页面上出一个 loading的效果。数据成功回来后,loading消失。
1. loading.gif 2. 插件 3. css3 loading 效果
<1>我用css3loading效果,先在App.vue中放置html,和样式
<2>因为loading和数据是互斥的,所以我们分别给他们两个加上v-if=“flag”,v-else
<3>我们让flag映射到data里面
…mapState({countAias: ‘count’,movieData:‘movieData’,flag:‘flag’}),
<4>在action中,还没有网络请求的时候进行提交commit,payload默认为true,也就是loading是默认显示的
store.commit(‘modifyFlag’, true);
<5>在mutation中关于modifyFlag进行操作
<6>在已经请求回来数据时(savemovieData),将flag改为false

(12)调试
vuejs全家桶之vuex

store:

import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex)
const store = new Vuex.Store({
    state: {

        count: 0,


        //异步修改数据第二步:因为我们希望仓库来帮我们管理接口数据,所以我在这里放一个电影列表的容器,待会我把数据请求回来了就放在这里,这一步做完了之后,我们让页面触发一个行为,dispatch
        movieData:[]
    },
    //mutation接收到提交过来的行为和载荷,操作仓库里的数据state
    mutations: {


        //store里面有一个state数据,这是一个对象,对象里面含有count数据
        //当点击加号的时候,count=count+payload
        increment (state) {
            state.count += 1
        },


        //store里面有一个state数据,这是一个对象,对象里面含有count数据
        //当点击加号的时候,count=count+payload
        decrement (state) {
            state.count -= 1
        },
        //异步修改数据第五步:保存数据到仓库,state 是数据
        saveMovie(state,payload){
            state.movieData=payload
            state.flag=false
        },

        modifyFlag:function(state,payload){
            state.flag=payload
        }
    },
    //异步修改数据第四步:action向服务器端请求数据,然后将请求回来的数据保存下来,所以这里向action操作完了之后,要commit action 和payload
    actions:{
        getMovie:function(store, payload){
            var url='https://movie.52kfw.cn/index.php/Api/Movie/alst?page=1&size=20'
            //当第一次向服务器发送网络请求是,浏览器会对数据进行缓存,我们已经有了数据,但是在这里第二次第三次还是会向服务器请求数据,这样太耗费性能
            // 我们可以在向服务器发送网络请求前,判断一下仓库里面有没有数据,如果没有,发送网络请求,如果有,则不发送
            if(store.state.movieData.length>0){
                console.log('数据来自缓存!')
                return
            }

            //loading
            store.commit('modifyFlag', true);

            axios.get(url).then(response=>{
                console.log(response)
                if(response.status=== 200 && response.data.error_code===0){
                    //这里的保存数据的操作是对数据库进行操作,只有mutation才可以操作数据库,所以saveMovie这个方法要写在mutation当中
                    store.commit('saveMovie',response.data.result)
                }
            })
        }
    },


    getters:{
        returnStarBig12w:function(state){
            console.log(state)
            return state.movieData.filter(item =>{
                return item.star>=120000;
            })
        }
    }
})
export default store;

App.use:

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <button @click="decrement">-</button>
    <span>{{ countAias }}</span>
    <button @click="increment">+</button>
    <button @click="clickHandler">获取电影列表</button>

    <div class="loading" v-if="flag">
      <span></span>
      <span></span>
      <span></span>
      <span></span>
      <span></span>
    </div>

    <ul v-for="ele in movieData" v-else>
      <li>{{ ele.id }}</li>
      <li>{{ ele.actors}}</li>
      <li>{{ ele.title}}</li>
    </ul>
    <h2>收藏数大于12w</h2>
    <ul v-for="ele in returnStarBig12w">
      <li>{{ ele.id }}</li>
      <li>{{ ele.actors}}</li>
      <li>{{ ele.title}}</li>
    </ul>
    <router-view/>
  </div>
</template>

<script>
 //可以将仓库里的state映射到组件的data里面(好处:不用写this.$store.state.count这么一大串了),但是需要映射成计算属性才行
 //可以将仓库中的mutations(只能通过这个来修改仓库中的数据)映射到组件的method里面
  import { mapState,mapMutations,mapActions,mapGetters} from 'vuex';
  export default {
    //数据初始阶段就开始了
    created:function() {
      console.log(this.$store);
    },
    computed:{
       //将仓库里的state里的count和movieData映射到组件的data里面
       ...mapState({countAias: 'count',movieData:'movieData',flag:'flag'}),
      ...mapGetters(['returnStarBig12w'])



      //上面这句话的底层原理就是下面这个函数,相当于返回了仓库里的count,好处:1,简洁,2防止重名可以用对象的方式重命名
      // countAias:function(){
      //    return this.$store.state.count
      // }

    },
    methods:{


      //把仓库里面的mutations映射到组件中的methods中
      ...mapMutations(['increment','decrement']),
      //上面这句话的底层原理如下

      //点击网页上的按钮,页面触发一个改变数据的行为,直接使用commit向mutation提交action和payload
 //      increment:function () {
 //   this.$store.commit('increment',10)
 // },
 // decrement:function () {
 //   this.$store.commit('decrement',10)
 // }


      ...mapActions({clickHandler:'getMovie'}),
      //异步修改数据第三步:页面触发一个请求数据的行为,页面dispatch这个行为(action),然后action向服务器端请求数据
      // clickHandler:function(){
      //   this.$store.dispatch('getMovie')
      // },

    }
  }
</script>

<style lang="less">
  ul{
    li{
      list-style: none;
    }
  }
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;

  a {
    font-weight: bold;
    color: #2c3e50;

    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
  .loading{
    width: 80px;
    height: 40px;
    margin: 0 auto;
    margin-top:100px;
  }
  .loading span{
    display: inline-block;
    width: 8px;
    height: 100%;
    border-radius: 4px;
    background: lightgreen;
    -webkit-animation: load 1s ease infinite;
  }
  @-webkit-keyframes load{
    0%,100%{
      height: 40px;
      background: lightgreen;
    }
    50%{
      height: 70px;
      margin: -15px 0;
      background: lightblue;
    }
  }
  .loading span:nth-child(2){
    -webkit-animation-delay:0.2s;
  }
  .loading span:nth-child(3){
    -webkit-animation-delay:0.4s;
  }
  .loading span:nth-child(4){
    -webkit-animation-delay:0.6s;
  }
  .loading span:nth-child(5){
    -webkit-animation-delay:0.8s;
  }

</style>