亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

小程序原生實現(xiàn)左滑抽屜菜單

 更新時間:2021年07月30日 11:27:45   作者:Skuld_yi''s Blog  
在移動端,側(cè)滑菜單是一個很常用的組件,本文就詳細(xì)的介紹小程序原生實現(xiàn)左滑抽屜菜單,具有一定的參考價值,感興趣的可以了解一下

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

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

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

A 菜單在上層 

A2 菜單在上層,下層遮罩 

B 菜單在下層

WXS 響應(yīng)事件

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

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

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

wxs 文件和 wxml 文件中的基本寫法如下:

// 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

頁面結(jié)構(gòu)和樣式

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

<wxs module="drawer" src="./index.wxs"></wxs>

<view>
  <view class="main" bindtouchstart="{{drawer.touchstart}}"
    bindtouchmove="{{drawer.touchmove}}" bindtouchend="{{drawer.touchend}}">
    <view>
      右滑顯示側(cè)邊菜單 方案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 中的幾個重點:

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

WXSS 沒啥好說的,寫在注釋里了:

.main {
  height: 100vh;
  width: 100%;
  position: absolute;
}

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

WXS 事件回調(diào)函數(shù)

wxs 函數(shù)有兩個入?yún)?/p>

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

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

var wxsFunction = function(event, ownerInstance) {
    var instance = ownerInstance.selectComponent('.classSelector') // 返回組件的實例
    instance.setStyle({
        "font-size": "14px" // 支持rpx
    })
    instance.getDataset()
    instance.setClass(className)

    return false // 不往上冒泡,相當(dāng)于調(diào)用了同時調(diào)用了stopPropagation和preventDefault
}

WXS 腳本

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

  • 不要用 let, const 聲明變量,會報錯
  • 把設(shè)置 transform 屬性 X 位移的代碼簡單封裝一下,看起來更美觀
  • judge point 類似于吸附效果,就是菜單劃出來超過某一位置就自動把剩余部分打開
var startmark = 0;
var status = 0;  // 菜單開閉狀態(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
}

遮罩層

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

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

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

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

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

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

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

方案B

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

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

因為移動的是 .main 元素,因此把寬度配置數(shù)據(jù)放到了該元素的標(biāo)簽中,這樣可以少獲取一個組件實例。

<view class="drawer"></view>

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

transition 動畫屬性也放在 .main 中,.drawer 的偏移不需要了。

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

.drawer {
  height: 100vh;
  width: 150px;
  position: absolute;
}

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

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 開發(fā)很像,但底層存在一些區(qū)別。網(wǎng)頁中,渲染和腳本執(zhí)行在同一個線程中執(zhí)行(因此執(zhí)行腳本可能會導(dǎo)致頁面整個卡死);小程序在不同的線程中分別運行邏輯層(JS腳本)和渲染層(WXML和WXSS),線程間經(jīng)由客戶端(Native)進(jìn)行通信。

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

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

結(jié)語 & 參考資料

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

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

參考資料:

小程序框架/視圖層/事件系統(tǒng)/WXS 響應(yīng)事件

官方 demo

小程序宿主環(huán)境

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

相關(guān)文章

  • JSONP解決JS跨域問題的實現(xiàn)

    JSONP解決JS跨域問題的實現(xiàn)

    這篇文章主要介紹了JSONP解決JS跨域問題的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 淺談js script標(biāo)簽中的預(yù)解析

    淺談js script標(biāo)簽中的預(yù)解析

    本文主要對js中script標(biāo)簽中的預(yù)解析進(jìn)行詳細(xì)介紹。具有一定的參考價值,下面跟著小編一起來看下吧
    2016-12-12
  • 一行JavaScript代碼如何實現(xiàn)瀑布流布局

    一行JavaScript代碼如何實現(xiàn)瀑布流布局

    這篇文章主要給大家介紹了如何通過一行JavaScript代碼實現(xiàn)瀑布流布局的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • JavaScript表單即時驗證 驗證不成功不能提交

    JavaScript表單即時驗證 驗證不成功不能提交

    這篇文章主要為大家詳細(xì)介紹了JavaScript表單即時驗證,驗證不成功不能提交,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • JavaScript對Json的增刪改屬性詳解

    JavaScript對Json的增刪改屬性詳解

    下面小編就為大家?guī)硪黄狫avaScript對Json的增刪改屬性詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • js注入 黑客之路必備!

    js注入 黑客之路必備!

    這篇文章主要為大家詳細(xì)介紹了js注入,黑客之路必備!本文告訴大家什么是js注入,如何進(jìn)行js注入攻防,感興趣的小伙伴們可以參考一下
    2016-09-09
  • Javascript 構(gòu)造函數(shù) 實例分析

    Javascript 構(gòu)造函數(shù) 實例分析

    一般構(gòu)造函數(shù)沒有返回值,他們通過關(guān)鍵字this初始化對象,沒有返回值。當(dāng)然一個構(gòu)造器允許返回一個對 象,如果這樣的話 返回的對象將變成new 表達(dá)式的值,在這種情況下值為this的對象將拋棄
    2008-11-11
  • 微信小程序之多列表的顯示和隱藏功能【附源碼】

    微信小程序之多列表的顯示和隱藏功能【附源碼】

    今天在項目碰到一個問題,之前在項目首頁實現(xiàn)單列表的顯示和隱藏,通過wx:if判斷就可實現(xiàn),現(xiàn)在要實現(xiàn)多列表的單項顯示和隱藏功能應(yīng)該如何實現(xiàn)呢?下面小編給大家?guī)砹宋⑿判〕绦蛑嗔斜淼娘@示和隱藏功能,感興趣的朋友一起看看吧
    2018-08-08
  • JS實現(xiàn)距離上次刷新已過多少秒示例

    JS實現(xiàn)距離上次刷新已過多少秒示例

    這篇文章主要介紹了JS如何實現(xiàn)距離上次刷新已過多少秒,需要的朋友可以參考下
    2014-05-05
  • 實例講解避免javascript沖突的方法

    實例講解避免javascript沖突的方法

    這篇文章主要以實例的方式講解了避免javascript沖突的方法,具有一定的參考價值,感興趣的朋友可以參考一下
    2016-01-01

最新評論