Vuex学习笔记

教程来源:https://www.bilibili.com/video/av39088530/?spm_id_from=333.788.videocard.11

前言:概念

1.什么是Vuex

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

2.什么情况下我应该使用 Vuex?

Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。

如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。

一.Vuex快速安装和使用

1.直接下载 / CDN 引用

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@3.1.1/dist/vuex.js"></script>

2.NPM

npm install vuex --save

在一个模块化的打包系统中,您必须显式地通过 Vue.use() 来安装 Vuex:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

二.开始

最简单的 Store

1.html中构建

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vuex的安装</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex@3.1.1/dist/vuex.js"></script>
</head>
<body>

<script>
    const store = new Vuex.Store({
        state: {
            count: 0
        },
        mutations: {
            increment (state) {
                state.count++
            }
        }
    })
</script>
</body>
</html>

然后进入浏览器中,打开管理台,输入以下代码

第一个程序成功完成

2.模块化工具中构建

(1).项目创建并初始化项目(创建package.json):创建文件夹、js文件

初始化项目:命令行输入npm init -y

(2).安装vue、vuex:命令行npm install vue vuex

(3).导入vue、vuex。这里有两种导入方式

  • const方式

const Vue = require("vue")
const  Vuex = require("vuex")

Vue.use(Vuex)
const store = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})
console.log(store.state.count);
store.commit("increment");
console.log(store.state.count);

然后命令行:node index.js

运行结果:

  •  import方式

首先将index.js文件放入src路径下(如果没有该路径,则创建)

import Vue from "vue"
import Vuex from "vuex"

Vue.use(Vuex)
const store = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})

console.log(store.state.count);
store.commit("increment");
console.log(store.state.count);

直接在命令行中输入npm run build 编译,此时会报错

此时需要安装webpack进行编译:npm install -D webpack webpack-cli,然后在package.json文件中新建一个脚本

命令行输入:npm run build  完成项目编译,此时项目中出现dist路径,并且main.js

最终运行:node  dist/main.js

其中黄色字体WARNING:

其意思就是   配置警告:“模式”选项没有设置,webpack将回退“生产”这个值。将“mode”选项设置为“development”或“production”,以便为每个环境启用默认值。

此时有两种解决方案:

方案一:在package.json文件中添加

之后再重新编译npm run build,就不会出现警告了

方案二:

在package.json同一级目录下创建webpack.config.js文件

module.exports = {
    entry:"./src/index.js",
    mode:"development"
}

再在package.json中定义一个build2:

最后编译npm run build2,就不会出现警告了

三.使用webpack工程化vuex

1.创建项目结构

2.初始化项目

yarn 命令安装:npm install -g yarn

yarn init -y,此时会产生一个package.json

更改package.json

其中index.js

const store = new Vuex.Store({
    state: {
        count: 8000,
        message:"Hello Vuex!!!"
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})

const Counter = {
    template:"<div>{{sayHi}}----{{totalData}}----{{count}}----{{message}}</div>",
    data(){
        return{
            dataStart:100
        }
    },
    // 方式一
    /*computed:{
        count(){
            return store.state.count;
        }
    }*/
    // 方式二
    /*computed:Vuex.mapState(["count","message"])*/
    // 方式三
    /*computed:Vuex.mapState({
        count:"count",
        message:"message"
    })*/
    // 方式四
    computed:{
        sayHi(){
            return "Hi!!!!"
        },
        ...Vuex.mapState({
            count:(state)=>state.count,
            message:function (state) {
                return state.message
            },
            // 为了能够使用 `this` 获取局部状态,必须使用常规函数
            totalData:function (state) {
                return this.dataStart+state.count
            }
        })
    }
}
const app = new Vue({
    el:"#app",
    store,
    components:{Counter},
    template: '<div class="app"><counter></counter></div>   '
})

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vuex</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

安装vue、vuex:yarn add vue vuex

js文件中导入vue、vuex

此时需要安装webpack进行编译:yarn  add  -D webpack webpack-cli

在package.json同一级目录下创建webpack.config.js文件

module.exports = {
    entry:"./src/index.js",
    mode:"development"
}

此时目录中有dist文件夹,同时有main.js,但是没有html文件,此时需要依赖webpack的一个插件html-webpack-plugin,安装

yarn  add -D html-webpack-plugin

然后在webpack.config.js文件中导入,并定模板

const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
    entry:"./src/index.js",
    mode:"development",
    plugins:[
        new HtmlWebpackPlugin({
            template:"./src/index.html"
        })
    ]
}

再次编译,最终出现index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vuex的安装</title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="main.js"></script></body>
</html>

 

运行dist/index.html,打开控制台,报错

此时需要在webpack.config.js文件中,用resolve解决一个冲突

重新编译

提高开发效率,安装webpack-dev-server插件yarn add -D webpack-dev-server,并在package.json文件中添加代码

运行yarn dev

