真實幹貨,走心分享!html
如何作一個優秀的時間管理者? lzx告訴咱們,天天少睡幾個小時,你就有更多的時間去作運動。程序員
對於程序員來講,天天少點時間寫業務,就有更多時間去作(hua)優(hua)化(shui)。api
咱們今天講的是Vue中如何更靈活的封裝業務組件,使效率翻倍。由於Ctrl + c
加Ctrl + v
都不足以知足咱們了,搬過來還要改一大堆東西。那怎麼辦嘛,還有比CV工程師
更快的職業嗎?數組
答案是有的!咱們稱其爲配置工程師
,簡單無腦!async
其實這個方法的核心思想就是封裝。可是封裝方式不一樣,使用起來也是天差地別。如何實現一個靈活易用的封裝,這就是咱們本篇文章的主要討論目標。函數
最簡單的封裝是什麼?就是往原組件外再套一層,而且保留全組件的全部功能。而後擴展本身的功能。post
假設咱們有一個組件x-button
,很遺憾這個組件竟然不支持加載狀態!那咋辦,爲了用戶體驗,咱們得給它加上加載狀態才行。因此咱們在它的基礎上封裝一個y-button
:fetch
<template>
<x-button>
<i v-if="loading" class="font-loading"></i>
<slot></slot>
</x-button>
</template>
複製代碼
export default {
name: 'YButton',
props: {
loading: {
type: Boolean,
default: false,
}
}
};
複製代碼
這樣一來,咱們的y-button
就支持loading
了!可是等等,若是咱們要給原來的x-button
傳遞屬性咋辦?簡單!ui
<template>
<x-button :size="size">
<i v-if="loading" class="font-loading"></i>
<slot></slot>
</x-button>
</template>
複製代碼
export default {
props: {
loading: {
type: Boolean,
default: false,
},
size: {
type: String,
default: undefined,
}
}
};
複製代碼
對就是這麼簡單,原組件的屬性,有一個加一個! 好累啊!!!咱們不能這麼作,這太不優雅了。好在Vue提供了$attrs
能夠解決這個問題。this
那麼$attrs
是幹哈的啊?
$attrs 包含了父做用域中不做爲 prop 被識別 (且獲取) 的 attribute 綁定 (class 和 style 除外)
簡單點來講也就是我不要的,全丟給你。那咱們來改寫一下。
<template>
<x-button v-bind="$attrs">
<i v-if="loading" class="font-loading"></i>
<slot></slot>
</x-button>
</template>
複製代碼
export default {
props: {
loading: {
type: Boolean,
default: false,
}
}
};
複製代碼
這樣寫,當咱們傳遞屬性給y-button
時,除了loading
之外,其餘所有屬性都會透傳給x-button
。這就是$attrs
的做用。
這是本篇關鍵的一步,也是效率提高最多的一步。 想想,當你對着原型圖一步一步寫出頁面配置,頁面就搭好了是什麼感受。
平常咱們用的最多,也是最多見的組件:表格+分頁!講真的,表格真的是無處不在!
優秀的表格組件有不少,但它們寫起來的確很複雜,並且充斥着大量重複代碼。是時候將它封裝一下了!咱們以el-table
爲基礎組件。
首先,el-table
是這樣用的:
<template>
<el-table :data="tableData">
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
</template>
複製代碼
export default {
data() {
return {
tableData: [
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀區金沙江路 1518 弄"
}
]
};
}
};
複製代碼
如今咱們開始改造這個組件,封裝一個f-table
!首先咱們要將這些el-table-column
都幹掉。
<template>
<div>
<el-table>
<el-table-column v-for="(col, i) in cols" :key="i" v-bind="col"> </el-table-column>
</el-table>
</div>
</template>
複製代碼
export default {
props: {
cols: {
type: Array,
default: () => []
}
}
};
複製代碼
這樣咱們在使用的時候就是這樣的:
<template>
<div>
<f-table cols=""></f-table>
</div>
</template>
複製代碼
export default {
data() {
return {
cols: [
{
prop: "date",
label: "日期",
width: "180",
formatter: dateFormatter
}
]
};
}
};
複製代碼
咱們經過最原始的調用知道el-table
是經過
<el-table :data="tableData">
複製代碼
data
屬性來傳遞數據的。咱們只要直接透傳數據數組就行了,可是咱們不這樣作,由於這裏咱們能夠作更多。咱們不直接傳入數據,而是傳入獲取數據的方法。
<template>
<div>
<el-table :data="tableData">
<!-- ... -->
</el-table>
</div>
</template>
複製代碼
export default {
props: {
// ...
fetch: {
type: Function,
default: () => Promise.resolve({ rows: [] })
}
},
data() {
return {
loading: false,
tableData: []
};
},
created() {
this.fetchData()
},
methods: {
async fetchData() {
this.loading = true;
try {
const { rows } = await this.fetch();
this.tableData = rows;
} catch (error) {
console.error(error);
} finally {
this.loading = false;
}
}
}!
};
複製代碼
你能夠看到咱們在獲取數據的時候能夠設置表格的加載狀態,處理錯誤。這裏咱們還能夠將分頁集成進去,不過這個後面再講。這能夠省去咱們不少工做!
咱們再來看看組件調用代碼:
<template>
<div>
<f-table :cols="cols" :fetch="fetchUsers"></f-table>
</div>
</template>
複製代碼
export default {
data() {
return {
cols: [
{
prop: "date",
label: "日期",
width: "180"
}
]
};
},
methods: {
fetchUsers() {
return {
rows: [{ name: "xxx", date: "xx" }]
};
}
}
};
複製代碼
咱們只須要關心怎麼獲取數據,要展現什麼數據。沒了!
OK!下面咱們順帶解決分頁問題,咱們使用的是el-pagination
。
<template>
<div>
<el-pagination :current-page.sync="currentPage" :total="total"> </el-pagination>
</div>
</template>
複製代碼
export default {
data() {
return {
currentPage: 1,
total: 0
};
}
};
複製代碼
<template>
<div>
<el-table :data="tableData">
<!-- -->
</el-table>
<el-pagination @current-change="fetchData" :current-page.sync="currentPage" :total="total">
</el-pagination>
</div>
</template>
複製代碼
export default {
// ...
data() {
return {
// ...
currentPage: 1,
total: 0
};
},
methods: {
async fetchData() {
// ...
const { rows, total } = await this.fetch(this.currentPage);
this.tableData = rows;
this.total = total;
}
}
};
複製代碼
咱們看一下咱們加了哪些東西:
fetch
的時候多返回了total
代表總數據,以便於分頁fetch
的時候向函數中傳入了當前頁碼而咱們的組件調用代碼,僅僅只增長了幾行:
<f-table :cols="cols" :fetch="fetchUsers"></f-table>
複製代碼
methods: {
async fetchUsers(currentPage) {
const query = {
page: currentPage
};
const { rows, total } = await api.getUsers(query);
return { rows, total };
}
}
複製代碼
這樣,一個帶有自動分頁的表格組件就封裝好了,使用起來十分簡單。
固然這並不能知足你的全部需求我知道。好比你想要使用表格最原始的el-table-column
,給表格列加個按鈕,加個輸入框什麼的。
要定製內容的時候,使用slot是最合適的。可是如何加在咱們的f-table
裏面呢?
還記得咱們使用cols
來配置el-table-column
。咱們只須要代表某個col
是某個slot
就行了。
<template>
<div>
<el-table :data="tableData">
<template v-for="(col, i) in cols">
<slot v-if="col.slot" :name="col.slot" />
<el-table-column v-else :key="i" v-bind="col"> </el-table-column>
</template>
</el-table>
</div>
</template>
複製代碼
使用方法:
<template>
<div>
<f-table :cols="cols" :fetch="fetchUsers">
<template slot="action">
<el-table-column>使用原生ElTableColumn的用法</el-table-column>
</template>
</f-table>
</div>
</template>
複製代碼
export default {
data() {
return {
cols: [
{
slot: 'operation'
},
{
prop: "date",
label: "日期",
width: "180"
}
]
};
}
}
複製代碼
一旦習慣這種方法,再配上各類formatter
,寫頁面真的無腦,就差改爲拖拽了(有沒有嗅到什麼)!
寫做不易,懇求你們動動手指點個關注點個贊!