本文純屬我的平時實踐過程當中的一些經驗總結,算是一點點小技巧吧,不是多麼高明的技術,若是對你有幫助,那麼不勝榮幸。javascript
本文不涉及罕見API
使用方法等,大部份內容都是基於對vue的一些實踐而已。因爲涉嫌投機取巧,可能會帶來一些不符合規範的反作用,請根據項目要求酌情使用。html
多個頁面都使用的到方法,放在 vue.prototype
上會很方便前端
剛接觸 vue
的時候作過一件傻事,由於封裝了一個異步請求接口post
,放在 post.js
文件裏面,而後在每一個須要使用異步請求的頁面引入vue
import port from './xxxx/xxxx/post'
複製代碼
若是隻是這樣,還沒什麼,咱們能夠寫好一個頁面之後再複製,能夠保證每一個頁面都有上面的語句。可是若是每一個文件所在的目錄層級不同呢?java
// 假設正常是這樣
import port from '../xxxx/xxxx/post'
// 目錄加深一級,就變成這樣
import port from '../../xxxx/xxxx/post'
// 再加深一級的樣子
import port from '../../../xxxx/xxxx/post'
複製代碼
固然,這個時候,咱們能夠用 別名 @/xxxx/post
,可是仍是少不了要每一個頁面引用。 那咱們來看看,用vue.prototype
有多方便? 首先,你得在 vue
的入口文件( vue-cli
生成的項目的話,默認是 /src/main.js
)裏面作以下設置ios
import port from './xxxx/xxxx/post'
vue.prototype.$post = post
複製代碼
這樣,咱們就能夠在全部的 vue
組件(頁面)裏面使用 this.post()
方法了,就像 vue
的親兒子同樣git
tip: 把方法掛在到
prototype
上的時候,最好加一個$
前綴,避免跟其餘變量衝突github
til again: 不要掛載太多方法到
prototype
上,只掛載一些使用頻率很是高的vuex
須要響應的數據,在獲取到接口數據的時候,先設置vue-cli
你們有沒有很常常碰到這樣都一種狀況,在循環列表的時候,咱們須要給列表項一個控制顯示的屬性,如 是否可刪除,是否已選中等等,然後端接口通常不會返回這種字段,由於這屬於純前端展現的,跟後端沒啥關係,好比後端給的數據以下
[
{name: 'abc', age: 18},
{name: 'def', age: 20},
{name: 'ghi', age: 22},
]
複製代碼
咱們不妨假設以上數據爲學生列表
而後咱們須要渲染這個列表,在每一項後面顯示一個勾選按鈕,若是用戶打勾,則這個按鈕是綠色,默認這個按鈕是灰色,這個時候,上表是沒有知足這個渲染條件的數據,而若是咱們在用戶打勾的時候,再去添加這個數據的話,正常的作法是沒法及時響應的。
若是咱們在獲取到數據的時候,先給數組的每一項都加一個是否打勾的標示,就能夠解決這個問題,咱們假設咱們獲取到的數據是 res.list
res.list.map(item => {
item.isTicked = false
})
複製代碼
這麼作的原理是 vue
沒法對不存在的屬性做響應,因此咱們在獲取到數據的時候,先把須要的屬性加上去,而後在賦值給 data
, 這樣 data
接收到數據的時候,已是存在這個屬性了,因此會響應。固然還有其餘方法能夠實現。不過對於一個強迫症來講,我仍是比較傾向於這種作法
封裝全局基於 promise
的異步請求方法
看過不少項目的源碼,發現大部分的異步請求都是直接使用 axios
之類的方法,以下
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
複製代碼
若是有跨域,或者須要設置 http
頭等,還須要加入更多的配置,而這些配置,對於同一個項目來講,基本都是同樣的,不同的只有 url
跟參數,既然這樣,那我嗎爲何不把它封裝成一個方法呢?
function post (url,param) {
return axios({
method: 'post',
url: url,
data: param
... axios 的其餘配置
})
}
複製代碼
tip: 這裏原來我多用了一層promise包起來,對簡單的需求來講是太多餘了,感受掘金用戶
@日月爲易。
指出
再結合第一點,咱們就能夠再任意 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 就是異步返回的數據
複製代碼
tip:
await
關鍵字必須在被 async 修飾的函數裏面使用
若是你以爲有時候,你真的須要父子組件共享一個值,不如試試傳個引用類型過去
vue
的父子組件傳值,有好多種方法,這裏就不一一列舉了,可是今天咱們要了解的,是利用 javascript
的引用類型特性,還達到另外一種傳值的目的
假設有這麼一個需求,父組件須要傳 3 個值到子組件,而後再子組件裏面改動後,須要立馬再父組件上做出響應,咱們一般的作法上改完之後,經過 this.$emit
發射事件,而後再父組件監聽對應的事件,然而這麼作應對一兩個數據還好,若是傳的數據多了,會累死人。 咱們不妨把這些要傳遞的數據,包再一個對象/數組 裏面,而後在傳給子組件
<subComponent :subData="subData"></subComponent>
複製代碼
data () {
return {
subData: {
filed1: 'field1',
filed2: 'field2',
filed3: 'field3',
filed4: 'field4',
filed5: 'field5',
}
}
}
複製代碼
這樣,咱們在子組件裏面改動 subData
的內容,父組件上就能直接做出響應,無需 this.$emit
或 vuex
並且若是有其餘兄弟組件的話,只要兄弟組件也有綁定這個 subData
,那麼兄弟組件裏面的 subData
也能及時響應
tip: 首先,這麼作我我的上感受有點不符合規範的,若是沒有特別多的數據,仍是乖乖用
this.$emit
吧,其次,這個數據須要有特定的條件才能構造的出來,並非全部狀況都適用。
異步請求的參數在 data
裏面構造好,用一個對象包起來,會方便不少
有作過相似 ERP
類型的系統的同窗,必定碰到過這樣的一個場景,一個列表,有 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'
}
}
複製代碼
而後提交數據的時候這樣:
var param = {
backend_field1: this.field1,
backend_field2: this.field2,
backend_field3: this.field3,
...
backend_fieldn: this.fieldn
}
this.post(url,param)
複製代碼
如你看到的,每次提交接口,都要去構造參數,還很容易遺漏,咱們不妨這樣:先去接口文檔裏面看一下後端須要的字段名稱,而後
<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'
}
}
}
```
而後提交數據的時候這樣:
```javascript
this.post(url,this.queryParam)
```
是的,這樣作也是有侷限性的,好比你一個數據在 2 個地方共用,好比前端組件綁定的是一個數組,你須要提交給後端的是 2 個字符串(例:`element ui` 的時間控件),不過部分特殊問題稍微處理一下,也比從新構建一個參數簡單不是嗎?
複製代碼
data
裏面的數據多的時候,給每一個數據加一個備註,會讓你後期往回看的時候很清晰
續上一點,data
裏面有不少數據的時候,可能你寫的時候是挺清晰的,畢竟都是你本身寫的東西,但是過了十天半個月,或者別人看你的代碼,相信我,無論是你本身,仍是別人,都是一頭霧水(記憶力超出常人的除外),因此咱們不妨給每一個數據後面加一個備註
data () {
return {
field1: 'value1', // 控制xxx顯示
field2: 'value2', // 頁面加載狀態
field3: [], // 用戶列表
...
fieldn: 'valuen' // XXXXXXXX
}
}
複製代碼
邏輯複雜的內容,儘可能拆成組件
假設咱們有一個這樣的場景:
<div>
<div>姓名:{{user1.name}}</div>
<div>性別:{{user1.sex}}</div>
<div>年齡:{{user1.age}}</div>
...此處省略999個字段...
<div>他隔壁鄰居的阿姨家小狗的名字:{{user1.petName}}</div>
</div>
<-- 固然,顯示中咱們不會傻到不用 v-for,咱們假設這種狀況沒法用v-for -->
<div>
<div>姓名:{{user2.name}}</div>
<div>性別:{{user2.sex}}</div>
<div>年齡:{{user2.age}}</div>
...此處省略999個字段...
<div>他隔壁鄰居的阿姨家小狗的名字:{{user2.petName}}</div>
</div>
複製代碼
這種狀況,咱們不妨把[用戶]的代碼,提取到一個組件裏面: 假設以下代碼,在 comUserInfo.vue
<template>
<div>
<div>姓名:{{user.name}}</div>
<div>性別:{{user.sex}}</div>
<div>年齡:{{user.age}}</div>
...此處省略999個字段...
<div>他隔壁鄰居的阿姨家小狗的名字:{{user.petName}}</div>
</div>
</template>
<script >
export default {
props:{
user:{
type:Object,
default: () => {}
}
}
}
</script>
複製代碼
而後原來的頁面能夠改爲這樣(省略掉導入和註冊組件,假設註冊的名字是 comUserInfo
):
<comUserInfo :user="user1"/>
<comUserInfo :user="user2"/>
複製代碼
這樣是否是清晰不少?不用看註釋,都能猜的出來,這是2個用戶信息模塊, 這樣作,還有一個好處就是出現錯誤的時候,你能夠更容易的定位到錯誤的位置。
若是你只在子組件裏面改變父組件的一個值,不妨試試 $emit('input')
,會直接改變 v-model
咱們正常的父子組件通訊是 父組件經過 props
傳給子組件,子組件經過 this.$emit('eventName',value)
通知父組件綁定在 @eventName
上的方法來作相應的處理。 可是這邊有個特例,vue
默認會監聽組件的 input
事件,並且會把子組件裏面傳出來的值,賦給當前綁定到 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
會自動幫你處理好
tip: 這種方法只適用於改變單個值的狀況,且子組件對父組件只需簡單的傳值,不須要其餘附加操做(如更新列表)的狀況。
補充一個 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>
複製代碼
該方法,我的認爲比較適用於 要更新的數據不能綁定在 v-model
的狀況下,或者要雙向通訊的數據大於 1 個(1個也能夠用,但我我的更推薦 input
的方式, 看我的喜愛吧),但又不會不少的狀況下.
conponents
放在 Vue options
的最上面
不知道你們有沒有這樣的經歷: 導入組件,而後在也頁面中使用,好的,報錯了,爲啥?忘記註冊組件了,爲何會常常忘記註冊組件呢?由於正常的一個 vue
實例的結構大概是這樣的:
import xxx form 'xxx/xxx'
export default {
name: 'component-name',
data () {
return {
// ...根據業務邏輯的複雜程度,這裏省略若干行
}
},
computed: {
// ...根據業務邏輯的複雜程度,這裏省略若干行
},
created () {
// ...根據業務邏輯的複雜程度,這裏省略若干行
},
mounted () {
// ...根據業務邏輯的複雜程度,這裏省略若干行
},
methods () {
// ...根據業務邏輯的複雜程度,這裏省略若干行
},
}
複製代碼
我不知道你們正常是把 components
屬性放在哪一個位置,反正我以前是放在最底下,結果就是致使常常犯上述錯誤。
後面我把 components
調到第一個去了
import xxx form 'xxx/xxx'
export default {
components: {
xxx
},
// 省略其餘代碼
}
複製代碼
今後之後,媽媽不再用擔憂我忘記註冊組件了,導入和註冊都在同一個位置,想忘記都難。
大部分狀況下,生命週期裏面,不要有太多行代碼,能夠封裝成方法,再調用
看過不少代碼,包括我本身以前的,在生命週期裏面洋洋灑灑的寫了一兩百行的代碼,如:把頁面加載的時候,該作的事,所有寫在 created
裏面,致使整個代碼難以閱讀,徹底不知道你在頁面加載的時候,作了些什麼, 這個時候,咱們不妨把那些邏輯封裝成方法,而後在生命週期裏面直接調用:
created () {
// 獲取用戶信息
this.getUserInfo()
// 獲取系統信息
this.getSystemInfo()
// 獲取配置
this.getConfigInfo()
},
methods:{
// 獲取用戶信息
getUserInfo () {...},
// 獲取系統信息
getSystemInfo () {...},
// 獲取配置
getConfigInfo () {...},
}
複製代碼
這樣是否是一眼就能看的出,你在頁面加載的時候作了些什麼?
tip: 這個應該算是一個約定俗成的規範吧,只是以爲看的比較多這樣寫的,加上我本身初學的時候,也這麼作了,因此寫出來,但願新入坑的同窗能避免這個問題
少用 watch
,若是你以爲你好多地方都須要用到 watch
,那十有八九是你對 vue
的 API
還不夠了解
vue
自己就是一個數據驅動的框架,數據的變更,能實時反饋到視圖上去,若是你想要根據數據來控制試圖,正常狀況一下配合 computed
服用就能解決大部分問題了,而視圖上的變更,咱們通常能夠經過監聽 input
change
等事件,達到實時監聽的目的, 因此不多有需求使用到 watch
的時候,至少我最近到的十來個項目裏面,是沒有用過 watch
固然,並非說 watch
是確定沒用處, vue
提供這個api,確定是有他的道理,也有部分需求是真的須要用到的,只是我以爲應該不多用到纔對,若是你以爲處處都得用到的話, 那麼我以爲 十有八九你應該多去熟悉一下 computed
和 vue
的其餘 api
了
本文的github地址 歡迎隨意star,follow, 和 不隨意的 issue
另外,github上還有其餘一些關於前端的教程和組件, 有興趣的童鞋能夠看看,大家的支持就是我最大的動力。