从壹开始先后端分离 [ Vue2.0+.NET Core2.1] 二十三║Vue实战:Vuex 其实很简单

前言

哈喽你们周五好,立刻又是一个周末了,下周就是中秋了,下下周就是国庆啦,这里先祝福你们一个比一个假日嗨皮啦~~转眼咱们的专题已经写了第 23 篇了,好几回都坚持不下去想要中断,不过每当看到群里的交流,看到博客下边好多小伙伴提出问题,我又燃起了斗志,不过这两天感冒了,因此更新的比较晚,这里也提醒你们,节日要照顾好本身哟~~~,好多人说我写的上不了台面,哈哈这里表示赞同,本系列的宗旨就是,给你们一个学习的点,让你们去自学一个面,而后你们一块儿学,把面交流成一个立体,就达到一个体系了。好啦,言归正传(一直告诫本身,不能写心情贴,哈哈要写技术文章),昨天呢,不知道有几个小伙伴按照教程把本身的以前的 .net core api 教程里的项目给展现出来了呢,必定要本身动手试试哟,只要成功了,就是棒棒哒,今天我们继续往下走,来讲说一个一直让人头大的东西,就是表单以及 Vuex的使用,好啦,开始今天的讲解!html

 

零、今天要完成实战1中的红色部分

 

1、常见的 Vue 表单提交是如何设计的?

说到了 Web开发,必定几乎全部人都能说到表单提交,这个是真的少不了,并且也让人写的头晕眼花,心身疲惫,天然在 Vue 开发中,也是少不了的一部分工做,常见的表单是什么样子的呢?vue

一、表单、按钮等在一个组件内

这个时候机智如你必定会说:这有什么难的是吧,Vue 提供了完美的 双向数据绑定,能够很好的实现数据的更新、获取和提交,嗯~没错,你说的很对,咱们不再用费心的操做 DOM 了,用户填好数据就能够直接 axios 到 后端api接口了,多好,固然,这也是一个处理方式。webpack

这里的代码就不写了,很简单,把全部的写到一个页面内就行,你们能够本身试一试。ios

但是想想,若是页面内有不少组件,有不少的表单,或者更直接点儿,想要表单单独是一个组件用做弹窗,你会怎么办呢~为何呢?git

 

二、按钮在父组件、表单在单独的子组件内

这种开发利于开发,易于维护,但是就是不适合数据传输,由于父子组件内的数据通信是很麻烦的,虽然 Vue 支持双向数据绑定,可是父子通信是:组件之间的数据只能是单项流通的,并且由父组件传递给子组件,若是你看过我以前写的文章,有关组件的《从壹开始先后端分离 [ Vue2.0+.NET Core2.1] 二十║Vue基础终篇:组件详解+项目说明》,你应该知道,之因此这么麻烦 , 是由于父组件能够经过 props 给子组件传递参数 , 但子组件内却不能直接修改父组件传过来的参数。只能经过自定义方法,向上提交时数据,今天,我们说下第二种方法,子组件可使用 $emit 触发父组件的自定义事件。github

 

2、经过 $emit 修改父组件数据

还个方法的本质的经过自定义事件的方式,把子组件的值,经过参数的形式广播到父组件去,而后父组件接收,我在以前的文章中有详细的讲解,请看《从壹开始先后端分离 [ Vue2.0+.NET Core2.1] 二十║Vue基础终篇:组件详解+项目说明》章节——组件传值 子传父。web

这里说说说说这两种方式ajax

一、在原来代码里 About.vue 修改为 Form.vue

注意,若是你是使用 Webstorm 的话,重命名的时候,会自动的把固然文件的所有应用的地方都会修改(举栗子:router 中的名字),若是是手动修改的文件夹中的,请确保其余地方都被修改了。vue-router

在 Form.vue 组件内,添加如下代码vuex

<!-- 父组件 Form.vue -->

<template>
    <div class="parent">
        <h3>问卷调查</h3>
       <!-- 注意这里,formData是自定义属性,用来向子组件传递数据,若是要想被子组件控制,必须加上 .sync,
请注意,如今新版本的vue能够不用写.sync-->
<child :formData.sync="form"></child> <div class=""> <p>姓名:{{form.name}}</p> <p>年龄:{{form.age}}</p> <p>地址:{{form.address}}</p> </div> </div> </template> <script> import child from "../components/dialog.vue";//导入子组件 export default { components: { child }, data: function() {//定义返回data return { form: { name: "", namePla: "姓名不能为空", address: "", age: "" } }; } }; </script>

 

二、在 components 文件夹内,添加窗口子组件 dialog.vue(之因此叫窗口,就是你能够把它设计成弹窗)

<!-- 子组件 dialog.vue -->

<template>
    <div class="child">
        <label>
            姓名:<input :placeholder="form.namePla" type="text" v-model="form.name">
        </label>
        <label>
            年龄:<input type="text" v-model="form.age">
        </label>
        <label>
            地址:<input type="text" v-model="form.address">
        </label>
    </div>
</template>

