<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 5182字,需瀏覽 11分鐘

           ·

          2021-12-20 12:54


          點(diǎn)擊上方?前端陽光,關(guān)注公眾號

          回復(fù)加群,加入技術(shù)交流群交流群

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

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

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

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

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

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

          1、組件樣式問題

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

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

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

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

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

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

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

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

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

          img

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

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

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

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

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

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

          第一步你需要將組件代碼瀏覽一遍,了解它的邏輯。看看你需要加什么代碼,如果在 vue 中,使用 computedwatch,或是修改 createdmountedmethods 就能完成你的功能,那么就大膽地嘗試。

          舉個

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

          • 默認(rèn)看到級聯(lián)看板展開,不會收起
          @visible-change="blurCascader(true)"?//?可觸發(fā)展開

          mounted()?{
          ????this.blurCascader(true)
          }

          //?失焦后觸發(fā)展開級聯(lián)看板(默認(rèn)失焦后關(guān)閉看板)
          blurCascader()?{
          ????this.$nextTick(()?=>?{
          ????????this.$refs.cascader.toggleDropDownVisible(true)?//?調(diào)用組件內(nèi)部未暴露的方法
          ????})
          },

          • 搜索選中后展示級聯(lián)看板,并勾選搜索選中的節(jié)點(diǎn)
          //?響應(yīng)選中的節(jié)點(diǎn),選中節(jié)點(diǎn)后關(guān)閉選擇看板,展示級聯(lián)看板
          changecascader(e)?{
          this.$refs.cascader.handleDropdownLeave()
          },

          • 當(dāng)子級節(jié)點(diǎn)全部選中后,tag只展示一個父級節(jié)點(diǎn),而不是全部子節(jié)點(diǎn)
          ?//?獲取所有勾選的節(jié)點(diǎn)
          ????getPresetTags()?{
          ??????const?tree?=?this.panel.menus[0]
          ??????const?result?=?[]
          ??????loop(tree)
          ??????//?遞歸查找選中的節(jié)點(diǎn)
          ??????function?loop(tree?=?[])?{
          ????????for?(let?i?=?0;?i???????????const?child?=?tree[i]
          ??????????if?(child.checked)?{????????????????//?checked?狀態(tài)表示選中
          ????????????result.push({?...child,?closable:?true?})
          ??????????}?else?if?(child.indeterminate)?{???//?indeterminate?狀態(tài)表示待定,是半選
          ????????????child.children?&&?loop(child.children)
          ??????????}
          ????????}
          ??????}
          ??????this.presentFormatTags?=?result?//?得到可顯示的?tag
          ????},

          • 刪除節(jié)點(diǎn)

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

          deleteTag(index,?tag)?{
          ??????let?_?=?this
          ??????if?(tag?&&?tag.hasChildren)?{
          ???????//?當(dāng)刪除的節(jié)點(diǎn)是父節(jié)點(diǎn)時
          ????????loop(tag.children)
          ????????function?loop(list)?{
          ??????????for?(let?i?=?0;?i?????????????if?(list[i].hasChildren)?{
          ??????????????loop(list[i].children)
          ????????????}?else?{
          ??????????????_.checkedValue?=?_.checkedValue.filter(n?=>?n?!==?list[i].path)
          ??????????????_.$emit('remove-tag',?tag)
          ????????????}
          ??????????}
          ????????}
          ??????}?else?if?(tag)?{
          ??????//?當(dāng)刪除的是子節(jié)點(diǎn)時
          ????????this.checkedValue?=?this.checkedValue.filter((n,?i)?=>?n?!==?tag.path)
          ????????this.$emit('remove-tag',?tag)
          ??????}?else?{
          ??????//?當(dāng)以回車鍵刪除時
          ????????const?temp?=?this.presentFormatTags[this.presentFormatTags.length?-?1]
          ????????temp?&&?this.deleteTag(null,?temp)
          ??????}
          ??????//?原本這個方法的代碼如下
          ??????//?const?{?checkedValue?}?=?this
          ??????//?const?val?=?checkedValue[index]
          ??????//?this.checkedValue?=?checkedValue.filter((n,?i)?=>?i?!==?index)
          ??????//?this.$emit('remove-tag',?val)
          ????}

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

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

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

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

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

          tablepagination 放到一個組件中:

          "pug">
          div
          ??.el-table
          ????template(v-for="(item,?index)?in?columns")
          ??????el-table-column(
          ????????:prop="item.prop"
          ????????:key="index"
          ????????:label="item.label")

          ??el-pagination.pg-wrapper(
          ????layout="total,?sizes,?prev,?pager,?next,?jumper"
          ????@size-change="handleSizeChange"
          ????@current-change="handleCurrentChange"
          ????:current-page="currentPage"
          ????:page-sizes="[10,?20,?50,?100]"
          ????:page-size="pagesize"
          ????:total="total")


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

          props:?{
          ??//?列信息
          ??columns:?{
          ????type:?Array,
          ????default:?[],
          ??}
          ??//?單頁數(shù)據(jù)量
          ??pagesize:?{
          ????type:?Number,
          ????default:?10,
          ??},
          ??//?當(dāng)前頁碼
          ??currentPage:?{
          ????type:?Number,
          ????default:?1,
          ??},
          ??//?表格數(shù)據(jù)
          ??tableData:?{
          ????type:?Array,
          ????default:?[],
          ??},
          ??//?數(shù)據(jù)總數(shù)
          ??total:?{
          ????type:?Number,
          ????default:?1000,
          ??},
          ??//?獲取數(shù)據(jù)的接口
          ??fetch:{
          ?????type:?function,
          ?????default:()?=>?{}
          ??},
          ??//?表單查詢的參數(shù)
          ??query:{
          ????type:?Object,
          ????default:?()?=>?{}
          ??}
          },
          methods:?{
          ??//?改變當(dāng)前頁碼?currentPage?時觸發(fā)
          ??handleCurrentChange:?function?(currentPage)?{
          ????this.$emit('handleChange',?this.pagesize,?currentPage)
          ????this.fetch(this.query)
          ??},
          ??//?改變當(dāng)前頁?pageSize?時觸發(fā)
          ??handleSizeChange:?function?(pageSize)?{
          ????this.$emit('handleChange',?pageSize,?this.currentPage)
          ????this.fetch(this.query)
          ??}
          }

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

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

          5、完全沒有符合的組件

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

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

          總結(jié)

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

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

          作者:Huup_We 鏈接:https://juejin.cn/post/6917771825808146446 來源:稀土掘金 著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

          參考資料

          [1]

          GitHub: https://github.com/Gesj-yean/vue-demo-collection/tree/master/docs/.vuepress/components/cascader

          [2]

          Vue Demo Collection: https://github.com/Gesj-yean/vue-demo-collection


          作者:Huup_We

          https://juejin.cn/post/6917771825808146446


          技術(shù)交流群


          我組建了技術(shù)交流群,里面有很多?大佬,歡迎進(jìn)來交流、學(xué)習(xí)、共建。回復(fù)加群即可。




          ???“分享、點(diǎn)贊在看” 支持一波??

          瀏覽 42
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久久久亚洲AV色欲av | 亚洲第一视频网站 | 国产精品无码成人久久久 | 免费黄色毛片 | 午夜视频网|