自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

前端如何修改組件庫源碼來封裝符合自己需求的組件?

開發(fā) 前端
產(chǎn)品中需要實(shí)現(xiàn)某項(xiàng)功能,常用的 elementui、antd 等組件庫中確實(shí)有差不多功能的組件。但實(shí)際上這些組件可能并不能滿足你的功能,或多或少都需要你去看看如何修改它才能滿足你的需求。

[[436888]]

 前端開發(fā)的同學(xué)們或許會(huì)遇到這樣的問題:產(chǎn)品中需要實(shí)現(xiàn)某項(xiàng)功能,常用的 elementui、antd 等組件庫中確實(shí)有差不多功能的組件。但實(shí)際上這些組件可能并不能滿足你的功能,或多或少都需要你去看看如何修改它才能滿足你的需求。

比如我曾遇到過 element-ui 中的「樹形控件」暴露出的參數(shù)沒有我需要的(獲取參數(shù));或者是「對話框」組件我需要給它的 body 加上上下兩條 border 等(樣式修改);還有「級聯(lián)選擇器」的多選可搜索功能:需要修改級聯(lián)看板使它保持展開,且當(dāng)子節(jié)點(diǎn)全部選中時(shí),不展示全部子節(jié)點(diǎn) tag 而只展示它的父節(jié)點(diǎn) tag(源碼無此功能)。

例如,我需要的功能是左二(因?yàn)槲也幌脒x項(xiàng)過多時(shí) tag 占得位置太大),而原組件如左一。我截了兩張圖對比:

關(guān)于組件庫可能要修改的地方,我將它們分為以下五類可供參考:

  •  樣式問題
  •  組件暴露的參數(shù)和方法不充分(源碼中存在)
  •  可利用部分功能,其余功能要自己開發(fā)封裝
  •  2+ 個(gè)組件之間的聯(lián)動(dòng),多合一
  •  完全沒有符合的組件

下面詳細(xì)說說這些問題,以及如何解決這些問題。如果有不滿足或更好的建議,歡迎指出。

1、組件樣式問題

當(dāng)修改單個(gè)文件的樣式時(shí),以 less 為例,如果你想要修改組件的樣式,可以使用 /deep/ 或 >>> 來深度選擇到你要修改的樣式(這能夠幫你省去一大串的類名)。 

  1. .dialog-wrapper {  
  2.     /deep/.el-dialog__body{  
  3.      border: solid 1px #999;  
  4.     }  

如果你要修改全局的樣式,第一種方法,你可以在全局樣式文件中寫樣式覆蓋,引入到 main.js 中即可全局生效。如下: 

  1. import "./assets/css/index.css"; 

第二,跟著組件庫提供的『自定義主題』教程修改,一般組件庫都會(huì)給出相關(guān)的教程。

2、組件暴露的參數(shù)和方法不充分

首先提出一個(gè)問題,你如何知道組件暴露的參數(shù)和方法不充分?其實(shí)答案很簡單:因?yàn)槲铱戳私M件庫的源碼。

當(dāng)我們想要獲取組件的一個(gè)參數(shù),首先是看文檔中提供了哪些 Attributes、Events、Methods。如果符合需求,直接拿來用就好。如果沒有你要的屬性和方法,請你先去看看源碼中提供了哪些東西沒有向外暴露出來的,但是我們能拿來用的。

舉個(gè)🌰,上述的「Cascader 級聯(lián)選擇器」,我想要在選中一個(gè)搜索的選項(xiàng)后不關(guān)閉看板。我在組件的 Events、Methods中沒有找到相關(guān)的方法控制看板展開,如下:

img

但當(dāng)我去 github 上看該組件的源碼時(shí),我發(fā)現(xiàn) toggleDropDownVisible() 方法是控制看板展開的。于是我在外部用 $refs 直接調(diào)用組件里的這個(gè)方法就好了。圖片

