vue 简单版状态机(vuex)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue 简单版状态机(vuex)相关的知识,希望对你有一定的参考价值。

参考技术A index.js

import service from '../service.js';

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store(

  state:

    /**

     * 是否需要强制登录

     */

    forcedLogin: true,

    hasLogin: false,

    userName: "",

msg:

  ,

  mutations:

    login(state, userName)

      state.userName = userName || '新用户';

      state.hasLogin = true;

    ,

    logout(state)

      state.userName = "";

      state.hasLogin = false;

service.removeUser();

    ,

setmsg(state, msg)

state.msg = msg



  

)

export default store

———————————————————————————————————————————————————————————————

引入:import

             mapState,

             mapMutations

           from 'vuex'

设置值:

              methods:

                    ...mapMutations(['login', 'setmsg']),

             

              let userMsg =

                       user_grade: data.data.user_grade,

                       discount_rate: data.data.discount_rate

             

  that.setmsg(userMsg);

获取值:

            computed:

                ...mapState(['forcedLogin', 'hasLogin', 'userName','msg']),

           

            this.msg(就可以出来了)

vue-cli安装以及创建一个简单的项目(vuex使用)

1.vuex的使用

  vuex是vue的状态管理中心,vuex来保存我们需要管理的状态值,值一旦被修改,所有引用该值的地方就会自动更新,常用于:

1.多个视图依赖同一状态(l例:菜单导航)

2.来自不同视图的行为需要变更同一状态(例如评论弹幕)

 

上篇创建的vue项目目录结构:

 

  在上一节我们已经安装了vuex模块。查看store/index.js内容,如下:

import Vue from \'vue\';
import Vuex from \'vuex\';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  },
});

  上面引入Vue模块和Vuex模块,并将Vuex安装到Vue中。

 

下面使用vuex。在Test路由中改变值,在about模块中接收,代码如下:

(1)修改store/index.js

import Vue from \'vue\';
import Vuex from \'vuex\';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    count: 0,
  },
  mutations: {
    increase() {
      this.state.count = this.state.count + 1;
    },
  },
  actions: {
  },
  modules: {
  },
});

  定义一个状态count,mutations中是修改状态的唯一入口。

(2)修改Test.vue

<template>
  <div class="test">
      这是Test
      <button tybe="button" @click="addOne()">点击我</button>
  </div>
</template>

<script>
import store from \'@/store\';

export default {
  name: \'Test\',
  store,
  methods: {
    addOne() {
      console.log(\'add\');
      store.commit(\'increase\');
    },
  },
};
</script>

  点击按钮的时候调用方法addOne()。addOne()中调用store.commit("increase") 提交该方法进行修改状态,相当于调用 Vuex.Store 实例的 increase() 方法。

(3)修改About.vue接收状态count

<template>
  <div class="about">
    <h1>This is an about page</h1>
    {{msg}}
  </div>
</template>

<script>
import store from \'@/store\';

export default {
  name: \'About\',
  store,
  data() {
    return {
      msg: store.state.count,
    };
  },
};
</script>

(4)测试:

补充:关于vuex调用函数传递参数。比如我们传递一个username参数到vuex中,如:

store/index.js:

import Vue from \'vue\';
import Vuex from \'vuex\';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    username: \'\'
  },
  mutations: {
    setLoginUsername(state, username) {
      state.username = username
    },
  },
  actions: {
    setLoginUsernameFun(context, username) {
      context.commit("setLoginUsername", username);
    },
  },
  modules: {
  },
});

调用方法如下:(登录成功之后跳转到首页并记录登录的用户)=如下面红色代码

    login() {
      this.isReg = false;
      var nameLocal = localStorage.getItem("name");
      var passwordLocal = localStorage.getItem("name");
      if (nameLocal == \'\' || passwordLocal == \'\') {
        alert("您还没注册!");
        return;
      }

      if (nameLocal === this.name || passwordLocal === this.password) {
        store.dispatch("setLoginUsernameFun", nameLocal);
        this.$router.push(\'/home\')
        return;
      }

      alert("账号或者密码错误");
    },

 

补充:vueX的五个核心属性

(1)state:

state即Vuex中的基本数据!
state就是用来存放数据,若是对数据进行处理输出,比如数据要过滤,一般我们可以写到computed中。

(2)getters(相当于State的计算属性) :

基础用法:

index.js

const store = new Vuex.Store({
  state: {
    list: [1, 3, 5, 7, 9, 20, 30]
  },
  getters: {
    filteredList: state => {
      return state.list.filter(item => item > 5)
    },
    listCount: (state, getters) => {
      return getters.filteredList.length;
    }
  }
})

vue中:

<template>
 
  <div>
    过滤后的列表:{{list}}
    <br>
    列表长度:{{listCount}}
  </div>
</template>
 
<script>
  export default {
    name: "index.vue",
    computed: {
      list() {
        return this.$store.getters.filteredList;
      },
      listCount() {
        return this.$store.getters.listCount;
      }
    }
  }
</script>

(3)mutation(提交更改数据的方法,同步!必须是同步函数) 

使用vuex修改state时,有两种方式:
1)可以直接使用 this.$store.state.变量 = xxx;
2)this.$store.dispatch(actionType, payload)或者 this.$store.commit(commitType, payload)
异同点:
1)共同点: 能够修改state里的变量,并且是响应式的(能触发视图更新)
2)不同点:
若将vue创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过mutation的函数,
vue就会 throw error : [vuex] Do not mutate vuex store state outside mutation handlers。