此时在浏览器中输入:http://localhost:8080/即可访问

3.代码分离

由于一个工程中代码非常多,所以还得代码分离,意思就是将vuex的代码专门放在一个js文件中

在src目录下,新创建一个store.js并将index.js中的一部分代码添加到store.js中

import Vuex from "vuex"

function creatStore() {
    return new Vuex.Store({
        state: {
            count: 8000,
            message:"Hello Vuex,This is webpack!"
        },
        mutations: {
            increment (state) {
                state.count++
            }
        }
    })
}
export default creatStore;

在src目录下,新创建一个components文件夹,并在其里面新创建一个counter.js并将index.js中的一部分代码添加到counter.js中

import Vuex from "vuex";

const Counter = {
    template:"<div>{{sayHi}}----{{totalData}}----{{count}}----{{message}}</div>",
    data(){
        return{
            dataStart:100
        }
    },
    // 方式一
    /*computed:{
        count(){
            return store.state.count;
        }
    }*/
    // 方式二
    /*computed:Vuex.mapState(["count","message"])*/
    // 方式三
    /*computed:Vuex.mapState({
        count:"count",
        message:"message"
    })*/
    // 方式四
    computed:{
        sayHi(){
            return "Hi!!!!"
        },
        ...Vuex.mapState({
            count:(state)=>state.count,
            message:function (state) {
                return state.message
            },
            // 为了能够使用 `this` 获取局部状态,必须使用常规函数
            totalData:function (state) {
                return this.dataStart+state.count
            }
        })
    }
}
export default Counter;

index.js中并导入这两个文件

import Vue from "vue"
import Vuex from "vuex"
import creatStore from "./store"
import Counter from "./components/counter"

Vue.use(Vuex)

const store = creatStore()


const app = new Vue({
    el:"#app",
    store,
    components:{Counter},
    template: '<div class="app"><counter></counter></div>   '
})

最后运行看效果,Perfect!!!

四.Getter

对state中的数据派生出一些状态,例如对数据进行过滤。(可以认为是store中的计算属性),会对state中的变量进行过滤再保存,只要state中的变量发生了改变,它也会发生变化,不变化的时候,读的缓存。

<DOCTYPE !>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuex的Getter</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
</head>
<body>
<div id="app"></div>
<script>
    const store = new Vuex.Store({
        state: {
            todos:[
                {id:1, name:"读书1小时", done:false},
                {id:2, name:"B站看跟山地人学Vuex",done:true },
                {id:3, name:"找山地人加微信",done:true },
                {id:4, name:"反馈意见和建议",done:true },
                {id:5, name:"跑步1小时",done:false },
            ]
        },
        getters:{
            doneTodos(state){
                return state.todos.filter(todo=>todo.done)
            },
            doneTodosCount(state,getters){
                return  getters.doneTodos.length
            },
            getTodoById:(state)=>{
                return (id)=>{
                    return state.todos.find(todo=>todo.id===id)
                }
            }
        },
        mutations: {
            increment (state) {
                state.count++
            }
        }
    })
    const Counter = {
        template:'<div><div>当前任务{{curTodo.id}}:{{ curTodo.name }}</div> <p> 今日已完成{{ doneTodosCount }}件事 </p> <ul><li v-for="todo in doneTodos" :key="todo.id">{{todo.name}}</li></ul> </div>',
        data(){
            return {
                start:5,
            }
        },
        // 改造前
        /*computed:{
            doneTodos(){
                return this.$store.getters.doneTodos
            },
            doneTodosCount(){
                return this.$store.getters.doneTodosCount
            },
            curTodo(){
                return this.$store.getters.getTodoById(3)
            }
        },*/
        //改造后 mapGetters
        computed:{
            ...Vuex.mapGetters(["doneTodos","doneTodosCount"]),
            curTodo(){
                return this.$store.getters.getTodoById(3)
            }
        }
    }
    const app = new Vue({
        el:"#app",
        store,
        components:{ Counter },
        template:'<div class="app"><counter></counter></div>'
    })

</script>
</body>
</html>

五.Mutations

Vue的视图是由数据驱动的,也就是说state里面的数据是动态变化的,那么怎么改变呢,切记在Vuexstore数据改变的唯一方法就是mutation!通俗的理解mutations,里面装着一些改变数据方法的集合,这是Veux设计很重要的一点,就是把处理数据逻辑方法全部放在mutations里面,使得数据和视图分离。

六.Action

在mutation中我们讲到,mutation中是存放处理数据的方法的集合,我们使用的时候需要commit。但是commit是同步函数,而且只能是同步执行。在actions中提交mutation,并且可以包含任何的异步操作。actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据(但是还是通过mutation来操作,因为只有它能操作)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Action</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>

