摘要:里邊涉及到的指令是自定義的指令,為了處理移動(dòng)端的點(diǎn)擊操作,我還整理了一片陋文移動(dòng)點(diǎn)擊長(zhǎng)按滑動(dòng)指令然后這個(gè)組件的源碼我放在了我出來(lái)的項(xiàng)目上謝謝各位品嘗,
公司移動(dòng)端開(kāi)發(fā)平臺(tái)進(jìn)行了大變革,前端架構(gòu)由DCloud大生態(tài)轉(zhuǎn)換為VUE,所以移動(dòng)端的UI組件庫(kù)從MUI改為使用MintUI,然后開(kāi)始大刀闊斧的把MintUI組件改成MUI組件的樣子,然后發(fā)現(xiàn)少了幾個(gè)較為常用的,其中一個(gè)就是,嗯,側(cè)滑面板(也叫側(cè)滑菜單,也叫抽屜面板-andriod官方是這么翻譯的,很形象)。但是,它就是一個(gè)布局組件,具體里邊菜單什么的,那都是浮云(嗯,就是愛(ài)用幾年前的流行詞匯,而且很喜歡在網(wǎng)上沖浪和踩別人的空間)
開(kāi)發(fā)一個(gè)側(cè)滑面板(類似QQ、網(wǎng)易郵箱等app的)
可以在左邊,也可以在右邊
側(cè)滑面板內(nèi)容隨意定制
側(cè)滑面板相對(duì)的就有主面板,那么衍生出不同的體位和姿勢(shì)
(1)主面板滑動(dòng),側(cè)滑面板不動(dòng)
(2)側(cè)滑面板動(dòng),主面板不動(dòng)
(3)它倆一塊動(dòng),一起--------
代碼風(fēng)格盡量和MintUI的其他組件風(fēng)格類似(這個(gè)挺重要的)
參考mintUI組件中同樣??滑動(dòng)操作的tabContainer,為了滿足需求5,我連函數(shù)名都抄了過(guò)來(lái)。
不說(shuō)廢話,上代碼吧
The Waaaaaaaay 1. 設(shè)計(jì)組件結(jié)構(gòu)這個(gè)組件分為兩部分,一部分為側(cè)滑面板容器,另一部分為主面板容器,然后具體容器內(nèi)部直接放了插槽,然后還需要一個(gè)主面板容器的遮罩,為了側(cè)滑面板打開(kāi)的時(shí)候顯現(xiàn)出來(lái)。上代碼了
2. 配置設(shè)計(jì)
這塊加了一些我們公司的一些需求,可能各位哥哥姐姐門用不到里邊的一些props的設(shè)計(jì),僅供參考
props: { // 側(cè)滑面板的寬度(單位px) "drawerWidth": { type: Number, default: 200 }, // 是否可用 "enable": { type: Boolean, default: true }, // 側(cè)滑菜單是否在右邊,默認(rèn)為false,在左邊 "isRight": { type: Boolean, default: false }, // 側(cè)滑菜單滑動(dòng)操作類型 // ["fixDrawer"——固定側(cè)滑面板,主面板滑動(dòng)] // ["fixContent"——固定主面板,側(cè)滑面板滑動(dòng)] // ["noFixed"——一起滑動(dòng)!] "swipeType": { type: String, default: "fixDrawer" }, // 點(diǎn)擊出現(xiàn)側(cè)滑菜單的按鈕的id ( @TODO 這里如何處理異步渲染的問(wèn)題 ) "btnId": { type: String, default: "" }, // 狀態(tài)位,側(cè)滑面板是否為打開(kāi)狀態(tài) // (因?yàn)槲覀児居羞@種一開(kāi)始就把側(cè)滑菜單打開(kāi)的shabee場(chǎng)景,所以這才會(huì)有這么個(gè)東西) //(如果這個(gè)不希望配置的話、可以放在data里邊) "isDrawerOpened": { type: Boolean, default: false }, // 是否可滑動(dòng),如果不可滑動(dòng)的話,就只能通過(guò)調(diào)用toogle方法打開(kāi)側(cè)滑面板 // 這個(gè)也是公司的一個(gè)使用場(chǎng)景,就是你甭滑,找個(gè)按鈕觸發(fā)一下側(cè)滑面板打開(kāi)的方法才能打開(kāi) //(如果這個(gè)不希望配置的話、也可以放在data里邊) "swipeable": { type: Boolean, default: true } }2. 樣式設(shè)計(jì)
不得不承認(rèn),我的css寫的shit
對(duì)于整個(gè)的組件來(lái)說(shuō),它應(yīng)該是默認(rèn)充滿整個(gè)父容器的,而且這個(gè)組件,我覺(jué)得,一般都是用來(lái)放在最外層的一個(gè)布局組件,所以,默認(rèn)充滿窗口就行了
所以組件的最外層來(lái)一個(gè)絕對(duì)布局,然后如下:
.mint-drawer-layout { position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow-x: hidden; }
然后側(cè)滑面板,只需要縱向充滿就可以了,寬度是配置
.mint-drawer-warp { position: absolute; top: 0; bottom: 0; }
然后是主面板,沒(méi)說(shuō)的
.mint-content-warp { position: relative; width: 100%; height: 100%; }4. 關(guān)鍵實(shí)現(xiàn)
終于來(lái)到了介紹到底該怎么實(shí)現(xiàn)的了
首先第一步上來(lái)就要設(shè)置一個(gè)記錄滑動(dòng)操作的狀態(tài)變量——dragging,設(shè)置為false,方便屏蔽滑動(dòng)時(shí)觸發(fā)的其他操作的執(zhí)行
——開(kāi)始的時(shí)候記錄開(kāi)始滑動(dòng)的位置
——滑動(dòng)中,dragging狀態(tài)記錄為true,開(kāi)始進(jìn)行滑動(dòng)位置和手指移動(dòng)的聯(lián)動(dòng)
——滑動(dòng)結(jié)束,dragging狀態(tài)記錄為false,計(jì)算當(dāng)前的滑動(dòng)位置,判斷是劃開(kāi)側(cè)滑面板還是關(guān)閉,并進(jìn)行動(dòng)畫處理
其中幾個(gè)細(xì)節(jié)小談一哈
(1)左右滑動(dòng)操作觸發(fā)的判斷:我這邊是公司的規(guī)范,橫軸移動(dòng)位移大于五,豎軸位移不大于橫軸的1.73倍就可以
(2)最后結(jié)束時(shí)判斷側(cè)滑面板的打開(kāi)和關(guān)閉:是這樣的,我這邊取的是三分之一的側(cè)滑面板的寬度,也就是從打開(kāi)到關(guān)閉,那么像關(guān)閉的方向滑動(dòng)側(cè)滑面板寬度的三分之一就可以了,如果是關(guān)閉到打開(kāi),往打開(kāi)的方向滑動(dòng)三分之一就可以了
(3)左側(cè)和右側(cè),還有三種不同的滑動(dòng)方式:三種不同的滑動(dòng)方式實(shí)際上就是控制到底哪個(gè)面板隨著手指動(dòng),具體的動(dòng)作過(guò)程和面板的偏移量實(shí)際上是一樣的。左右兩側(cè)就更簡(jiǎn)單了,直接是對(duì)稱的操作就可
滑動(dòng)結(jié)束的操作,參考的tabcontainer,也挺巧妙的,各位請(qǐng)上眼~
/** * 滑動(dòng)結(jié)束的動(dòng)畫 */ swipeLeaveTransition() { let g = this, currentMovingDoms = []; let {swipeType, drawerWidth} = g; switch (swipeType) { case "fixDrawer": currentMovingDoms.push(g.content); break; case "fixContent": currentMovingDoms.push(g.drawer); break; case "noFixed": currentMovingDoms.push(g.drawer); currentMovingDoms.push(g.content); break; default: break; } currentMovingDoms.forEach((val) => { val.classList.add("swipe-transition"); }); setTimeout(() => { if (g.isDO) { this.swipeMove(drawerWidth); } else { this.swipeMove(0); g.contentMask.style.opacity = 0; g.contentMask.style.display = "none"; } g.isToggle = false; currentMovingDoms.forEach((val) => { once(val, "webkitTransitionEnd", _ => { val.classList.remove("swipe-transition"); g.swiping = false; }); }); }, 0); }, /** * 滑動(dòng)操作 * @param offset 滑動(dòng)位置 */ swipeMove(offset) { let g = this; let {swipeType, isRight} = g; g.contentMask.style.display = "block"; g.contentMask.style.opacity = Math.abs(offset) / g.drawerWidth * 0.4; switch (swipeType) { case "fixDrawer": g.content.style.webkitTransform = `translate3d(${(!isRight ? "" : "-") + offset}px, 0, 0)`; g.swiping = true; break; case "fixContent": g.drawer.style.webkitTransform = `translate3d(${(!isRight ? "" : "-") + offset}px, 0, 0)`; g.swiping = true; break; case "noFixed": g.content.style.webkitTransform = `translate3d(${(!isRight ? "" : "-") + offset}px, 0, 0)`; g.drawer.style.webkitTransform = `translate3d(${(!isRight ? "" : "-") + offset}px, 0, 0)`; g.swiping = true; break; default: break; } }, // 開(kāi)始滑動(dòng) startDrag(evt) { let g = this; if (!g.enable || !g.swipeable) return false; evt = evt.changedTouches ? evt.changedTouches[0] : evt; g.start.x = evt.pageX; g.start.y = evt.pageY; }, // 滑動(dòng)中 onDrag(evt) { let g = this, swiping; if (!g.enable || !g.swipeable) return false; g.dragging = true; const e = evt.changedTouches ? evt.changedTouches[0] : evt; const offsetTop = e.pageY - g.start.y; const offsetLeft = e.pageX - g.start.x; const y = Math.abs(offsetTop); const x = Math.abs(offsetLeft); swiping = !(x < 5 || (x >= 5 && y >= x * 1.73)); if (!swiping) return; evt.preventDefault(); let offset; if (g.isDO) { offset = g.isRight ? (g.drawerWidth - offsetLeft) : (g.drawerWidth - (-offsetLeft)); } else { offset = g.isRight ? -offsetLeft : offsetLeft; } if (offset < 0 || offset > g.drawerWidth) { g.swiping = false; return; } g.offset = offset; g.swipeMove(offset); }, // 結(jié)束滑動(dòng) endDrag() { let g = this; if (!g.enable || g.isToggle || !g.dragging) { return false; } const tempWidth = g.drawerWidth / 3; if (g.isDO && g.offset < tempWidth * 2) { g.isDO = false; } else if (!g.isDO && g.offset > tempWidth) { g.isDO = true; } g.dragging = false; g.swipeLeaveTransition(); }
好啦,到這應(yīng)該就差不多了。。。
里邊涉及到的v-tap指令是自定義的指令,為了處理移動(dòng)端的點(diǎn)擊操作,我還整理了一片陋文:https://segmentfault.com/a/11... (移動(dòng)點(diǎn)擊長(zhǎng)按滑動(dòng)vue指令)
然后這個(gè)組件的源碼我放在了我fork出來(lái)的mintUI項(xiàng)目上
https://github.com/LylaYuKako...
謝謝各位品嘗,
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94272.html
摘要:學(xué)習(xí)成本很低,另外官方有比較完善的中文文檔。簡(jiǎn)單本身是沒(méi)有錯(cuò)誤,一個(gè)東西能以簡(jiǎn)單的方式解決難道不好嗎關(guān)于這個(gè)中文文檔居然還有人噴那些喜歡用的是不是英文能力差,我就再報(bào)以呵呵一笑。本身?yè)碛兄形奈臋n就是一個(gè)優(yōu)勢(shì),結(jié)果還成了被噴的地方。 前言 由于這段時(shí)間工作上也是挺忙的,就沒(méi)有時(shí)間去寫這個(gè)項(xiàng)目,中間一直都是寫寫停停,進(jìn)度也是非常慢的。正好前幾天都還比較空,就趕緊抓著空閑時(shí)間去寫這個(gè)項(xiàng)目,最...
摘要:本文介紹一個(gè)簡(jiǎn)單的類似的布局組件的實(shí)現(xiàn),基于。介紹的內(nèi)容已經(jīng)制作成組件。即當(dāng)不可以拖出抽屜時(shí),應(yīng)觸發(fā)默認(rèn)事件,比如垂直方向的滾動(dòng)等等。這種優(yōu)化可以將一部分復(fù)雜的計(jì)算工作提前準(zhǔn)備好,使頁(yè)面的反應(yīng)更為快速靈敏。 本文介紹一個(gè)簡(jiǎn)單的DrawerLayout(類似Android的DrawerLayout)布局組件的實(shí)現(xiàn),基于Vue.js。介紹的內(nèi)容已經(jīng)制作成 vue-drawer-layout...
閱讀 3183·2021-11-08 13:18
閱讀 2317·2019-08-30 15:55
閱讀 3626·2019-08-30 15:44
閱讀 3095·2019-08-30 13:07
閱讀 2802·2019-08-29 17:20
閱讀 1975·2019-08-29 13:03
閱讀 3448·2019-08-26 10:32
閱讀 3246·2019-08-26 10:15