国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

小程序原生實(shí)現左滑抽屜菜單

發(fā)布時(shí)間:2021-08-17 12:16 來(lái)源: 閱讀:0 作者:Skuld_yi''s Blog 欄目: JavaScript 歡迎投稿:712375056

目錄

                在移動(dòng)端,側滑菜單是一個(gè)很常用的組件(通常稱(chēng)作 Drawer,抽屜)。因為現在手機屏幕太大,點(diǎn)擊角落的菜單按鈕明顯不如在屏幕中間滑動(dòng)方便。

                相比其他平臺,小程序的組件庫支持明顯還不夠完善,各個(gè)框架也還不太成熟。由于之前使用框架的過(guò)程中被各種神秘bug搞的頭禿,還是用回了原生環(huán)境。

                最近研究了一下如何在原生框架中實(shí)現滑動(dòng)抽屜菜單效果,本來(lái)以為很麻煩,結果發(fā)現其實(shí)只需要幾十行代碼,而且可以類(lèi)比實(shí)現很多靈活的效果。感覺(jué)現在網(wǎng)上相關(guān)資料較少,因此在此分享一下。除了文中貼出的代碼塊,也可以點(diǎn)擊鏈接在小程序開(kāi)發(fā)工具中預覽效果、查看代碼片段。這里實(shí)現了三種常見(jiàn)效果,先看一下動(dòng)圖,下面將一一講解代碼實(shí)現。

                A 菜單在上層 

                A2 菜單在上層,下層遮罩 

                B 菜單在下層

                WXS 響應事件

                手勢控制菜單的原理很簡(jiǎn)單:小程序提供了一系列觸摸手勢觸發(fā)的事件,包括觸摸開(kāi)始、移動(dòng)、結束(touchstart, touchmove, touchend)等等。在這些事件上綁定自定義的事件響應函數,即可實(shí)現根據手勢打開(kāi)關(guān)閉菜單的操作。

                出于性能考慮,事件處理函數最好放在 WXS、而不是 JS 文件中。具體原理與小程序的運行環(huán)境有關(guān),感興趣的話(huà)可以去文末查看。WXS 是小程序的專(zhuān)用腳本語(yǔ)言(WXS 與 JS 的關(guān)系相當于 WXSS 與 CSS 的關(guān)系),語(yǔ)法和 JS 類(lèi)似,有部分區別,比如:

                • 與 JS 隔離,不能調用其他 JavaScript 文件中定義的函數,也不能調用小程序提供的API
                • 只能響應小程序內置組件的事件,不支持自定義組件的事件回調
                • 變量與函數默認為模塊私有,通過(guò) module.exports 對外暴露
                • 使用標簽在 WXML 中引入使用(必須使用相對路徑)

                wxs 文件和 wxml 文件中的基本寫(xiě)法如下:

                // index.wxs
                
                function touchStart(e, ins) {}
                function touchMove(e, ins) {}
                function touchEnd(e, ins) {}
                
                module.exports = {
                  touchstart: touchStart,
                  touchmove: touchMove,
                  touchend: touchEnd
                }
                <wxs module="drawer" src="./index.wxs"></wxs>
                
                <view bindtouchstart="{{drawer.touchstart}}"
                      bindtouchmove="{{drawer.touchmove}}" 
                      bindtouchend="{{drawer.touchend}}">
                </view>
                
                

                方案A

                頁(yè)面結構和樣式

                這是最常見(jiàn)的抽屜菜單樣式之一,滑動(dòng)主體內容不動(dòng),菜單在上層顯示。首先寫(xiě)出基本的 HTML 結構和 CSS 樣式(省略了一些美觀(guān)方面的樣式表):

                <wxs module="drawer" src="./index.wxs"></wxs>
                
                <view>
                  <view class="main" bindtouchstart="{{drawer.touchstart}}"
                    bindtouchmove="{{drawer.touchmove}}" bindtouchend="{{drawer.touchend}}">
                    <view>
                      右滑顯示側邊菜單 方案A
                    </view>
                  </view>
                
                  <view class="drawer" data-drawerwidth="150">
                    <view class="drawer-item">drawerA</view>
                    <view wx:for="{{[1, 2, 3]}}" class="drawer-item">
                      <text>menu item {{item}}</text>
                    </view>
                  </view>
                </view>
                
                

                WXML 中的幾個(gè)重點(diǎn):

                • 正確引入 wxs 模塊(必須用相對路徑)
                • 進(jìn)行滑動(dòng)手勢時(shí)菜單是隱藏的,所以實(shí)際上是在主界面上進(jìn)行滑動(dòng),所以三個(gè)滑動(dòng)事件回調需要綁定在主體內容的 view 上面
                • 進(jìn)行移動(dòng)的是 .drawer 元素,需要設置好 class 屬性方便獲取
                • 抽屜元素的 data-drawerwidth 屬性通過(guò) dataset 傳值給 wxs 腳本,規定了菜單的寬度,需要和樣式保持一致

                WXSS 沒(méi)啥好說(shuō)的,寫(xiě)在注釋里了:

                .main {
                  height: 100vh;
                  width: 100%;
                  position: absolute;
                }
                
                .drawer {
                  height: 100vh;
                  width: 150px;
                  position: absolute;
                  transition: transform 0.4s ease; /* 位移使用transform實(shí)現,加個(gè)過(guò)渡動(dòng)畫(huà)更順滑 */
                  left: -150px;  /* width、偏移與WXML中的數值保持一致,初始狀態(tài)隱藏菜單 */
                }

                WXS 事件回調函數

                wxs 函數有兩個(gè)入參

                • event 是小程序事件對象,并在此基礎上多了觸發(fā)事件的組件的實(shí)例 event.instance
                • ownerInstance 是觸發(fā)事件的組件的父組件(頁(yè)面)的實(shí)例

                wxs 中組件實(shí)例是封裝好的 ComponentDescriptor 對象,能夠操作組件的 dataset、設置 style、class 等,對于交互動(dòng)畫(huà)基本夠用了。更多用法可參考文檔。

                var wxsFunction = function(event, ownerInstance) {
                    var instance = ownerInstance.selectComponent('.classSelector') // 返回組件的實(shí)例
                    instance.setStyle({
                        "font-size": "14px" // 支持rpx
                    })
                    instance.getDataset()
                    instance.setClass(className)
                
                    return false // 不往上冒泡,相當于調用了同時(shí)調用了stopPropagation和preventDefault
                }
                
                

                WXS 腳本

                條件判斷為主,邏輯沒(méi)啥特別的,結合情景不難理解

                • 不要用 let, const 聲明變量,會(huì )報錯
                • 把設置 transform 屬性 X 位移的代碼簡(jiǎn)單封裝一下,看起來(lái)更美觀(guān)
                • judge point 類(lèi)似于吸附效果,就是菜單劃出來(lái)超過(guò)某一位置就自動(dòng)把剩余部分打開(kāi)
                var startmark = 0;
                var status = 0;  // 菜單開(kāi)閉狀態(tài)
                var JUDGEPOINT = 0.7;
                
                function touchStart(e, ins) {
                  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
                  startmark = pageX;
                }
                
                function touchMove(e, ins) {
                  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
                  var offset = pageX - startmark;
                  var drawerComp = ins.selectComponent('.drawer');
                  var drawerWidth = drawerComp.getDataset().drawerwidth;
                
                  if (offset > 0 && status == 0) {
                    setCompTransX(drawerComp, Math.min(drawerWidth, offset))
                  } else if (offset < 0 && status == 1) {
                    setCompTransX(drawerComp, Math.max(0, offset))
                  }
                }
                
                function touchEnd(e, ins) {
                  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
                  var offset = pageX - startmark;
                  var drawerComp = ins.selectComponent('.drawer');
                  var drawerWidth = drawerComp.getDataset().drawerwidth;
                
                  if (offset > 0 && status == 0) {
                    if (offset < drawerWidth * JUDGEPOINT) {
                      setCompTransX(drawerComp, 0);
                    } else {
                      setCompTransX(drawerComp, drawerWidth);
                      status = 1;
                    }
                  } else if (offset < 0) {
                    setCompTransX(drawerComp, 0);
                    status = 0;
                  }
                }
                
                function setCompTransX(comp, x) {
                  comp.setStyle({
                    transform: 'translateX(' + x + 'px)',
                  })
                }
                
                module.exports = {
                  touchstart: touchStart,
                  touchmove: touchMove,
                  touchend: touchEnd
                }

                遮罩層

                點(diǎn)擊文首或文末鏈接在小程序開(kāi)發(fā)工具中查看完整代碼。

                遮罩層只需要在菜單和主容器之間增加一個(gè) view 即可:

                <view class="main"></view>
                <view class="mask" data-maxopacity="0.6"></view>
                <view class="drawer" data-drawerwidth="150"></view>
                

                樣式中很重要的是這個(gè) pointer-events 屬性,設置為 none 之后點(diǎn)擊動(dòng)作會(huì )穿透這個(gè) view 達到下層。因為遮罩層不像抽屜是處在畫(huà)面以外的,它雖然透明度為0,但實(shí)際上一直覆蓋在 .main 上方,如果不加這個(gè)屬性,所有對 .main 的點(diǎn)擊操作都會(huì )點(diǎn)到 .mask 上面,那不管是滑動(dòng)還是其他按鈕都無(wú)效了。

                .mask {
                  height: 100vh;
                  width: 100%;
                  position: fixed;
                  transition: opacity 0.4s ease;
                  opacity: 0;
                  pointer-events: none;
                  background-color: #548CA8;
                }
                

                wxs 腳本也基本完全一致,只需要以相似的方法獲取到 .mask 的實(shí)例以及 dataset 中的透明度參數,并在設置位移屬性的同時(shí)設置遮罩層的透明度屬性即可。

                function setDrawer(x) {
                  setCompTransX(drawerComp, x);
                  maskComp.setStyle({
                    opacity: x / drawerWidth * maskOpacity,
                  })
                }
                

                方案B

                點(diǎn)擊文首或文末鏈接在小程序開(kāi)發(fā)工具中查看完整代碼。

                方案B 與方案A 的區別主要在于滑動(dòng)時(shí)是主界面向右移動(dòng)露出下層的菜單,其余各部分實(shí)現并無(wú)不同。這里只貼出主要差異的部分。

                因為移動(dòng)的是 .main 元素,因此把寬度配置數據放到了該元素的標簽中,這樣可以少獲取一個(gè)組件實(shí)例。

                <view class="drawer"></view>
                
                <view class="main" 
                      data-drawerwidth="150" 
                      bindtouchstart="{{drawer.touchstart}}"
                      bindtouchmove="{{drawer.touchmove}}" 
                      bindtouchend="{{drawer.touchend}}">
                </view>
                
                

                transition 動(dòng)畫(huà)屬性也放在 .main 中,.drawer 的偏移不需要了。

                .main {
                  height: 100vh;
                  width: 100%;
                  position: absolute;
                  transition: transform 0.4s ease;
                }
                
                .drawer {
                  height: 100vh;
                  width: 150px;
                  position: absolute;
                }
                
                

                wxs 腳本中除了獲取的組件不同外,連設置位移都不需要改。

                function touchMove(e, ins) {
                  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
                  var offset = pageX - startmark;
                  var mainComp = ins.selectComponent('.main');
                  var drawerWidth = mainComp.getDataset().drawerwidth;
                
                  if (offset > 0 && status == 0) {
                    setCompTransX(mainComp, Math.min(drawerWidth, offset))
                  } else if (offset < 0 && status == 1) {
                    setCompTransX(mainComp, Math.max(0, offset))
                  }
                }
                
                

                為什么要使用 WXS

                小程序在很多地方與 web 開(kāi)發(fā)很像,但底層存在一些區別。網(wǎng)頁(yè)中,渲染和腳本執行在同一個(gè)線(xiàn)程中執行(因此執行腳本可能會(huì )導致頁(yè)面整個(gè)卡死);小程序在不同的線(xiàn)程中分別運行邏輯層(JS腳本)和渲染層(WXML和WXSS),線(xiàn)程間經(jīng)由客戶(hù)端(Native)進(jìn)行通信。

                因此,如果使用 JS 腳本響應事件,每次觸發(fā) touchmove 都會(huì )產(chǎn)生兩次進(jìn)程間通信(下圖左所示),通信開(kāi)銷(xiāo)較大;同時(shí)“setData 渲染也會(huì )阻塞其它腳本執行”(文檔這么說(shuō)的,我也不知道為什么)。由于一次手勢會(huì )觸發(fā)巨量的 touchmove 事件,上述原因會(huì )造成動(dòng)畫(huà)的卡頓。

                而 WXS 函數運行在視圖層,不存在上述問(wèn)題(下圖右所示)。

                結語(yǔ) & 參考資料

                以上就是原生小程序的幾種抽屜菜單實(shí)現方法,希望對你有所幫助;對于文中存在的疏漏歡迎討論指正。

                點(diǎn)擊可以在小程序開(kāi)發(fā)工具中查看完整代碼(使用小程序開(kāi)發(fā)工具的代碼片段分享,對開(kāi)發(fā)工具版本有一定要求)。他這個(gè)分享代碼片段有點(diǎn)玄學(xué),如果直接打開(kāi)失敗,可以在登錄后嘗試在“項目-導入代碼片段”中直接輸入鏈接或鏈接最后一段ID。

                參考資料:

                到此這篇關(guān)于小程序原生實(shí)現左滑抽屜菜單的文章就介紹到這了,更多相關(guān)小程序 左滑抽屜菜單內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

                免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

                鲁鲁鲁爽爽爽在线视频观看| 99精品电影一区二区免费看| 天天爽夜夜爽夜夜爽精品视频| 中文字幕一区二区人妻性色| 中国少妇内射XXXXⅩHD| 欧美综合自拍亚洲综合图片区|