0
点赞
收藏
分享

微信扫一扫

Vuex 结合 iview 做个加法器

码农K 2021-09-24 阅读 71
一、iview 框架的使用

安装依赖:

npm install --save iview

打包时的入口文件,main.js 引用使用:

import iview from "iview";
Vue.use(iview);

为了提高 webpack 打包的速度,我们把 CSS 文件给提取出来放到 index.html 里面,使用 link 标签引入。我们的找到 iview 框架,CSS 样式所在的位置,它的位置就在 node_modules\iview ,在这个文件夹里面找到 styles 这个文件夹,复制到 index.html 同级目录下,之所以要整个样式文件夹是因为里面还有内置的字体,这时打开 index.html 引入这个样式表。
index.html :

  <link rel="stylesheet" href="./styles/iview.css">

到此,配置全部完成。

二、Vuex 安装

每一个 Vuex 应用的核心就是 store(仓库)。“store” 就是一个容器,它包含着你的应用中大部分的状态 (state),可以简单理解为 const store = {"state":{a:1,b:2}}这种简单的对象映射关系。

Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。state 数据更新组件响应的会自动更新。
  2. 不能直接改变 store 中的 state,只能使用 commit 或mutation 更新。

安装依赖:

npm install --save vuex

改变入口文件 main.js:

import Vue from "vue";
import App from "./App";
import Vuex from "vuex";
import iview from 'iview';
import store from "./store/index";
// Vuex作为插件使用
Vue.use(Vuex);
// iview作为插件使用
// 子组件可直接使用iview里面的组件
Vue.use(iview);

new Vue({
    el:"#app",
    render(h){
        return h(App);
    },
    store:new Vuex.Store(store)
});

最后使用此 store:new Vuex.Store(store) 代码,就能做到子组件均可访问 store 里面值。

三、Vuex 的 countstore 和 index 文件

countstore.js 文件里面的配置是特别像 react 的 dva。这个文件里面主要负责数据,和监听。一共由四部分组成。
countstore.js

export default {
    // 命名空间
    namespaced: true,
    // 数据
    state: {
        a: 10
    },
     // 所有可能对数据的改变
    mutations: {
        // 同步
        // commit触发
        add(state,action){
            // state是数据,action表示载荷
            console.log("我是" + action.palyload);
            state.a ++;
        }
    },
    actions: {
        // 异步
        // dispatch触发
        ADD({state,commit},action) {
            console.log("我是" + action.palyload);
            setTimeout(function(){
                commit("add");
            },2000);
        }
    }
};

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。

index.js 文件里面的内容,是为了防止由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就变得相当臃肿,不利于管理。为了解决以上问题,和使模块具有更高的封装度和复用性,Vuex 允许我们将 store 分割成模块(module)可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

import countstore from "./countstore.js";

export default {
    modules : {
        countstore
    }
}

这时引入入口文件。通过 store:new Vuex.Store(store) 这个代码即可使用,子组件可以通识状态容器。

四、加法器和延迟加法器

利用上面配置好的 iview 框架和 vuex 来做个加法器。App.vue 组件里面的业务代码:

<template>
    <div>
        <h1>{{$store.state.countstore.a}}</h1>
        <Button @click = "$store.commit('countstore/add',{'palyload':'同步载荷'})">同步加一</Button>
        <Button @click = "$store.dispatch('countstore/ADD',{'palyload':'异步载荷'})">异步加一</Button>
    </div>
</template>

<script>
    export default {
        
    }
</script>

<style lang="scss" scoped>

</style>

此时浏览器运行的效果:



此处需要注意 commit 和 dispatch 还有一种提交方式,功能是一样的只是写法和上面稍有不同:

<Button @click = "$store.commit({type:'countstore/add','palyload':'同步载荷'})">同步加一</Button>
<Button @click = "$store.dispatch({type:'countstore/ADD','palyload':'异步载荷'})">异步加一</Button>
知识普及

Vuex 是什么?

如果你不会 React 的 redux 看完上图就行了。Flux 的原理是啥我们看看:
Flux将一个应用分成四个部分。

Flux 的最大特点,就是数据的"单向流动"。

Vuex 出现主要是为了解决:

  1. 多个组件共享状态时,单向数据流的简洁性很容易被破坏:
  2. 多个视图依赖于同一状态。

造成代码不好维护。
来自不同视图的行为需要变更同一状态。

摘录:Flux 架构入门教程 - 阮一峰的网络日志

看看下面在入口文件配置的 Vuex 运行时会输出多少?

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";


Vue.use(Vuex);

const store = new Vuex.Store(
    {
        state:{
            name:"Condor Hero"
        }
    }
);
console.log(store.state.name)
new Vue({
    el:"#app",
    render(h){
        return h(App);
    },
    store
});

console.log(store.state.name) 输出 Condor Hero
认识同步异步:

const store = new Vuex.Store(
    {
        state:{
            name:"Condor Hero",
            age:18
        },
        mutations:{
            GetName(state,action){
                console.log(action);
            }
        },
        actions:{
            GetAge({state},action){
                console.log(action)
            }
        }
    }
);
store.commit("GetName","我是一个A");
store.dispatch("GetAge","我是一个B");

合并

const store = new Vuex.Store(
    {
        modules:{
            student:{
                state:{
                    name:"Condor Hero",
                    age:18
                },
                mutations:{
                    GetName(state,action){
                        console.log(action);
                    }
                },
                actions:{
                    GetAge({state},action){
                        console.log(action)
                    }
                }
            }
        }
    }
);
console.log(store.state.student.name)
store.commit("GetName","我是一个A");
store.dispatch("GetAge","我是一个B");

