前言
哈喽大家周五好,马上又是一个周末了,下周就是中秋了,下下周就是国庆啦,这里先祝福大家一个比一个假日嗨皮啦~~转眼我们的专题已经写了第 23 篇了,好几次都坚持不下去想要中断,不过每当看到群里的交流,看到博客下边好多小伙伴提出问题,我又燃起了斗志,不过这两天感冒了,所以更新的比较晚,这里也提醒大家,节日要照顾好自己哟~~~,好多人说我写的上不了台面,哈哈这里表示赞同,本系列的宗旨就是,给大家一个学习的点,让大家去自学一个面,然后大家一起学,把面交流成一个立体,就达到一个体系了。好啦,言归正传(一直告诫自己,不能写心情贴,哈哈要写技术文章),昨天呢,不知道有几个小伙伴按照教程把自己的之前的 .net core api 教程里的项目给展示出来了呢,一定要自己动手试试哟,只要成功了,就是棒棒哒,今天咱们继续往下走,来说说一个一直让人头大的东西,就是表单以及 Vuex的使用,好啦,开始今天的讲解!
零、今天要完成实战1中的红色部分
image
一、常见的 Vue 表单提交是如何设计的?
说到了 Web开发,一定几乎所有人都能说到表单提交,这个是真的少不了,而且也让人写的头晕眼花,心身疲惫,自然在 Vue 开发中,也是少不了的一部分工作,常见的表单是什么样子的呢?
1、表单、按钮等在一个组件内
这个时候机智如你一定会说:这有什么难的是吧,Vue 提供了完美的 双向数据绑定,可以很好的实现数据的更新、获取和提交,嗯~没错,你说的很对,我们再也不用费心的操作 DOM 了,用户填好数据就可以直接 axios 到 后端api接口了,多好,当然,这也是一个处理方式。
这里的代码就不写了,很简单,把所有的写到一个页面内就行,大家可以自己试一试。
可是想一想,如果页面内有很多组件,有很多的表单,或者更直接点儿,想要表单单独是一个组件用作弹窗,你会怎么办呢~为什么呢?
2、按钮在父组件、表单在单独的子组件内
这种开发利于开发,易于维护,可是就是不适合数据传输,因为父子组件内的数据通讯是很麻烦的,虽然 Vue 支持双向数据绑定,但是父子通讯是:组件之间的数据只能是单项流通的,而且由父组件传递给子组件,如果你看过我之前写的文章,有关组件的《从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十║Vue基础终篇:组件详解+项目说明》,你应该知道,之所以这么麻烦 , 是因为父组件可以通过 props
给子组件传递参数 , 但子组件内却不能直接修改父组件传过来的参数。只能通过自定义方法,向上提交时数据,今天,咱们说下第二种方法,子组件可以使用 $emit 触发父组件的自定义事件。
二、通过 $emit 修改父组件数据
1、在原来代码里 About.vue 修改成 Form.vue
注意,如果你是使用 Webstorm 的话,重命名的时候,会自动的把当然文件的全部应用的地方都会修改(举栗子:router 中的名字),如果是手动修改的文件夹中的,请确保其他地方都被修改了。
在 Form.vue 组件内,添加以下代码
<!-- 父组件 Form.vue --><template> <div class="parent"> <h3>问卷调查</h3> <!-- 注意这里,formData是自定义属性,用来向子组件传递数据,如果要想被子组件控制,必须加上 .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>
2、在 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: Object//对象的形式 }, watch: { // 因为不能直接修改 props 里的属性,所以不能直接把 formData 通过v-model进行绑定到 input 上 // 在这里我们需要监听 formData,当它发生变化时,立即将值赋给 data 里的 form,这个时候才可以用来 绑定 input formData: { immediate: true, handler(val) { this.form = val; } } }, mounted() {//挂载完成 // props 是单向数据流,通过触发 update 事件修改 formData, // 将 data 里的 form 指向父组件通过 formData 绑定的那个对象 // 父组件在绑定 formData 的时候,需要加上 .sync this.$emit("update:formData", this.form); } }; </script>
这里要说下 几个概念:
1、watch : 用来监听 父组件传递过来的值,当传递过来的时候,赋给 form,然后用 from 才可以双向绑定 DOM
2、mounted : 挂载完成后执行,如果有不明白的小伙伴,可以看看我之前的有关生命周期的文章 —— 《从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十九║Vue基础: 样式动态绑定+生命周期》。
3、emit("自定义事件名",要传送的数据),用来触发父组件的自定义事件,这里不是很明白没关系,因为它要配合 .sync 来使用。(注意:如果你在父组件里写了一个事件,这里就是那个事件的名字)
4、.sync : .sync 修饰符所提供的功能。当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定,就是说我们可以直接在我们需要传的 prop 后面加上 .sync。也就是说我们在子组件内,用过 update:formData 来改变了父组件的 属性 prop 的值,通过 .sync 来同步到了父组件的 form 对象里。嗯~大概就是这个意思。官网 :地址
5、 update:my-prop-name
的模式触发事件。举个栗子,在一个包含 title
prop 的假设的组件中,我们可以用以下方法表达对其赋新值:
this.$emit('update:title', newTitle)
然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。例如:
<text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event"></text-document>
为了方便起见,我们为这种模式提供一个缩写,即 .sync
修饰符:
<text-document text- v-bind:title.sync="doc.title"></text-document>
3、这个时候,我们看我们看我们的项目,结果就出来了
不仅可以把父组件的 ”姓名不能为空“传递到子组件,还可以,把子组件内的数据发送到父组件,是不是感觉很神奇?!而且也可以做成一个弹窗的,大家可以自己试试。
image
但是呢,这里是一个小 DEMO 还好,要是多的话,要设置总感觉不是很舒服,还需要 用到那么多的新的东西,欸!机智如你, Vuex 就这么登台了。
三、使用 Vuex 来实现父子通讯
1、老规矩,什么是 Vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。说人话就是,它就像是一个容器,一个第三方,我们可以把内容存进去,然后在别的任何地方去取出来,这个是不是正好就是我们的父子组件通讯?!大家再看看上面,父子组件之间的通信是不是比较麻烦,改变数据还要用$emit。如果有一个地方跟仓库一样就存放着form的值,谁要用谁去请求form的值,谁想改就改该多好是吧,vuex就是一个管理仓库,有点全局变量的意思。任何组件需要拿,改东西,都可以找他。
image
2、首先我们需要安装 Vuex
利用npm下载vuex包,在命令行工具中输入以下命令,cd到你的项目目录
npm install vuex --save
3、还记得那个 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;
4、在 views 文件夹下,新建 FormVuex.vue 页面
内容和 Form.vue 主要内容差不多
<!-- 父组件 parent.vue --><template> <div class="parent"> <h3>问卷调查</h3> <child ></child><!-- 注意: 这里已经没有 .sync 了 --> <div class=""> <br> <br> <p>数据:{{_formData}}</p> </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>
5、在 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('fatherData', this.form) } }; </script>
6、修改 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") } ] });
7、浏览页面,搞定!
就这样就完成啦!是不是很简单,原理就是:在子组件内,把双向数据绑定的数据,提交到 store 里,然后再在父组件里获取,剩下的大家可以在处理
image
四、其他扩展
1、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
即可。这个大家可以自由的尝试,这里就不一一说明了。
2、什么情况下我应该使用 Vuex?
虽然 Vuex 可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
作者:SAYLINING
链接:https://www.jianshu.com/p/029080a56707
共同学习,写下你的评论
评论加载中...
作者其他优质文章