具體調(diào)用方法如下,這樣即使方法沒有暴露出來,也可以調(diào)用它內(nèi)部的方法: 

  1. <el-cascader  
  2.     ref="cascader" // ref獲取組件  
  3.     placeholder="試試搜索:指南"  
  4.     :options="options"  
  5.     :props="{ multiple: true }"  
  6.     filterable></el-cascader  
  7.     @visible-change="$refs.cascader.toggleDropDownVisible(true)"> // 調(diào)用組件及其方法 

3、可利用部分功能,其余功能要自己開發(fā)封裝

第三類其實(shí)我們用到的已經(jīng)比較少了,畢竟現(xiàn)在的組件庫已經(jīng)非常豐富了。但是這一步引起的思考確是很重要的,多看別人的源碼有助于提高自己封裝組件的水平。

當(dāng)要用到一個(gè)組件,但從頭開發(fā)這個(gè)組件既復(fù)雜又耗時(shí),而組件庫中這個(gè)組件需要再往上加一些功能就能為你所用時(shí),你可以考慮把組件庫的代碼拿到自己本地,修改它。

第一步你需要將組件代碼瀏覽一遍,了解它的邏輯??纯茨阈枰邮裁创a,如果在 vue 中,使用 computed、watch,或是修改 created、mounted、methods 就能完成你的功能,那么就大膽地嘗試。

舉個(gè)🌰

