需要響應(yīng)的數(shù)據(jù),在獲取到接口數(shù)據(jù)的時候,先設(shè)置
大家有沒有很經(jīng)常碰到這樣都一種情況,在循環(huán)列表的時候,我們需要給列表項一個控制顯示的屬性,如 是否可刪除,是否已選中等等,而后端接口一般不會返回這種字段,因為這屬于純前端展示的,跟后端沒啥關(guān)系,比如后端給的數(shù)據(jù)如下
[ {name: 'abc', age: 18}, {name: 'def', age: 20}, {name: 'ghi', age: 22}, ]
我們不妨假設(shè)以上數(shù)據(jù)為學(xué)生列表
然后我們需要渲染這個列表,在每一項后面顯示一個勾選按鈕,如果用戶打勾,則這個按鈕是綠色,默認這個按鈕是灰色,這個時候,上表是沒有滿足這個渲染條件的數(shù)據(jù),而如果我們在用戶打勾的時候,再去添加這個數(shù)據(jù)的話,正常的做法是無法及時響應(yīng)的。
如果我們在獲取到數(shù)據(jù)的時候,先給數(shù)組的每一項都加一個是否打勾的標示,就可以解決這個問題,我們假設(shè)我們獲取到的數(shù)據(jù)是 res.list
res.list.map(item => { item.isTicked = false })
這么做的原理是 vue
無法對不存在的屬性作響應(yīng),所以我們在獲取到數(shù)據(jù)的時候,先把需要的屬性加上去,然后在賦值給 data
, 這樣 data
接收到數(shù)據(jù)的時候,已經(jīng)是存在這個屬性了,所以會響應(yīng)。當(dāng)然還有其他方法可以實現(xiàn)。不過對于一個強迫癥來說,我還是比較傾向于這種做法
封裝全局基于 promise
的異步請求方法
看過很多項目的源碼,發(fā)現(xiàn)大部分的異步請求都是直接使用 axios
之類的方法,如下
axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
如果有跨域,或者需要設(shè)置 http
頭等,還需要加入更多的配置,而這些配置,對于同一個項目來說,基本都是一樣的,不一樣的只有 url
跟參數(shù),既然這樣,那我嗎為什么不把它封裝成一個方法呢?
function post (url,param) { return axios({ method: 'post', url: url, data: param ... axios 的其他配置 }) }
@日月為易。
指出再結(jié)合第一點,我們就可以再任意 vue
實例中這樣使用
let param = { firstName: 'Fred', lastName: 'Flintstone' } this.post('/user/12345',param) .then(...) .catch(...)
有沒有比原始的簡單很多呢?如果你的項目支持 async
await
,還可以這樣用
let param = { firstName: 'Fred', lastName: 'Flintstone' } let res = await this.post('/user/12345',param) console.log(res) // res 就是異步返回的數(shù)據(jù)
await
關(guān)鍵字必須在 被 async 修飾的函數(shù)里面使用
如果你覺得有時候,你真的需要父子組件共享一個值,不如試試傳個引用類型過去
vue
的父子組件傳值,有好多種方法,這里就不一一列舉了,但是今天我們要了解的,是利用 javascript
的引用類型特性,還達到另一種傳值的目的
假設(shè)有這么一個需求,父組件需要傳 3 個值到子組件,然后再子組件里面改動后,需要立馬再父組件上作出響應(yīng),我們通常的做法上改完以后,通過 this.$emit
發(fā)射事件,然后再父組件監(jiān)聽對應(yīng)的事件,然而這么做應(yīng)對一兩個數(shù)據(jù)還好,如果傳的數(shù)據(jù)多了,會累死人。
我們不妨把這些要傳遞的數(shù)據(jù),包再一個對象/數(shù)組 里面,然后在傳給子組件
<subComponent :subData="subData"></subComponent>
data () { return { subData: { filed1: 'field1', filed2: 'field2', filed3: 'field3', filed4: 'field4', filed5: 'field5', } } }
這樣,我們在子組件里面改動 subData
的內(nèi)容,父組件上就能直接作出響應(yīng),無需 this.$emit
或 vuex
而且如果有其他兄弟組件的話,只要兄弟組件也有綁定這個 subData
,那么兄弟組件里面的 subData
也能及時響應(yīng)
this.$emit
吧,其次,這個數(shù)據(jù)需要有特定的條件才能構(gòu)造的出來,并不是所有情況都適用。異步請求的參數(shù)在 data
里面構(gòu)造好,用一個對象包起來,會方便很多
有做過類似 ERP
類型的系統(tǒng)的同學(xué),一定碰到過這樣的一個場景,一個列表,有 N 個過濾條件,這個時候通常我們這么綁定
<input type="text" v-model="field1"> <input type="text" v-model="field2"> <input type="text" v-model="field3"> .... <input type="text" v-model="fieldn">
data () { return { field1: 'value1', field2: 'value2', field3: 'value3', ... fieldn:'valuen' } }
然后提交數(shù)據(jù)的時候這樣:
var param = { backend_field1: this.field1, backend_field2: this.field2, backend_field3: this.field3, ... backend_fieldn: this.fieldn } this.post(url,param)
如你看到的,每次提交接口,都要去構(gòu)造參數(shù),還很容易遺漏,我們不妨這樣:先去接口文檔里面看一下后端需要的字段名稱,然后
<input type="text" v-model="queryParam.backend_field1"> <input type="text" v-model="queryParam.backend_field2"> <input type="text" v-model="queryParam.backend_field3"> .... <input type="text" v-model="queryParam.backend_fieldn">
"javascript data () { return { queryParam:{ backend_field1: 'value1' backend_field2: 'value2' backend_field3: 'value3' ... backend_fieldn: 'valuen' } } } " 然后提交數(shù)據(jù)的時候這樣: "javascript this.post(url,this.queryParam) "
是的,這樣做也是有局限性的,比如你一個數(shù)據(jù)在 2 個地方共用,比如前端組件綁定的是一個數(shù)組,你需要提交給后端的是 2 個字符串(例:element ui
的時間控件),不過部分特殊問題稍微處理一下,也比重新構(gòu)建一個參數(shù)簡單不是嗎?
data
里面的數(shù)據(jù)多的時候,給每個數(shù)據(jù)加一個備注,會讓你后期往回看的時候很清晰
續(xù)上一點,data
里面有很多數(shù)據(jù)的時候,可能你寫的時候是挺清晰的,畢竟都是你自己寫的東西,可是過了十天半個月,或者別人看你的代碼,相信我,不管是你自己,還是別人,都是一頭霧水(記憶力超出常人的除外),所以我們不妨給每個數(shù)據(jù)后面加一個備注
data () { return { field1: 'value1', // 控制xxx顯示 field2: 'value2', // 頁面加載狀態(tài) field3: [], // 用戶列表 ... fieldn: 'valuen' // XXXXXXXX } }
邏輯復(fù)雜的內(nèi)容,盡量拆成組件
假設(shè)我們有一個這樣的場景:
<p> <p>姓名:{{user1.name}}</p> <p>性別:{{user1.sex}}</p> <p>年齡:{{user1.age}}</p> ...此處省略999個字段... <p>他隔壁鄰居的阿姨家小狗的名字:{{user1.petName}}</p> </p> <-- 當(dāng)然,顯示中我們不會傻到不用 v-for,我們假設(shè)這種情況無法用v-for --> <p> <p>姓名:{{user2.name}}</p> <p>性別:{{user2.sex}}</p> <p>年齡:{{user2.age}}</p> ...此處省略999個字段... <p>他隔壁鄰居的阿姨家小狗的名字:{{user2.petName}}</p> </p>
這種情況,我們不妨把[用戶]的代碼,提取到一個組件里面:
假設(shè)如下代碼,在 comUserInfo.vue
<template> <p> <p>姓名:{{user.name}}</p> <p>性別:{{user.sex}}</p> <p>年齡:{{user.age}}</p> ...此處省略999個字段... <p>他隔壁鄰居的阿姨家小狗的名字:{{user.petName}}</p> </p> </template> <script > export default { props:{ user:{ type:Object, default: () => {} } } } </script>
然后原來的頁面可以改成這樣(省略掉導(dǎo)入和注冊組件,假設(shè)注冊的名字是 comUserInfo
):
<comUserInfo :user="user1"/> <comUserInfo :user="user2"/>
這樣是不是清晰很多?不用看注釋,都能猜的出來,這是2個用戶信息模塊, 這樣做,還有一個好處就是出現(xiàn)錯誤的時候,你可以更容易的定位到錯誤的位置。
如果你只在子組件里面改變父組件的一個值,不妨試試 $emit('input')
,會直接改變 v-model
我們正常的父子組件通信是 父組件通過 props
傳給子組件,子組件通過 this.$emit('eventName',value)
通知父組件綁定在 @eventName
上的方法來做相應(yīng)的處理。
但是這邊有個特例,vue
默認會監(jiān)聽組件的 input
事件,而且會把子組件里面?zhèn)鞒鰜淼闹?,賦給當(dāng)前綁定到 v-model
上的值
正常用法 - 父組件
<template> <subComponent :data="param" @dataChange="dataChangeHandler"></subComponent> </template> <script > export default { data () { return { param:'xxxxxx' } }, methods:{ dataChangeHandler (newParam) { this.param = newParam } } } </script>
正常用法 - 子組件
<script > export default { methods:{ updateData (newParam) { this.$emit('dataChange',newParam) } } } </script>
利用默認 input
事件 - 父組件
<template> <subComponent v-model="param"></subComponent> </template>
利用默認 input
事件 - 子組件
<script > export default { methods:{ updateData (newParam) { this.$emit('input',newParam) } } } </script>
這樣,我們就能省掉父組件上的一列席處理代碼,vue
會自動幫你處理好
補充一個 this.$emit('update:fidldName',value)
方法 (感謝掘金用戶 @日月為易。
指出)
具體用法如下:
父組件
<subComponent field1.sync="param1" field2.sync="param2"></subComponent>
子組件
<script > export default { methods:{ updateData1 (newValue) { this.$emit('update:field1',newValue) }, updateData2 (newValue) { this.$emit('update:field2',newValue) } } } </script>
該方法,個人認為比較適用于 要更新的數(shù)據(jù)不能綁定在 v-model
的情況下,或者要雙向通信的數(shù)據(jù)大于 1 個(1個也可以用,但我個人更推薦 input
的方式, 看個人喜好吧),但又不會很多的情況下.
conponents
放在 Vue options
的最上面
不知道大家有沒有這樣的經(jīng)歷: 導(dǎo)入組件,然后在也頁面中使用,好的,報錯了,為啥?忘記注冊組件了,為什么會經(jīng)常忘記注冊組件呢?因為正常的一個 vue
實例的結(jié)構(gòu)大概是這樣的:
import xxx form 'xxx/xxx' export default { name: 'component-name', data () { return { // ...根據(jù)業(yè)務(wù)邏輯的復(fù)雜程度,這里省略若干行 } }, computed: { // ...根據(jù)業(yè)務(wù)邏輯的復(fù)雜程度,這里省略若干行 }, created () { // ...根據(jù)業(yè)務(wù)邏輯的復(fù)雜程度,這里省略若干行 }, mounted () { // ...根據(jù)業(yè)務(wù)邏輯的復(fù)雜程度,這里省略若干行 }, methods () { // ...根據(jù)業(yè)務(wù)邏輯的復(fù)雜程度,這里省略若干行 }, }
我不知道大家正常是把 components
屬性放在哪個位置,反正我之前是放在最底下,結(jié)果就是導(dǎo)致經(jīng)常犯上述錯誤。
后面我把 components
調(diào)到第一個去了
import xxx form 'xxx/xxx' export default { components: { xxx }, // 省略其他代碼 }
從此以后,媽媽再也不用擔(dān)心我忘記注冊組件了,導(dǎo)入和注冊都在同一個位置,想忘記都難。
大部分情況下,生命周期里面,不要有太多行代碼,可以封裝成方法,再調(diào)用
看過很多代碼,包括我自己之前的,在生命周期里面洋洋灑灑的寫了一兩百行的代碼,如:把頁面加載的時候,該做的事,全部寫在 created
里面,導(dǎo)致整個代碼難以閱讀,完全不知道你在頁面加載的時候,做了些什么,
這個時候,我們不妨把那些邏輯封裝成方法,然后在生命周期里面直接調(diào)用:
created () { // 獲取用戶信息 this.getUserInfo() // 獲取系統(tǒng)信息 this.getSystemInfo() // 獲取配置 this.getConfigInfo() }, methods:{ // 獲取用戶信息 getUserInfo () {...}, // 獲取系統(tǒng)信息 getSystemInfo () {...}, // 獲取配置 getConfigInfo () {...}, }
這樣是不是一眼就能看的出,你在頁面加載的時候做了些什么?
tip: 這個應(yīng)該算是一個約定俗成的規(guī)范吧,只是覺得看的比較多這樣寫的,加上我自己初學(xué)的時候,也這么做了,所以寫出來,希望新入坑的同學(xué)能避免這個問題少用 watch
,如果你覺得你好多地方都需要用到 watch
,那十有八九是你對 vue
的 API
還不夠了解
vue
本身就是一個數(shù)據(jù)驅(qū)動的框架,數(shù)據(jù)的變動,能實時反饋到視圖上去,如果你想要根據(jù)數(shù)據(jù)來控制試圖,正常情況一下配合 computed
服用就能解決大部分問題了,而視圖上的變動,我們一般可以通過監(jiān)聽 input
change
等事件,達到實時監(jiān)聽的目的,
所以很少有需求使用到 watch
的時候,至少我最近到的十來個項目里面,是沒有用過 watch
當(dāng)然,并不是說 watch
是肯定沒用處, vue
提供這個api,肯定是有他的道理,也有部分需求是真的需要用到的,只是我覺得應(yīng)該很少用到才對,如果你覺得到處都得用到的話,
那么我覺得 十有八九你應(yīng)該多去熟悉一下 computed
和 vue
的其他 api
了
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com