<script>
export default {
  data: function() {//子组件返回data
    return {
      form: {
        name: "",
        namePla: "",
        age: "",
        address: ""
      }
    };
  },
  props: {
    // 这个 prop 属性用来接收父组件传递进来的值
//这么写是为了说明,接受参数能够指定参数类型,你能够直接[“formData”]来接收,可是这个方法必须了解
formData: Object//对象的形式 }, watch: { // 由于不能直接修改 props 里的属性,因此不能直接把 formData 经过v-model进行双向绑定到 input 上 // 在这里咱们须要监听 formData,当它发生变化时,当即将值赋给 data 里的 form,由于 from 能够用来 绑定 input,就好像增长了一个跳板 formData: { immediate: true, handler(val) { this.form = val; } } }, }; </script>

 

这里要说下 几个概念:
一、watch : 用来监听 父组件传递过来的值,当传递过来的时候,赋给 form,只有子组件的 from 才能够双向绑定 DOM

二、mounted : 挂载完成后执行,若是有不明白的小伙伴,能够看看我以前的有关生命周期的文章 —— 《从壹开始先后端分离 [ Vue2.0+.NET Core2.1] 十九║Vue基础: 样式动态绑定+生命周期》。

三、$emit : this.$emit("自定义事件名",要传送的数据),用来触发父组件的自定义事件,这里不是很明白不要紧,由于它要配合 .sync 来使用。(注意:若是你在父组件里写了一个事件,这里就是那个事件的名字)

四、.sync : .sync 修饰符所提供的功能。当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定,就是说咱们能够直接在咱们须要传的 prop 后面加上 .sync。也就是说咱们在子组件内,用过 update:formData 来改变了父组件的 属性 prop 的值,经过 .sync 来同步到了父组件的 form 对象里。嗯~大概就是这个意思。官网 :地址

五、 update:my-prop-name 的模式触发事件。举个栗子,在一个包含 title prop 的假设的组件中,咱们能够用如下方法表达对其赋新值:

this.$emit('update:formData', newData)

而后父组件能够监听那个事件并根据须要更新一个本地的数据属性。例如:

<text-document
  v-bind:formData="form"
  v-on:update:formData="form = $event"
></text-document>

为了方便起见,咱们为这种模式提供一个缩写,即 .sync 修饰符:是否是和上边的是同样的

<text-document  v-bind:formData.sync="form"></text-document>

 

详细的过程:

 

 

三、这个时候,看咱们的项目,结果就出来了 

不只能够把父组件的 ”姓名不能为空“传递到子组件,还能够,把子组件内的数据发送到父组件,是否是感受很神奇?!并且也能够作成一个弹窗的,你们能够本身试试。

可是呢,这里是一个小 DEMO 还好,要是多的话,要设置总感受不是很舒服,还须要 用到那么多的新的东西,欸!机智如你, Vuex 就这么登台了。

 

3、使用 Vuex 来实现父子通信

一、老规矩,什么是 Vuex?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。说人话就是,它就像是一个容器,一个第三方,咱们能够把内容存进去,而后在别的任何地方去取出来,这个是否是正好就是咱们的父子组件通信?!你们再看看上面,父子组件之间的通讯是否是比较麻烦,改变数据还要用$emit。若是有一个地方跟仓库同样就存放着form的值,谁要用谁去请求form的值,谁想改就改该多好是吧,vuex就是一个管理仓库,有点全局变量的意思。任何组件须要拿,改东西,均可以找他。

 

更新:2019-07-03 —— 为何要使用 Vuex ?

 

在上边的开发过程当中,咱们必定能感受到如下几个问题:

 
一、props 传参的方法对于多层嵌套的组件很是繁琐,有些须要从 App.vue -> List.vue -> Item.vue ,这样都太乱了。
二、上边咱们仍是在有关联的父子之间传值(固然爷孙也是如此),那对于兄弟组件间的数据传递,咱们该怎么办呢?
三、若是你说可使用 storage 的话,有个很大的弊端,就是没法响应式,不信你能够试试。
 

 

欸,这个时候就是 Vuex 的表现的时候了。

下面是vuex的一些解释:

 
一、vuex有哪几种属性?
答:有五种,分别是 State、 Getter、Mutation 、Action、 Module
 
二、vuex的State特性是?
答:
1、Vuex就是一个仓库,仓库里面放了不少对象。其中state就是数据源存放地,对应与通常Vue对象里面的data
2、state里面存放的数据是响应式的,Vue组件从store中读取数据,如果store中的数据发生改变,依赖这个数据的组件也会发生更新
3、它经过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
 
三、vuex的Getter特性是?
答:
1、getters 能够对State进行计算操做,它就是Store的计算属性
2、 虽然在组件内也能够作计算属性,可是getters 能够在多组件之间复用
3、 若是一个状态只在一个组件内使用,是能够不用getters
 
四、vuex的Mutation特性是?
答:
1、Action 相似于 mutation,不一样在于:
2、Action 提交的是 mutation,而不是直接变动状态。
3、Action 能够包含任意异步操做
 
五、Vue.js中ajax请求代码应该写在组件的methods中仍是vuex的actions中?
答:
1、若是请求来的数据是否是要被其余组件公用,仅仅在请求的组件内使用,就不须要放入vuex 的state里。
2、若是被其余地方复用,这个很大概率上是须要的,若是须要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。若是不要复用这个请求,那么直接写在vue文件里很方便。

 

二、首先咱们须要安装 Vuex

利用npm下载vuex包,在命令行工具中输入如下命令,cd到你的项目目录

npm install vuex --save

 

三、还记得那个 store.js 么,终于用到了,修改内容

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

Vue.use(Vuex);

const store = new Vuex.Store({
  // 初始化的数据
  state: {
    formDatas: null//定义一个变量 formDatas
  },
  // 改变state里面的值得方法
  mutations: {
    getFormData(state, data) {
      state.formDatas = data;
    }
  }
});
// 输出模块
export default store;

 

四、在 views 文件夹下,新建 FormVuex.vue 页面

内容和 Form.vue 主要内容差很少

<!-- 父组件 parent.vue -->

<template>
    <div class="parent">
        <h3>问卷调查</h3>
        <child ></child><!-- 注意: 这里已经没有 .sync 了 -->
        <div class="">
            <br>
            <br>
            <p>数据:{{_fatherData}}</p>//感谢网友 @Mr.TangHao 的纠错
        </div>
    </div>
</template>

<script>
import child from "../components/dialogVuex.vue";

export default {
  components: {
    child
  },
  data: function() {
    return {
      form: {
        name: "",
        namePla: "姓名不能为空",
        address: "",
        age: ""
      }
    };
  },
  computed: {//挂载完成后
    _fatherData() {//获取全局 store 仓库中的 formDatas 值 // 读取store里面的值,这里是重点
      return this.$store.state.formDatas;
    }
  }
};
</script>

 

五、在 components 文件夹下,新增 dialogVuex.vue 页面

<!-- 子组件 child.vue -->

<template>
    <div class="child">
        <label>
            姓名:<input  type="text" v-model="form.name">
        </label>
        <label>
            年龄:<input type="text" v-model="form.age">
        </label>
        <label>
            地址:<input type="text" v-model="form.address">
        </label>
    </div>
</template>

<script>
export default {
  data: function() {
    return {
      form: {
        name: "",
        namePla: "",
        age: "",
        address: ""
      }
    };
  },
  mounted() {
    // 将数据提交到 store
    this.$store.commit('getFormData', this.form)//感谢网友 @Mr.TangHao 的纠错
  }
};
</script>

 

六、修改 App.vue 和 路由 router.js,提供 Vuex 页面入口

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import FormVuex from "./views/FormVuex.vue";

Vue.use(Router);

export default new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "home",
      component: Home
    },
    {
      path: "/Vuex",
      name: "Vuex",
      component: FormVuex
    },
    {
      path: "/about",
      name: "about",
      // 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/Form.vue")
    }
  ]
});

 

