前言
哈嘍大家周五好驳阎,馬上又是一個(gè)周末了,下周就是中秋了,下下周就是國(guó)慶啦谭期,這里先祝福大家一個(gè)比一個(gè)假日嗨皮啦~~轉(zhuǎn)眼我們的專題已經(jīng)寫了第 23 篇了,好幾次都堅(jiān)持不下去想要中斷吧凉,不過(guò)每當(dāng)看到群里的交流隧出,看到博客下邊好多小伙伴提出問(wèn)題,我又燃起了斗志阀捅,不過(guò)這兩天感冒了胀瞪,所以更新的比較晚,這里也提醒大家饲鄙,節(jié)日要照顧好自己?jiǎn)褈~~凄诞,好多人說(shuō)我寫的上不了臺(tái)面,哈哈這里表示贊同忍级,本系列的宗旨就是帆谍,給大家一個(gè)學(xué)習(xí)的點(diǎn),讓大家去自學(xué)一個(gè)面轴咱,然后大家一起學(xué)汛蝙,把面交流成一個(gè)立體,就達(dá)到一個(gè)體系了嗦玖。好啦患雇,言歸正傳(一直告誡自己,不能寫心情貼宇挫,哈哈要寫技術(shù)文章)苛吱,昨天呢,不知道有幾個(gè)小伙伴按照教程把自己的之前的 .net core api 教程里的項(xiàng)目給展示出來(lái)了呢器瘪,一定要自己動(dòng)手試試喲翠储,只要成功了,就是棒棒噠橡疼,今天咱們繼續(xù)往下走援所,來(lái)說(shuō)說(shuō)一個(gè)一直讓人頭大的東西,就是表單以及 Vuex的使用欣除,好啦住拭,開始今天的講解!
零、今天要完成實(shí)戰(zhàn)1中的紅色部分
一滔岳、常見的 Vue 表單提交是如何設(shè)計(jì)的杠娱?
說(shuō)到了 Web開發(fā),一定幾乎所有人都能說(shuō)到表單提交谱煤,這個(gè)是真的少不了摊求,而且也讓人寫的頭暈眼花,心身疲憊刘离,自然在 Vue 開發(fā)中室叉,也是少不了的一部分工作,常見的表單是什么樣子的呢硫惕?
1茧痕、表單、按鈕等在一個(gè)組件內(nèi)
這個(gè)時(shí)候機(jī)智如你一定會(huì)說(shuō):這有什么難的是吧疲憋,Vue 提供了完美的 雙向數(shù)據(jù)綁定凿渊,可以很好的實(shí)現(xiàn)數(shù)據(jù)的更新、獲取和提交缚柳,嗯~沒錯(cuò)埃脏,你說(shuō)的很對(duì),我們?cè)僖膊挥觅M(fèi)心的操作 DOM 了秋忙,用戶填好數(shù)據(jù)就可以直接 axios 到 后端api接口了彩掐,多好,當(dāng)然灰追,這也是一個(gè)處理方式堵幽。
這里的代碼就不寫了,很簡(jiǎn)單弹澎,把所有的寫到一個(gè)頁(yè)面內(nèi)就行朴下,大家可以自己試一試。
可是想一想苦蒿,如果頁(yè)面內(nèi)有很多組件殴胧,有很多的表單,或者更直接點(diǎn)兒佩迟,想要表單單獨(dú)是一個(gè)組件用作彈窗团滥,你會(huì)怎么辦呢~為什么呢?
2报强、按鈕在父組件灸姊、表單在單獨(dú)的子組件內(nèi)
這種開發(fā)利于開發(fā),易于維護(hù)秉溉,可是就是不適合數(shù)據(jù)傳輸力惯,因?yàn)楦缸咏M件內(nèi)的數(shù)據(jù)通訊是很麻煩的碗誉,雖然 Vue 支持雙向數(shù)據(jù)綁定,但是父子通訊是:組件之間的數(shù)據(jù)只能是單項(xiàng)流通的夯膀,而且由父組件傳遞給子組件诗充,如果你看過(guò)我之前寫的文章,有關(guān)組件的《從壹開始前后端分離 [ Vue2.0+.NET Core2.1] 二十║Vue基礎(chǔ)終篇:組件詳解+項(xiàng)目說(shuō)明》诱建,你應(yīng)該知道,之所以這么麻煩 , 是因?yàn)楦附M件可以通過(guò) props
給子組件傳遞參數(shù) , 但子組件內(nèi)卻不能直接修改父組件傳過(guò)來(lái)的參數(shù)碟绑。只能通過(guò)自定義方法俺猿,向上提交時(shí)數(shù)據(jù),今天格仲,咱們說(shuō)下第二種方法押袍,子組件可以使用 $emit 觸發(fā)父組件的自定義事件。
二凯肋、通過(guò) $emit 修改父組件數(shù)據(jù)
1谊惭、在原來(lái)代碼里 About.vue 修改成 Form.vue
注意,如果你是使用 Webstorm 的話侮东,重命名的時(shí)候圈盔,會(huì)自動(dòng)的把當(dāng)然文件的全部應(yīng)用的地方都會(huì)修改(舉栗子:router 中的名字),如果是手動(dòng)修改的文件夾中的悄雅,請(qǐng)確保其他地方都被修改了驱敲。
在 Form.vue 組件內(nèi),添加以下代碼
<!-- 父組件 Form.vue -->
<template>
<div class="parent">
<h3>問(wèn)卷調(diào)查</h3>
<!-- 注意這里宽闲,formData是自定義屬性众眨,用來(lái)向子組件傳遞數(shù)據(jù),如果要想被子組件控制容诬,必須加上 .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";//導(dǎo)入子組件
export default {
components: {
child
},
data: function() {//定義返回data
return {
form: {
name: "",
namePla: "姓名不能為空",
address: "",
age: "" }
};
}
}; </script>
2娩梨、在 components 文件夾內(nèi),添加窗口子組件 dialog.vue(之所以叫窗口览徒,就是你可以把它設(shè)計(jì)成彈窗)
<!-- 子組件 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: { // 這個(gè) prop 屬性用來(lái)接收父組件傳遞進(jìn)來(lái)的值
formData: Object//對(duì)象的形式
},
watch: { // 因?yàn)椴荒苤苯有薷?props 里的屬性狈定,所以不能直接把 formData 通過(guò)v-model進(jìn)行綁定到 input 上 // 在這里我們需要監(jiān)聽 formData,當(dāng)它發(fā)生變化時(shí)吱殉,立即將值賦給 data 里的 form掸冤,這個(gè)時(shí)候才可以用來(lái) 綁定 input
formData: {
immediate: true,
handler(val) { this.form = val;
}
}
},
mounted() {//掛載完成 // props 是單向數(shù)據(jù)流,通過(guò)觸發(fā) update 事件修改 formData友雳, // 將 data 里的 form 指向父組件通過(guò) formData 綁定的那個(gè)對(duì)象 // 父組件在綁定 formData 的時(shí)候稿湿,需要加上 .sync
this.$emit("update:formData", this.form);
}
}; </script>
這里要說(shuō)下 幾個(gè)概念:
1、watch : 用來(lái)監(jiān)聽 父組件傳遞過(guò)來(lái)的值押赊,當(dāng)傳遞過(guò)來(lái)的時(shí)候饺藤,賦給 form包斑,然后用 from 才可以雙向綁定 DOM
2、mounted : 掛載完成后執(zhí)行涕俗,如果有不明白的小伙伴罗丰,可以看看我之前的有關(guān)生命周期的文章 —— 《從壹開始前后端分離 [ Vue2.0+.NET Core2.1] 十九║Vue基礎(chǔ): 樣式動(dòng)態(tài)綁定+生命周期》。
3再姑、emit("自定義事件名",要傳送的數(shù)據(jù))萌抵,用來(lái)觸發(fā)父組件的自定義事件,這里不是很明白沒關(guān)系元镀,因?yàn)樗浜?.sync 來(lái)使用绍填。(注意:如果你在父組件里寫了一個(gè)事件,這里就是那個(gè)事件的名字)
4栖疑、.sync : .sync 修飾符所提供的功能讨永。當(dāng)一個(gè)子組件改變了一個(gè) prop 的值時(shí),這個(gè)變化也會(huì)同步到父組件中所綁定遇革,就是說(shuō)我們可以直接在我們需要傳的 prop 后面加上 .sync卿闹。也就是說(shuō)我們?cè)谧咏M件內(nèi),用過(guò) update:formData 來(lái)改變了父組件的 屬性 prop 的值萝快,通過(guò) .sync 來(lái)同步到了父組件的 form 對(duì)象里锻霎。嗯~大概就是這個(gè)意思。官網(wǎng) :地址
5杠巡、 update:my-prop-name
的模式觸發(fā)事件量窘。舉個(gè)栗子,在一個(gè)包含 title
prop 的假設(shè)的組件中氢拥,我們可以用以下方法表達(dá)對(duì)其賦新值:
this.$emit('update:title', newTitle)
然后父組件可以監(jiān)聽那個(gè)事件并根據(jù)需要更新一個(gè)本地的數(shù)據(jù)屬性蚌铜。例如:
<text-document
v-bind:title="doc.title" v-on:update:title="doc.title = $event"
></text-document>
為了方便起見,我們?yōu)檫@種模式提供一個(gè)縮寫嫩海,即 .sync
修飾符:
<text-document text- v-bind:title.sync="doc.title"></text-document>
3冬殃、這個(gè)時(shí)候,我們看我們看我們的項(xiàng)目叁怪,結(jié)果就出來(lái)了
不僅可以把父組件的 ”姓名不能為空“傳遞到子組件审葬,還可以,把子組件內(nèi)的數(shù)據(jù)發(fā)送到父組件奕谭,是不是感覺很神奇涣觉?!而且也可以做成一個(gè)彈窗的血柳,大家可以自己試試官册。
但是呢,這里是一個(gè)小 DEMO 還好难捌,要是多的話膝宁,要設(shè)置總感覺不是很舒服鸦难,還需要 用到那么多的新的東西,欸员淫!機(jī)智如你合蔽, Vuex 就這么登臺(tái)了。
三介返、使用 Vuex 來(lái)實(shí)現(xiàn)父子通訊
1拴事、老規(guī)矩,什么是 Vuex映皆?
Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式挤聘。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化捅彻。說(shuō)人話就是,它就像是一個(gè)容器鞍陨,一個(gè)第三方步淹,我們可以把內(nèi)容存進(jìn)去,然后在別的任何地方去取出來(lái)诚撵,這個(gè)是不是正好就是我們的父子組件通訊缭裆?!大家再看看上面寿烟,父子組件之間的通信是不是比較麻煩澈驼,改變數(shù)據(jù)還要用$emit。如果有一個(gè)地方跟倉(cāng)庫(kù)一樣就存放著form的值筛武,誰(shuí)要用誰(shuí)去請(qǐng)求form的值缝其,誰(shuí)想改就改該多好是吧,vuex就是一個(gè)管理倉(cāng)庫(kù)徘六,有點(diǎn)全局變量的意思内边。任何組件需要拿,改東西待锈,都可以找他漠其。
2、首先我們需要安裝 Vuex
利用npm下載vuex包竿音,在命令行工具中輸入以下命令,cd到你的項(xiàng)目目錄
npm install vuex --save
3和屎、還記得那個(gè) store.js 么,終于用到了春瞬,修改內(nèi)容
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex); const store = new Vuex.Store({ // 初始化的數(shù)據(jù)
state: {
formDatas: null//定義一個(gè)變量 formDatas
}, // 改變state里面的值得方法
mutations: {
getFormData(state, data) {
state.formDatas = data;
}
}
}); // 輸出模塊
export default store;
4柴信、在 views 文件夾下,新建 FormVuex.vue 頁(yè)面
內(nèi)容和 Form.vue 主要內(nèi)容差不多
<!-- 父組件 parent.vue -->
<template>
<div class="parent">
<h3>問(wèn)卷調(diào)查</h3>
<child ></child><!-- 注意: 這里已經(jīng)沒有 .sync 了 -->
<div class="">
<br>
<br>
<p>數(shù)據(jù):{{_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 倉(cāng)庫(kù)中的 formDatas 值 // 讀取store里面的值快鱼,這里是重點(diǎn)
return this.$store.state.formDatas;
}
}
}; </script>
5颠印、在 components 文件夾下纲岭,新增 dialogVuex.vue 頁(yè)面
<!-- 子組件 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() { // 將數(shù)據(jù)提交到 store
this.$store.commit('fatherData', this.form)
}
}; </script>
6、修改 App.vue 和 路由 router.js线罕,提供 Vuex 頁(yè)面入口
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止潮、瀏覽頁(yè)面,搞定钞楼!
就這樣就完成啦喇闸!是不是很簡(jiǎn)單,原理就是:在子組件內(nèi)询件,把雙向數(shù)據(jù)綁定的數(shù)據(jù)燃乍,提交到 store 里,然后再在父組件里獲取宛琅,剩下的大家可以在處理
四刻蟹、其他擴(kuò)展
1、store.js 各部分單獨(dú)管理
從上邊可以看出嘿辟,雖然我們的 store 單獨(dú)在一個(gè)文件里舆瘪,那組件多了之后 , 狀態(tài)也多了 , 這么多狀態(tài)都堆在 store.js 不好維護(hù)怎么辦 ?
我們可以使用 vuex 的 modules
, 把 store.js
改成 :
import Vue from 'vue' import vuex from 'vuex' Vue.use(vuex);
import dialog_store from '../components/dialog_store.js';//引入某個(gè)store對(duì)象
export default new vuex.Store({
modules: {
dialog: dialog_store
}
})
這里我們引用了一個(gè) dialog_store.js
, 在這個(gè) js 文件里我們就可以單獨(dú)寫 dialog 組件的狀態(tài)了 :
export default {
state: {
formDatas: null }, // 改變state里面的值得方法
mutations: {
getFormData(state, data) {
state.formDatas = data;
}
}
}
做出這樣的修改之后 , 我們將之前我們使用的 $store.state.formDatas
統(tǒng)統(tǒng)改為 $store.state.dialog.formDatas
即可。這個(gè)大家可以自由的嘗試红伦,這里就不一一說(shuō)明了英古。
2、什么情況下我應(yīng)該使用 Vuex昙读?
雖然 Vuex 可以幫助我們管理共享狀態(tài)召调,但也附帶了更多的概念和框架。這需要對(duì)短期和長(zhǎng)期效益進(jìn)行權(quán)衡蛮浑。
如果您不打算開發(fā)大型單頁(yè)應(yīng)用唠叛,使用 Vuex 可能是繁瑣冗余的。確實(shí)是如此——如果您的應(yīng)用夠簡(jiǎn)單陵吸,您最好不要使用 Vuex玻墅。一個(gè)簡(jiǎn)單的 store 模式就足夠您所需了。但是壮虫,如果您需要構(gòu)建一個(gè)中大型單頁(yè)應(yīng)用澳厢,您很可能會(huì)考慮如何更好地在組件外部管理狀態(tài),Vuex 將會(huì)成為自然而然的選擇囚似。
3剩拢、其他擴(kuò)展問(wèn)題補(bǔ)充中
五、結(jié)語(yǔ)
今天因?yàn)闀r(shí)間的問(wèn)題饶唤,就暫時(shí)說(shuō)到了這里徐伐,是不是感覺很簡(jiǎn)單,這個(gè)就是 vuex 的使用募狂,當(dāng)然办素,還有其他的一些擴(kuò)展使用角雷,我還沒有來(lái)得及準(zhǔn)備,明天就是周末了性穿,我再整理后勺三,再修改下吧,如果你以上的都看懂了需曾,那父子組件通訊吗坚,各種表單提交,你已經(jīng)沒有問(wèn)題啦~好啦下次再見咯呆万。
六商源、CODE
https://github.com/anjoy8/Blog.Vue
注意:如果下載好了,首先需要 執(zhí)行 npm install 安裝依賴
請(qǐng)確保已經(jīng)把 webpack 和 vue-cli 都安裝了谋减。
QQ群:
867095512 (blod.core)