</head>
<body>
<div id="app"></div>
<script>
    const Counter = {
        /*methods:{
          addCount(){
              this.$store.dispatch("increment",{count:1})
          }
        },*/
        /*methods:Vuex.mapActions({
            addCount:"increment"
        }),*/
        //与下面的 <button @click="increment">ADD</button> 对应
        methods:Vuex.mapActions(["increment"]),
        template:`
            <div>
                <h1>{{ $store.state.count }}</h1>
                <!--<button @click="addCount">ADD</button>-->
                <button @click="increment">ADD</button>
            </div>
        `
    }

    const store = new Vuex.Store({
        state: {
            count: 1
        },
        mutations: {
            increment (state) {
                state.count++
            }
        },
        actions:{
            increment(context) {
                context.commit("increment");
            },
            incrementAsync({commit}){
                setInterval(()=>{
                    commit('increment')
                },1000)
            }
        }
    })

    const app = new Vue({
        el:"#app",
        store,
        computed:Vuex.mapState(["count"]),
        components:{
            Counter
        },
        template:`
            <div>
                <h1><counter></counter></h1>
            </div>
        `
    })
    /*store.dispatch("incrementAsync")*/
</script>
</body>
</html>

七.Module

在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理。module则可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Module</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex@3.1.1/dist/vuex.js"></script>
</head>
<body>

<script>
    const userModule = {
        state:{
            user:{
                name:"calmLyx",
                gender:"male",
                age:"22",
                tel:"15222222222"
            },
            products:[],
            orders:[]
        }
    }
    const homeModule = {
        state:{
            cities:[
                "四川",
                "重庆",
                "贵州",
                "陕西",
                "广东"
            ],
            home:{}
        }
    }
    const shopcartModule = {
        state:{
            count:0,
            shopcart:[
                { id:1,name:"机械师T58-V 全面屏游戏本",count:1},
                { id:2,name:"漫步者(EDIFIER) 游戏头戴式耳机",count:2},
                { id:3,name:"魔炼者 1505 机械键盘",count:5},
                { id:4,name:"银雕 无线无声鼠标",count:8},
                { id:5,name:"金士顿 64G 黑色U盘",count:3}
            ]
        },
        mutations: {
            increment (state) {
                // 这里的 `state` 对象是模块的局部状态
                state.count++
            }
        },

        getters: {
            doubleCount (state) {
                return state.count * 2
            }
        },
    }

    const store = new Vuex.Store({
        modules:{
          user:userModule,
          home:homeModule,
          shopcart:shopcartModule,
        },
        mutations: {
            increment (state) {
                state.count++
            }
        }
    })
</script>
</body>
</html>

八.项目结构

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中。

  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。

  3. 异步逻辑都应该封装到 action 里面。

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:官方实例

九.插件

     内置 Logger 插件

Vuex 自带一个日志插件用于一般的调试:

import createLogger from 'vuex/dist/logger'

const store = new Vuex.Store({
  plugins: [createLogger()]
})

十.严格模式

开启严格模式,仅需在创建 store 的时候传入 strict: true

const store = new Vuex.Store({
  // ...
  strict: true
})

在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

开发环境与发布环境

不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失。

类似于插件,我们可以让构建工具来处理这种情况:

const store = new Vuex.Store({
  // ...
  strict: process.env.NODE_ENV !== 'production'
})

十一.对表单的处理

当在严格模式中使用 Vuex 时,在属于 Vuex 的 state 上使用 v-model 会比较棘手:

<input v-model="obj.message">

假设这里的 obj 是在计算属性中返回的一个属于 Vuex store 的对象,在用户输入时,v-model 会试图直接修改 obj.message。在严格模式中,由于这个修改不是在 mutation 函数中执行的, 这里会抛出一个错误。

<html>
    <head>
        <title>课15.Vuex的表单处理</title>
        <script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
    </head>
    <body>
        <div id="app"></div>
        <script>
            
           const store = new Vuex.Store({
                strict: true,
                state: {
                    count: 0
                },
                mutations: {
                    increment (state) {
                        state.count++
                    },
                    updateCount(state,value){
                        if(value && value!=""){
                            state.count= parseFloat(value)
                        }
                        
                    }
                }
            })
       
            const app = new Vue({
                el:'#app',
                store,
                computed:{
                    count:{
                        get(){
                            return this.$store.state.count;   
                        },
                        set(value){
                            this.$store.commit("updateCount",value)
                        }
                    }
                },
                methods:{
                    updateMessage(e){
                        const value = e.target.value
                        console.log(value)
                        this.$store.commit("updateCount",value)
                    }
                },
                template:`
                    <div>
                        <h1>{{  $store.state.count }}</h1>
                        <div>
                            <span>v-model</span>
                            <input v-model="$store.state.count">
                        </div>
                        <div>
                            <span>:value+@input</span>
                            <input :value="count" @input="updateMessage">
                        </div>
                        <div>
                            <span>v-model Vuex</span>
                            <input v-model="count">
                        </div>
                    </div>
                `
            })
        </script>
    </body>
</html>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值