七、浏览页面,搞定!

就这样就完成啦!是否是很简单,原理就是:在子组件内,把双向数据绑定的数据,提交到 store 里,而后再在父组件里获取,剩下的你们能够在处理

 

 

4、其余扩展

一、store.js 各部分单独管理

从上边能够看出,虽然咱们的 store 单独在一个文件里,那组件多了以后 , 状态也多了 , 这么多状态都堆在 store.js 很差维护怎么办 ?

咱们可使用 vuex 的 modules , 把   store.js 改为 :(感谢群小伙伴@宝 的纠错)

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

import dialog_store from './components/dialog_store.js';//引入某个store对象

export default new Vuex.Store({
    modules: {
        dialog: dialog_store
    }
})

这里咱们引用了一个 dialog_store.js , 在这个 js 文件里咱们就能够单独写 dialog 组件的状态了 :

export default {
   state: {
    formDatas: null
  },
  // 改变state里面的值得方法
  mutations: {
    getFormData(state, data) {
      state.formDatas = data;
    }
  }
}

作出这样的修改以后 , 咱们将以前咱们使用的 $store.state.formDatas 通通改成 $store.state.dialog.formDatas 便可。这个你们能够自由的尝试,这里就不一一说明了。

二、什么状况下我应该使用 Vuex?

虽然 Vuex 能够帮助咱们管理共享状态,但也附带了更多的概念和框架。这须要对短时间和长期效益进行权衡。

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

 

三、其余扩展问题补充中

 

5、结语

 今天由于时间的问题,就暂时说到了这里,是否是感受很简单,这个就是 vuex 的使用,固然,还有其余的一些扩展使用,我尚未来得及准备,明天就是周末了,我再整理后,再修改下吧,若是你以上的都看懂了,那父子组件通信,各类表单提交,你已经没有问题啦~好啦下次再见咯。

 

6、CODE

https://github.com/anjoy8/Blog.Vue

注意:若是下载好了,首先须要 执行 npm install 安装依赖

请确保已经把 webpack 和 vue-cli 都安装了。