计算属性:

const store = new Vuex.Store(
    {
        state:{
            value: 10
        },
        getters:{
            doneTodos(state){
                return state.value;
            }
        }
    }
);

console.log(store.getters.doneTodos);//10

https://vuex.vuejs.org/zh/guide/hot-reload.html

安装Vue devtools 调试工具:首先必须能访问外网。





当当当,安装完成。 另外需要知道的是没有通过 commit 和 dispatch 改变 state 里面的变量,devtools 是检测不到的。例如这种直接加加的例子:

<el-button @click="$store.state.a++" >按我加一</el-button>

OK,到现在我们使用 Vuex 里面的东西基本都是这样使用的:

this.$store.commit();
this.$store.dispatch()
this.$sotre.getter.xxx
this.$store.state.xxx

看看吧,想要操作 Vuex 竟然要写那么长得字符串,这还是没加上命名空间的,如果加上又得长一节(namespaced:true;为 modules服务)。怎么解决这个书写黑洞,Vuex 提供了辅助函数,大大简化了这个过程,下面来看看Vuex 的四个辅助函数。它们分数别是:

...mapState 映射为 this.$store.state.xxxx
...mapGetters 映射为 this.$store.getters.xxxx
...mapActions 映射为 this.$store.dispatch("xxx",n);
...mapMutations 映射为 this.$store.commit("xxx",n);

其中 mapState 和 mapGetters 写在 computed 里面,mapActions 和 mapMutations 写在methods里面,想想也是很合理的,computed 和 methods 不同有两点,一是 computed 不能传参,二是 computed 有缓存,函数的速度比 methods 里面的更快。这两点恰好也是符合 mapState 和 MapGetters 的,剩下的两个特性自然也是属于 methods 的。

先来看 mapState 的用法:

<template>
    <div>
        <el-button>{{a}}</el-button>
        <el-button>{{$store.state.a}}</el-button>
        <el-button @click="$store.state.a++" >按我加一</el-button>
    </div>
</template>

<script>
    import {mapState} from "Vuex";
    export default {
        computed:{
            ...mapState(["a"])
        },
        methods:{

        }
    }
</script>

... 的意思就是将State里的数据全部展开,括号里的参数就表示你从展开中的数据拿指定的数据放到当前的computed 之中。这种参数是数组的方式有弊端,如果想对数据进行处理的,无法处理,所以一般里面都写成对象:

computed:{
    ...mapState({
        count:state=>state.a
    })
}

现在把计数器每次增加的间隔计为 10:

<template>
    <div>
        <el-button>{{count}}</el-button>
        <el-button @click="$store.state.a++" >按我加一</el-button>
    </div>
</template>

<script>
    import {mapState} from "Vuex";
    export default {
        computed:{
            ...mapState({
                count:state=>{
                    state.a+=10;
                    return state.a;
                }
            })
        },
        methods:{

        }
    }
</script>

猜猜看这个结果输出是多少?



记住我们 的 mapState 通过 ... 语法其实就是把 Vuex 的state拿过来了,所以我们在组件里面进行改写,相应的 Vuex 里面的 state 也发生改变,所以组件一上来就会调用 count 一次,a 这时是 20,当我们 点击 的时候, Vuex 里面的变量 a 先自增一次,变为 ,31。

mapState既然是个对象,我们就可以更加激进的这样写,省的再去强制结构了:

computed:mapState(["a"])
或者这样
computed:Object.assign(mapState(["a"]),mapGetters(["sum"]))

注意:只有mapState能用对象里面跟函数的方式,而其它的辅助函数,后面只能对象里面跟字符串;

再来看看 mapGetters 的使用:这时 a =2
Vuex 里面的 getters :

  getters:{
      sum(state){
          return state.a ** state.a;
      }
  }

在组件里面使用:

<template>
    <div>
        <el-button>{{sum}}</el-button>
    </div>
</template>

<script>
    import {mapGetters} from "Vuex";
    export default {
        computed:{
            ...mapGetters(["sum"])
        }
    }
</script>

得到的结果是:



改写成对象的方法:

computed:{
    ...mapGetters({
        getsum:"sum"
    })
}

再来看看 mapActions 的用法:
组件里面:

<template>
    <div>
        <el-button>{{a}}</el-button>
        <el-button @click="delay({'name':'Condor Hero'})">延迟三秒加十</el-button>
    </div>
</template>

<script>
    import {mapActions,mapState} from "Vuex";
    export default {
        computed:{
            ...mapState(["a"]),
        },
        methods:{
            ...mapActions(["delay"])
        }
    }
</script>

Vuex 里面的 actions:

  actions: {
    delay(context,payload){
        console.log(`负载可以直接传,我能接收到,你传过来的东西是${payload.name}`)
        setTimeout(()=>{
            context.state.a+=10;
        },3000);
    }
  }

得到结果如下:



并且成功打印出来:

负载可以直接传,我能接收到,你传过来的东西是Condor Hero

Action函数的第一个参数和Vuex其他里面的函数不同,Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。

再来看看同步的 mutation :
组件中使用:

<template>
    <div>
        <el-button>{{a}}</el-button>
        <el-button @click="increment({'name':'increment'})">同步加十</el-button>
    </div>
</template>

<script>
    import {mapMutations,mapState} from "Vuex";
    export default {
        computed:mapState(["a"]),
        methods:mapMutations(["increment"])
    }
</script>

对象的写法,请仿照上个 action 写。
Vuex 中使用

  mutations: {
    increment(state,payload){
        state.a += 10;
        console.log(payload.name);
    }
举报

相关推荐

0 条评论