(4)action(像一个装饰器,包裹mutations,使之可以异步。) 

action的功能和mutation是类似的,都是去变更store里的state,不过action和mutation有两点不同:
1)action主要处理的是异步的操作,mutation必须同步执行,而action就不受这样的限制,也就是说action中我们既可以处理同步,也可以处理异步的操作
2)action改变状态,最后是通过提交mutation。

  Action 通过 store.dispatch 方法触发。

(5)modules ( 模块化Vuex):

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

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

 

2. 打包vue项目并制作成app

  vue-cli3之后的打包与之前不一样,配置文件在vue.config.js中,并且这个文件需要自己创建置于与package.json同目录。关于其配置项可参考:

 

如果想打包之后静态页面直接点击运行需要将路由改为hash路由:

(1)修改router/index.js

const router = new VueRouter({
  mode: \'hash\',
  base: process.env.BASE_URL,
  routes,
});

 

(2)vue.config,js修改打包的默认路径:

module.exports = {
  publicPath:  \'./\',
  lintOnSave: false
}

   如果将来我们将页面置于项目中,项目名称为exam,我们将publicPath修改为exam即可。默认是/,./是相对路径。

  lintOnSave: false 是关闭eslint验证(这个验证太烦了)

 

  接下来到项目根路径运行打包命令即可得到正常的html、css等文件。如下:

E:\\HBuilderSpace\\vue-demo>npm run build

> vue-demo@0.1.0 build E:\\HBuilderSpace\\vue-demo
> vue-cli-service build


-  Building for production...

 DONE  Compiled successfully in 51657ms


  File                                 Size               Gzipped

  dist\\js\\chunk-vendors.ae7fcf93.js    125.21 KiB         43.38 KiB
  dist\\js\\app.628ec198.js              7.19 KiB           2.75 KiB
  dist\\js\\about.672d2588.js            1.32 KiB           0.59 KiB
  dist\\css\\about.b0b00f5a.css          0.57 KiB           0.31 KiB
  dist\\css\\app.59544d79.css            0.21 KiB           0.15 KiB

 

打包后会生成dist目录,并且对文件都进行了压缩,如下:

 index.html内容如下:(原本是一行,这是我格式化后的。可以看到路径是相对路由)

<!DOCTYPE html>
<html lang=en>
<head>
    <meta charset=utf-8>
    <meta http-equiv=X-UA-Compatible content="IE=edge">
    <meta name=viewport content="width=device-width,initial-scale=1">
    <link rel=icon href=favicon.ico>
    <title>vue-demo</title>
    <link href=css/about.b0b00f5a.css rel=prefetch>
    <link href=js/about.672d2588.js rel=prefetch>
    <link href=css/app.59544d79.css rel=preload as=style>
    <link href=js/app.628ec198.js rel=preload as=script>
    <link href=js/chunk-vendors.ae7fcf93.js rel=preload as=script>
    <link href=css/app.59544d79.css rel=stylesheet>
</head>
<body>
<noscript><strong>We\'re sorry but vue-demo doesn\'t work properly without JavaScript enabled. Please enable it to
    continue.</strong></noscript>
<div id=app></div>
<script src=js/chunk-vendors.ae7fcf93.js></script>
<script src=js/app.628ec198.js></script>
</body>
</html>

 

2.制作一个简单的基于localStorage本地登录的小app

  用vue制作一个简单的基于本地登录的app,基于hash的路由。

1.目录结构:

 

2.附上主要代码:

App.vue:只定义了入口,在router/index.js中设置默认路由

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style lang="scss">
*{
  padding: 0px;
  text-align: center;
}
</style>

 

Main.js