在 element-ui 中,它提供的多選可搜索級聯(lián)組件有一個(gè)問題:當(dāng)用戶選中全部子節(jié)點(diǎn)時(shí)不會(huì)合并為顯示父節(jié)點(diǎn)。要想完成這個(gè)功能,在經(jīng)歷過上述步驟一番探索后發(fā)現(xiàn)還是要修改源碼才能完成。于是我基于原本多選可搜索的級聯(lián)選擇器,進(jìn)行以下優(yōu)化:

  •  默認(rèn)看到級聯(lián)看板展開,不會(huì)收起 
  1. @visible-change="blurCascader(true)" // 可觸發(fā)展開  
  2. mounted() {  
  3.     this.blurCascader(true)  
  4.  
  5. // 失焦后觸發(fā)展開級聯(lián)看板(默認(rèn)失焦后關(guān)閉看板)  
  6. blurCascader() {  
  7.     this.$nextTick(() => {  
  8.         this.$refs.cascader.toggleDropDownVisible(true) // 調(diào)用組件內(nèi)部未暴露的方法  
  9.     })  
  10. }, 
  •  搜索選中后展示級聯(lián)看板,并勾選搜索選中的節(jié)點(diǎn) 
  1. // 響應(yīng)選中的節(jié)點(diǎn),選中節(jié)點(diǎn)后關(guān)閉選擇看板,展示級聯(lián)看板  
  2. changecascader(e) {  
  3. this.$refs.cascader.handleDropdownLeave()  
  4. }, 
  •  當(dāng)子級節(jié)點(diǎn)全部選中后,tag只展示一個(gè)父級節(jié)點(diǎn),而不是全部子節(jié)點(diǎn) 
  1. // 獲取所有勾選的節(jié)點(diǎn)  
  2.    getPresetTags() {  
  3.      const tree = this.panel.menus[0]  
  4.      const result = []  
  5.      loop(tree)  
  6.      // 遞歸查找選中的節(jié)點(diǎn)  
  7.      function loop(tree = []) {  
  8.        for (let i = 0; i < tree.length; i++) {  
  9.          const child = tree[i]  
  10.          if (child.checked) {                // checked 狀態(tài)表示選中  
  11.            result.push({ ...child, closable: true })  
  12.          } else if (child.indeterminate) {   // indeterminate 狀態(tài)表示待定,是半選  
  13.            child.children && loop(child.children)  
  14.          }  
  15.        }  
  16.      }  
  17.      this.presentFormatTags = result // 得到可顯示的 tag  
  18.    }, 
  •  刪除節(jié)點(diǎn)

由于我修改了 tag 的展示,所以它的 deleteTag 事件也要重寫。 

  1. deleteTag(index, tag) {  
  2.       let _ = this  
  3.       if (tag && tag.hasChildren) {  
  4.        // 當(dāng)刪除的節(jié)點(diǎn)是父節(jié)點(diǎn)時(shí)  
  5.         loop(tag.children)  
  6.         function loop(list) {  
  7.           for (let i = 0; i < list.length; i++) {  
  8.             if (list[i].hasChildren) {  
  9.               loop(list[i].children)  
  10.             } else {  
  11.               __.checkedValue = _.checkedValue.filter(n => n !== list[i].path)  
  12.               _.$emit('remove-tag', tag)  
  13.             }  
  14.           }  
  15.         }  
  16.       } else if (tag) {  
  17.       // 當(dāng)刪除的是子節(jié)點(diǎn)時(shí)  
  18.         thisthis.checkedValue = this.checkedValue.filter((n, i) => n !== tag.path)  
  19.         this.$emit('remove-tag', tag)  
  20.       } else {  
  21.       // 當(dāng)以回車鍵刪除時(shí)  
  22.         const temp = this.presentFormatTags[this.presentFormatTags.length - 1]  
  23.         temp && this.deleteTag(null, temp)  
  24.       }  
  25.       // 原本這個(gè)方法的代碼如下  
  26.       // const { checkedValue } = this  
  27.       // const val = checkedValue[index]  
  28.       // this.checkedValue = checkedValue.filter((n, i) => i !== index)  
  29.       // this.$emit('remove-tag', val) 
  30.     } 

其實(shí)修改組件庫代碼的過程并不難,主要是看懂它的邏輯,以及其中哪些東西是你可以用的。

上述組件的源碼可以在 GitHub[1] 查看。

4、2+ 個(gè)組件之間的聯(lián)動(dòng),多合一

到這一步,其實(shí)你已經(jīng)翻越最難的大山了!而這里要說的多個(gè)組件之間的聯(lián)動(dòng)其實(shí)已經(jīng)處于優(yōu)化用戶體驗(yàn)的道路上了。思考一下,什么時(shí)候會(huì)用到多個(gè)組件之間的聯(lián)動(dòng)呢?

其實(shí)場景有很多,例如將「Form 表單」、「Table 表格」和「Pagination 分頁」結(jié)合起來,封裝成一個(gè)組件,這樣在多表格的項(xiàng)目中直接使用就好了;

將 table 和 pagination 放到一個(gè)組件中: 

  1. <template lang="pug">  
  2. div  
  3.   .el-table  
  4.     template(v-for="(item, index) in columns" 
  5.       el-table-column(  
  6.         :prop="item.prop"  
  7.         :key="index"  
  8.         :label="item.label" 
  9.   el-pagination.pg-wrapper(  
  10.     layout="total, sizes, prev, pager, next, jumper"  
  11.     @size-change="handleSizeChange"  
  12.     @current-change="handleCurrentChange"  
  13.     :current-page="currentPage"  
  14.     :page-sizes="[10, 20, 50, 100]"  
  15.     :page-size="pagesize"  
  16.     :total="total"
  17.  </template> 

需要傳入的參數(shù)如下:列信息 columns、單頁數(shù)據(jù)量 pagesize、當(dāng)前頁碼 currentPage、表格數(shù)據(jù) tableData、數(shù)據(jù)總數(shù) total、表單查詢的參數(shù) query 等。 

  1. props: {  
  2.   // 列信息  
  3.   columns: {  
  4.     type: Array,  
  5.     default: [],  
  6.   }  
  7.   // 單頁數(shù)據(jù)量  
  8.   pagesize: {  
  9.     type: Number,  
  10.     default: 10, 
  11.   },  
  12.   // 當(dāng)前頁碼  
  13.   currentPage: { 
  14.     type: Number,  
  15.     default: 1,  
  16.   },  
  17.   // 表格數(shù)據(jù)  
  18.   tableData: {  
  19.     type: Array,  
  20.     default: [],  
  21.   }, 
  22.   // 數(shù)據(jù)總數(shù)  
  23.   total: {  
  24.     type: Number,  
  25.     default: 1000,  
  26.   },  
  27.   // 獲取數(shù)據(jù)的接口  
  28.   fetch:{  
  29.      type: function,  
  30.      default:() => {}  
  31.   },  
  32.   // 表單查詢的參數(shù)  
  33.   query:{  
  34.     type: Object,  
  35.     default: () => {}  
  36.   }  
  37. },  
  38. methods: {  
  39.   // 改變當(dāng)前頁碼 currentPage 時(shí)觸發(fā)  
  40.   handleCurrentChange: function (currentPage) {  
  41.     this.$emit('handleChange', this.pagesize, currentPage)  
  42.     this.fetch(this.query)  
  43.   },  
  44.   // 改變當(dāng)前頁 pageSize 時(shí)觸發(fā)  
  45.   handleSizeChange: function (pageSize) {  
  46.     this.$emit('handleChange', pageSize, this.currentPage)  
  47.     this.fetch(this.query)  
  48.   }  

使用時(shí)我們只需要傳以上的參數(shù)就可以直接調(diào)用這兩個(gè)組件了。

還有「表格中行選中狀態(tài)數(shù)據(jù)」,與「展示數(shù)據(jù)」之間的聯(lián)動(dòng)等等,可發(fā)揮之處有很多。將他們封裝后可以大大減輕重復(fù)的工作量,特別是像后臺(tái)管理類的項(xiàng)目,頁面間相似度很高的,尤其適合這種方法。

5、完全沒有符合的組件

如果你要的組件,外部的組件庫中都沒有提供,那就自己動(dòng)手封裝一個(gè)。盡可能將你的組件變得通用,兼容。嘗試想一想你的組件是否在其他情況下也能用。另外也可以多看看別人是如何封裝組件的,這有助于你自己開發(fā)。

如果你可以將你在前端開發(fā)道路上自己封裝的組件一個(gè)個(gè)收集起來,大概率可以方便你以后相同場景下直接復(fù)用,也有助于你的代碼解耦。

總結(jié)

如果你遇到了組件庫中的組件不合適的,先考慮看看是否能利用它的方法或?qū)傩赃_(dá)到效果,再看看能否修改它的代碼達(dá)成目的。如果最后實(shí)在不行,那么就自己動(dòng)手造輪子吧!自己造的輪子記得記下來,沒準(zhǔn)以后就能用上!

最后,Vue Demo Collection[2] 這個(gè)項(xiàng)目,是我在開發(fā)過程中遇到的通用 Vue 組件的 demo 收集,包含了 Vue/CSS/Echarts 等一些可以復(fù)用的組件 ❤️,基本上我認(rèn)為可以復(fù)用的組件和代碼片段我都會(huì)記錄在這,方便自己的回顧和使用,也算是個(gè)人成長的記錄。 

 

責(zé)任編輯:龐桂玉 來源: 前端大全
相關(guān)推薦

2021-10-07 09:03:44

Uniapp封裝組件

2021-04-30 17:35:16

前端開發(fā)技術(shù)熱點(diǎn)

2020-10-21 08:38:47

React源碼

2021-01-24 07:42:35

前端Table組件技術(shù)熱點(diǎn)

2022-09-16 07:46:10

組件庫設(shè)計(jì)結(jié)構(gòu)

2022-02-14 14:14:02

鴻蒙數(shù)據(jù)可視化JS

2021-11-22 10:00:33

鴻蒙HarmonyOS應(yīng)用

2022-05-13 21:20:23

組件庫樣式選擇器

2024-07-01 09:49:18

UI組件庫Radix

2023-02-27 09:10:57

前端組件設(shè)計(jì)

2021-09-17 06:56:54

前端Iconfont圖標(biāo)庫

2009-05-22 09:25:00

SQL Server版本SQL Server

2021-01-01 09:01:05

前端組件化設(shè)計(jì)

2014-05-26 16:52:29

移動(dòng)前端web組件

2022-02-15 13:55:08

圖片濾鏡glfx.jslena.js

2022-04-05 13:48:04

前端組件庫Web

2019-01-15 14:11:50

Android框架組件化

2010-01-13 13:53:32

VB.NET組件封裝

2022-02-14 08:58:00

架構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號