<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本篇文章記錄仿寫一個el-collapse
元件細節,從而有助於大家更好理解餓了麼ui對應元件具體工作細節。
本文是elementui原始碼學習仿寫系列的又一篇文章,後續空閒了會不斷更新並仿寫其他元件。原始碼在github上,大家可以拉下來,npm start執行跑起來,結合註釋有助於更好的理解。github倉庫地址如下:https://github.com/shuirongsh...
el-collapse
即為摺疊面板的意思,一般主要是用於:對複雜區域進行分組和隱藏,保持頁面的整潔,有分類整理的意思。
collapse
有摺疊的意思,不過fold
也有摺疊的意思。所以筆者這裡封裝的元件就改名字了,不叫my-collapse
,叫做my-fold
我們先看一下下圖摺疊元件的結構圖
結合上圖已經工作經驗,大致分析元件的需求有以下:
一般情況下父元件更改子元件資料狀態有以下方式:
this.$refs.child.xxx = yyy
,給子元件打一個ref
,直接更改對應值即可this.$children
可以存取所有的子元件範例物件。所以,也可以直接更改,如下:父元件程式碼
// html <template> <div> <h2>下方為三個子元件</h2> <child1 /> <child2 /> <child3 /> <button @click="changeChildData">點選按鈕更改所有子元件資料</button> </div> </template> // js changeChildData() { // this.$children拿到所有子元件範例物件的陣列,遍歷存取到資料,更改之 this.$children.forEach((child) => { child.flag = !child.flag; }); },
其中一個子元件程式碼,另外兩個也一樣
// html <template> <div>child1中的flag--> {{ flag }}</div> </template> // js <script> export default { data() { return { flag: false } }, }; </script>
效果圖
為什麼要提到這個呢?因為手風琴模式下的摺疊面板會用到這個方式去更改別的面板,使別的面板關閉
高度的過渡,主要是從0到某個高度,以及從某個高度到0的變化,需要搭配transition
以及overflow
屬性去控制。我們先看一下簡單的寫法和效果圖,再看一下封裝的元件的程式碼
1.簡單寫法
伸手黨福利,複製貼上即可使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .target { width: 120px; height: 120px; line-height: 120px; text-align: center; background-color: #baf; /* 以下兩個是必要的樣式控制屬性 */ transition: height 0.2s linear; overflow: hidden; } </style> </head> <body> <button>點選高度變化</button> <br> <br> <div class="target">過渡的dom</div> <script> let isOpen = true // 初始情況下,標識狀態為開啟狀態 let btn = document.querySelector('button') let targetDom = document.querySelector('.target') btn.onclick = () => { // 若為展開狀態,就將其高度置為0,因為css有過渡程式碼,所以高度過渡效果就出來了 if (isOpen) { targetDom.style.height = 0 + 'px' isOpen = false } // 若為關閉狀態,就將其高度置為原來,因為css有過渡程式碼,所以高度過渡效果就出來了 else { targetDom.style.height = 120 + 'px' isOpen = true } } </script> </body> </html>
2.簡單寫法效果圖
在我們封裝摺疊面板的時候,這個高度變化的過渡元件是必須要有的,沒有的話,摺疊面板展開關閉時,會有點突兀,加上一個元件,會絲滑不少。
3.摺疊元件的封裝
理解了上述的簡單案例,再將其思路應用到元件封裝中去即可
高度元件封裝程式碼思路:
根據show
變數的標識,去更改dom.style.height
;
初始載入時,獲取初始高度`dom.offsetHeight更改一次、當show變數標識發生變化的時候,再更改一次。
同時搭配高度的transition樣式控制即可(即:監聽props中show`標識的變化更改之)
封裝好的高度過渡元件程式碼如下:
<template> <div class="transitionWrap" ref="transitionWrap"> <slot></slot> </div> </template> <script> export default { props: { // 布林值show標識關閉還是展開 show: Boolean, }, data() { return { height: 0, }; }, mounted() { /* dom載入完畢,然後根據標識show去手動更新高度 */ this.$nextTick(() => { this.height = this.$refs.transitionWrap.offsetHeight; this.$refs.transitionWrap.style.height = this.show ? `${this.height}px` : 0; }); // this.$nextTick().then(() => { ... } }, watch: { /* 再監聽標識的變化,從而更改高度,即關閉還是展開 */ show(newVal) { this.$refs.transitionWrap.style.height = newVal ? `${this.height}px` : 0; }, }, }; </script> <style scoped> /* 關鍵css樣式,高度線性勻速過渡 */ .transitionWrap { transition: height 0.2s linear; overflow: hidden; } </style>
另外餓了麼UI也提供了el-collapse-transition
元件,也是一個不錯的選擇
封裝一套強大的開源元件其實要考慮的東西很多,比如需要適配螢幕閱讀器,我們看一下餓了麼UI的el-collapse
元件使用到的兩個螢幕閱讀器屬性role
和aria-multiselectable
。如下圖:
role
屬性是html中語意化標籤的進一步補充(如 螢幕閱讀器,給盲人使用),另舉一個例子<div role="checkbox" aria-checked="checked" />
高度螢幕閱讀器,此處有一個核取方塊,而且已經被選中了aria-multiselectable='true'
告知輔助裝置,一次可以展開多個項,還是隻能展開一個詳情 css http://edu.jb51.net/jqueryui/jqueryui-intro.html
由此可以看出,一套開源的元件,的確是方方面面都要考慮到。
我們先看一下效果圖
<template> <div> <!-- 手風琴模式 --> <my-fold v-model="openArr" accordion @change="changeFn"> <my-fold-item title="第一項" name="one">我是第一項的內容</my-fold-item> <my-fold-item title="第二項" name="two"> <p>我是第二項的內容</p> <p>我是第二項的內容</p> </my-fold-item> <my-fold-item title="第三項" name="three"> <p>我是第三項的內容</p> <p>我是第三項的內容</p> <p>我是第三項的內容</p> </my-fold-item> <my-fold-item title="第四項" name="four"> <p>我是第四項的內容</p> <p>我是第四項的內容</p> <p>我是第四項的內容</p> <p>我是第四項的內容</p> </my-fold-item> </my-fold> <br /> <!-- 可展開多個模式 --> <my-fold v-model="openArr2" @change="changeFn"> <my-fold-item title="第一項" name="one">我是第一項的內容</my-fold-item> <my-fold-item title="第二項" name="two"> <p>我是第二項的內容</p> <p>我是第二項的內容</p> </my-fold-item> <my-fold-item title="第三項" name="three"> <p>我是第三項的內容</p> <p>我是第三項的內容</p> <p>我是第三項的內容</p> </my-fold-item> <my-fold-item title="第四項" name="four"> <p>我是第四項的內容</p> <p>我是第四項的內容</p> <p>我是第四項的內容</p> <p>我是第四項的內容</p> </my-fold-item> </my-fold> </div> </template> <script> export default { data() { return { // 手風琴模式的陣列項要麼沒有項,要麼只能有一個項 openArr: [], // 可展開多個的陣列,可以有多個項 openArr2: ["one", "two"], }; }, methods: { changeFn(name, isOpen, vNode) { console.log(name, isOpen, vNode); }, }, }; </script>
<template> <div class="myFoldWrap"> <slot></slot> </div> </template> <script> export default { name: "myFold", props: { // 是否開啟手風琴模式(每次只能展開一個面板) accordion: { type: Boolean, default: false, // 預設不開啟(可展開多個) }, // 父元件v-model傳參,子元件props中key為'value'接收,'input'事件更改 value: { type: Array, // 手風琴模式的陣列項只能有一個,反之可以有多個 default() { return []; }, }, }, data() { return { // 展開的項可一個,可多個(使用層v-model陣列傳的有誰,就展開誰) openArr: this.value, // 收集誰需要展開 }; }, mounted() { // 手動加一個校驗 if (this.accordion & (this.value.length > 1)) { console.error("手風琴模式下,繫結的陣列最多一項"); } }, watch: { // 監聽props中value的變化,及時更新 value(value) { this.openArr = value; }, }, methods: { updateVModel(name, isOpen, vNode) { // 若為手風琴模式 if (this.accordion) { // 當某一項開啟的時候,才去關閉其他項 isOpen ? this.closeOther(name) : null; this.openArr = [name]; // 手風琴模式只保留(展開)一個 } // 若為可展開多項模式 else { let i = this.openArr.indexOf(name); // 包含就刪掉、不包含就追加 i > -1 ? this.openArr.splice(i, 1) : this.openArr.push(name); } // 無論那種模式,都需要更改並通知外層使用元件 this.$emit("input", this.openArr); // input事件控制v-model的資料更改 this.$emit("change", name, isOpen, vNode); // change事件丟擲去,供使用者使用 }, closeOther(name) { this.$children.forEach((item) => { // 將除了自身以外的都置為false,故其他的就都摺疊上了 if (item.name != name) { item.isOpen = false; } }); }, }, }; </script> <style lang="less" scoped> .myFoldWrap { border: 1px solid #e9e9e9; } </style>
<template> <div class="foldItem"> <!-- 頭部部分,主要是點選時展開內容,以及做小箭頭的旋轉,和頭部的標題呈現 --> <div class="foldItemHeader" @click="handleHeaderClick"> <i v-if="!hiddenArrow" class="el-icon-arrow-right" :class="{ rotate90deg: isOpen }" ></i> {{ title }} </div> <!-- 內容體部分,主要是展開摺疊時加上高度過渡效果,這裡封裝了一個額外的工具元件 --> <transition-height class="transitionHeight" :show="isOpen"> <div class="foldItemBody"> <slot></slot> </div> </transition-height> </div> </template> <script> import transitionHeight from "@/components/myUtils/transitionHeight/index.vue"; export default { name: "myFoldItem", components: { transitionHeight, // 高度過渡元件 }, props: { title: String, // 摺疊面板的標題 name: String, // 摺疊面板的名字,即為唯一識別符號(不可與其他重複!) // 是否隱藏小箭頭,預設false,即展示小箭頭 hiddenArrow: { type: Boolean, default: false, }, }, data() { return { // true為展開即open,false為摺疊 // 初始情況下取到父元件myFold元件的展開的陣列,看看自身是否在其中 isOpen: this.$parent.openArr.includes(this.name), }; }, methods: { // 點選展開或摺疊 handleHeaderClick() { this.isOpen = !this.isOpen; // 內容依託於變數isOpen直接更新即可 this.$parent.updateVModel(this.name, this.isOpen, this); // 於此同時也要通知父元件去更新 }, }, }; </script> <style lang="less" scoped> .foldItem { width: 100%; height: auto; // 高度由內容區撐開 .foldItemHeader { box-sizing: border-box; padding-left: 8px; min-height: 50px; display: flex; align-items: center; background-color: #fafafa; cursor: pointer; border-bottom: 1px solid #e9e9e9; // 展開摺疊項時,小圖示旋轉效果 i { transform: rotate(0deg); transition: all 0.24s; margin-right: 8px; } .rotate90deg { transform: rotate(90deg); transition: all 0.24s; } } .foldItemBody { width: 100%; height: auto; box-sizing: border-box; padding: 12px 12px 12px 8px; border-bottom: 1px solid #e9e9e9; } } // 去除和父元件的邊框重疊 .foldItem:last-child .foldItemHeader { border-bottom: none !important; } .foldItem:last-child .transitionHeight .foldItemBody { border-top: 1px solid #e9e9e9; border-bottom: none !important; } </style>
上述程式碼結合註釋,更好的理解哦
以上就是elementui原始碼學習仿寫el-collapse範例的詳細內容,更多關於elementui仿寫el-collapse的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45