import Vue from \'vue\';
import App from \'./App.vue\';
import router from \'./router\';
import store from \'./store\';

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App),
}).$mount(\'#app\');

 

router/index.js

import Vue from \'vue\';
import VueRouter from \'vue-router\';
import Login from \'../views/Login.vue\';

Vue.use(VueRouter);

const routes = [
  {
    path: \'/\',
    name: \'login\',
    component: Login,
  },
  {
    path: \'/home\',
    name: \'home\',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ \'../views/Home.vue\'),
    redirect: \'/home/user\',
    children: [{
      path: \'user\',
      name: \'user\',
      component: () => import(/* webpackChunkName: "about" */ \'../views/User.vue\')
    }, {
      path: \'contact\',
      name: \'contact\',
      component: () => import(/* webpackChunkName: "about" */ \'../views/Contact.vue\')
    }]
  },
];

const router = new VueRouter({
  mode: \'hash\',
  base: process.env.BASE_URL,
  linkActiveClass: \'active\',
  routes,
});

export default router;

  定义了默认路由是Login,Login采用一次性加载,其他采用懒加载。登录成功之后的/home重定向到子路由/home/user。

 

store/index.js

import Vue from \'vue\';
import Vuex from \'vuex\';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    username: \'\'
  },
  mutations: {
    setLoginUsername(state, username) {
      state.username = username
    },
  },
  actions: {
    setLoginUsernameFun(context, username) {
      context.commit("setLoginUsername", username);
    },
  },
  modules: {
  },
});

  vuex管理组件定义了一个属性与修改属性的方法

 

vies/Login.vue

<template>
  <div class="login">
    <form v-if="!isReg">
      <h1>欢迎来到XXX系统</h1>
      <br/>
      <br/>
      <div>用户名: <input type="text" v-model="name"/> </div>
      <br/>
      <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码: <input type="password" v-model="password"/> </div>
      <div class="rowBtn" @click="login()">登录</div>
      <div class="rowBtn regBtn" @click="reg()">注册</div>
    </form>
    <form v-else>
      <h1>注册</h1>
      <br/>
      <br/>
      <div>用户名: <input type="text" v-model="name"/> </div>
      <br/>
      <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码: <input type="password" v-model="password"/> </div>
      <br/>
      <div>确认密码: <input type="password" v-model="passwordRepeat"/> </div>
      <div class="rowBtn" @click="addUser()">注册</div>
      <div class="rowBtn regBtn" @click="cancel()">取消</div>
    </form>

  </div>
</template>

<script>
import store from \'@/store\';

export default {
  name: \'login\',
  store,
  data() {
    return {
      isReg: false,
      name: \'\',
      password: \'\',
    };
  },
  methods: {
    login() {
      this.isReg = false;
      var nameLocal = localStorage.getItem("name");
      var passwordLocal = localStorage.getItem("name");
      if (nameLocal == \'\' || passwordLocal == \'\') {
        alert("您还没注册!");
        return;
      }

      if (nameLocal === this.name || passwordLocal === this.password) {
        store.dispatch("setLoginUsernameFun", nameLocal);
        this.$router.push(\'/home\')
        return;
      }

      alert("账号或者密码错误");
    },
    reg() {
      this.isReg = true;
    },
    addUser() {
       if (this.name == \'\' || this.password == \'\') {
         alert("必填用户名密码!!!");
         return;
       }

      if (this.password !== this.passwordRepeat) {
        alert("两次密码不一致!!!");
        return;
      }

      localStorage.setItem("name", this.name);
      localStorage.setItem("password", this.password);
      this.name = \'\';
      this.password = \'\';
      alert("注册成功!");
      this.isReg = false;
    },
    cancel() {
      this.isReg = false;
    }
  },
};
</script>

<style scoped lang="scss">
.rowBtn{
  width: 100%;
  height: 40px;
  font-size: 20px;
  text-align: center;
  line-height: 40px;
  margin-top: 10px;
  background: #87CEEB;

  &.regBtn{
    background: #20B2AA;
  }
}
</style>

  定义了两个表单,登录和注册用的,用isReg属性进行切换。注册成功保存到本地localStorage。

 

views/Home.vue

<template>
  <div class="home">
    <router-view/>
    <ul class="footer">
      <router-link class="icons" to="/home/user">个人中心</router-link>
      <router-link class="icons" to="/home/contact">通讯录</router-link>
    </ul>
  </div>
</template>

<script>
export default {
  name: \'home\',
};
</script>

<style scoped lang="scss">
li{
list-style: none;
}
.footer{
  position: fixed;
  width: 100%;
  height: 60px;
  line-height:60px;
  left: 0px;
  bottom: 0px;
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-around;
}
.icons{
  font-size: 16px;
  flex: 1;
  text-align:center;
  border-top: 1px solid #42b983;
}

a {
  color: #42b983;
    &.active{
     color: #fffVue 组件通信方法 — vuex

详解vuex时光机

Vuex状态机快速了解与应用

一文教会你认识Vuex状态机

一文教会你认识Vuex状态机

Vuex modules的简单使用,Vue状态管理多模块实现