ミニプログラムは左スライドのドロワーメニューをネイティブに実装します

ミニプログラムは左スライドのドロワーメニューをネイティブに実装します

モバイル デバイスでは、サイドスライド メニューは非常によく使用されるコンポーネントです (通常はドロワーと呼ばれます)。最近の携帯電話の画面は大きすぎるため、画面の隅にあるメニューボタンをクリックするのは、画面の中央をスワイプするほど便利ではないのは明らかです。

他のプラットフォームと比較すると、ミニプログラムのコンポーネント ライブラリ サポートは明らかに十分ではなく、さまざまなフレームワークはまだ成熟していません。以前フレームワークを使用していた際に、さまざまな不可解なバグに困惑したため、ネイティブ環境に戻ることにしました。

最近、ネイティブフレームワークでスライドドロワーメニュー効果を実装する方法を勉強しました。とても面倒だと思っていましたが、数十行のコードで済み、類推によって多くの柔軟な効果を実現できることが分かりました。インターネット上には関連情報があまりないと感じたので、ここで共有したいと思います。記事に掲載されているコードブロックに加え、リンクをクリックして効果をプレビューしたり、ミニプログラム開発ツールでコードスニペットを表示したりすることもできます。ここでは、3 つの一般的なエフェクトが実装されています。まずはアニメーション画像を見てから、コードの実装を 1 つずつ説明していきます。

上部のメニュー

A2メニューは上層にあり、下層はマスクされています

Bメニューは下部にあります

WXS レスポンス イベント

ジェスチャ コントロール メニューの原理は非常にシンプルです。アプレットはtouchstart, touchmove, touchend touchend) など、タッチ ジェスチャによってトリガーされる一連のイベントを提供します。これらのイベントにカスタム イベント応答関数をバインドすることで、ジェスチャに応じてメニューを開いたり閉じたりすることができます。

パフォーマンス上の理由から、イベント処理関数は JS ファイルではなく WXS ファイルに配置するのが最適です。具体的な原理はアプレットの動作環境に関係しますので、興味のある方は記事の最後でご確認ください。 WXS はアプレット専用のスクリプト言語です (WXS と JS の関係は WXSS と CSS の関係に相当します)。構文は JS に似ていますが、次のような違いもあります。

  • JSから分離されているため、他のJavaScriptファイルで定義された関数を呼び出すことも、ミニプログラムによって提供されるAPIを呼び出すこともできません。
  • ミニプログラムの組み込みコンポーネントのイベントにのみ応答でき、カスタム コンポーネントのイベント コールバックはサポートされません。
  • 変数と関数はデフォルトではモジュール内でプライベートであり、 module.exportsを通じて外部に公開されます。
  • WXML にインポートするにはタグを使用します (相対パスを使用する必要があります)

wxs ファイルと wxml ファイルでの基本的な記述方法は次のとおりです。

// インデックス.wxs

関数 touchStart(e, ins) {}
関数 touchMove(e, ins) {}
関数 touchEnd(e, ins) {}

モジュール.エクスポート = {
  タッチスタート: タッチスタート、
  タッチムーブ: タッチムーブ、
  タッチエンド: タッチエンド
}
<wxs モジュール="引き出し" src="./index.wxs"></wxs>

<view bindtouchstart="{{drawer.touchstart}}"
      bindtouchmove="{{drawer.touchmove}}" 
      bindtouchend="{{drawer.touchend}}">
</ビュー>

プランA

ページ構造とスタイル

最も一般的なドロワーメニュースタイルのひとつです。スライドしてもメインコンテンツは移動せず、メニューは上層に表示されます。まず、基本的な HTML 構造と CSS スタイルを記述します (一部の美観スタイルシートは省略されています)。

<wxs モジュール="引き出し" src="./index.wxs"></wxs>

<表示>
  <view class="main" bindtouchstart="{{drawer.touchstart}}"
    bindtouchmove="{{drawer.touchmove}}" bindtouchend="{{drawer.touchend}}">
    <表示>
      右にスライドするとサイドメニューソリューションAが表示されます
    </ビュー>
  </ビュー>

  <view class="drawer" data-drawerwidth="150">
    <view class="drawer-item">引き出しA</view>
    <view wx:for="{{[1, 2, 3]}}" class="drawer-item">
      <text>メニュー項目 {{item}}</text>
    </ビュー>
  </ビュー>
</ビュー>

WXML の重要なポイント:

  • wxs モジュールを正しくインポートします (相対パスを使用する必要があります)
  • スライド ジェスチャを実行するとメニューは非表示になり、スライドは実際にはメイン インターフェイスで実行されるため、3 つのスライド イベント コールバックをメイン コンテンツのビューにバインドする必要があります。
  • .drawer要素が移動され、簡単にアクセスできるようにclass属性を設定する必要があります
  • ドロワー要素の data-drawerwidth 属性は、データセットを通じて wxs スクリプトに渡されます。この属性はメニューの幅を指定し、スタイルと一致している必要があります。

WXSS については特に言うことはありませんが、コメントに次のように書かれています:

。主要 {
  高さ:100vh;
  幅: 100%;
  位置: 絶対;
}

.引き出し{
  高さ:100vh;
  幅: 150ピクセル;
  位置: 絶対;
  transition: transform 0.4s easy; /* 変位を実現するために transform を使用し、よりスムーズにするために遷移アニメーションを追加します */
  left: -150px; /* 幅とオフセットはWXMLの値と一致しており、メニューは初期状態では非表示になっています*/
}

WXS イベントコールバック関数

wxs関数には2つの入力パラメータがある

  • eventはアプレットのイベントオブジェクトであり、これに基づいてイベントをトリガーするコンポーネントのインスタンスも存在しますevent.instance
  • ownerInstance 、イベントをトリガーしたコンポーネントの親コンポーネント(ページ)のインスタンスです。

wxs のコンポーネント インスタンスはカプセル化されたComponentDescriptorオブジェクトであり、コンポーネントのデータセットを操作したり、スタイルやクラスなどを設定したりすることができ、基本的にインタラクティブなアニメーションには十分です。詳しい使用方法については、ドキュメントを参照してください。

var wxsFunction = 関数(イベント、所有者インスタンス) {
    var instance = ownerInstance.selectComponent('.classSelector') // コンポーネントのインスタンスを返しますinstance.setStyle({
        "font-size": "14px" // rpx をサポート
    })
    インスタンス.getDataset()
    インスタンス.setClass(クラス名)

    false を返す // バブルアップしない。これは stopPropagation と preventDefault を同時に呼び出すのと同じである。
}

WXS スクリプト

条件判断が中心で、ロジックは特別なものではなく、状況と組み合わせると理解するのは難しくありません

  • 変数を宣言する際に let または const を使用しないでください。エラーが発生します。
  • 変換属性 X 変位を設定するコードは、見た目を美しくするために単純にカプセル化されています。
  • ジャッジポイントは吸着効果に似ており、メニューを一定の位置を超えて描画すると、残りの部分が自動的に開きます。
var スタートマーク = 0;
var status = 0; // メニューが開いているか閉じているかのステータス var JUDGEPOINT = 0.7;

関数touchStart(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  スタートマーク = pageX;
}

関数touchMove(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  var offset = pageX - 開始マーク;
  var drawerComp = ins.selectComponent('.drawer');
  var drawerWidth = drawerComp.getDataset().drawerwidth;

  if (オフセット > 0 && ステータス == 0) {
    setCompTransX(drawerComp, Math.min(drawerWidth, offset))
  } そうでない場合 (オフセット < 0 && ステータス == 1) {
    setCompTransX(drawerComp、Math.max(0、オフセット))
  }
}

関数touchEnd(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  var offset = pageX - 開始マーク;
  var drawerComp = ins.selectComponent('.drawer');
  var drawerWidth = drawerComp.getDataset().drawerwidth;

  if (オフセット > 0 && ステータス == 0) {
    if (オフセット < 引き出し幅 * JUDGEPOINT) {
      setCompTransX(引き出しComp, 0);
    } それ以外 {
      setCompTransX(引き出しComp、引き出し幅);
      ステータス = 1;
    }
  } そうでない場合 (オフセット < 0) {
    setCompTransX(引き出しComp, 0);
    ステータス = 0;
  }
}

関数setCompTransX(comp, x) {
  comp.setStyle({
    変換: 'translateX(' + x + 'px)',
  })
}

モジュール.エクスポート = {
  タッチスタート: タッチスタート、
  タッチムーブ: タッチムーブ、
  タッチエンド: タッチエンド
}

マスクレイヤー

記事の最初または最後に記載されているリンクをクリックすると、ミニプログラム開発ツールで完全なコードが表示されます。

マスク レイヤーでは、メニューとメイン コンテナーの間にビューを追加するだけで済みます。

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

スタイルでは、pointer-events プロパティが非常に重要です。これを none に設定すると、クリック アクションによってビューが下のレイヤーにまで浸透してしまいます。マスクレイヤーはドロワーと違って画面外にあるため、透明度は 0 ですが、実際には .main を常に覆っています。この属性を追加しないと、.main 上のクリックはすべて .mask 上になり、スライドなどのボタンが無効になります。

。マスク {
  高さ:100vh;
  幅: 100%;
  位置: 固定;
  遷移: 不透明度 0.4 秒、緩和;
  不透明度: 0;
  ポインタイベント: なし;
  背景色: #548CA8;
}

wxs スクリプトも基本的には同じです。同様の方法でデータセット内の .mask インスタンスと透明度パラメータを取得し、変位属性を設定する際にマスク レイヤーの透明度属性を設定するだけです。

関数setDrawer(x) {
  setCompTransX(引き出しComp、x);
  マスクComp.setStyle({
    不透明度: x / 引き出し幅 * マスク不透明度、
  })
}

プランB

記事の最初または最後に記載されているリンクをクリックすると、ミニプログラム開発ツールで完全なコードが表示されます。

ソリューション B とソリューション A の主な違いは、スライドするとメイン インターフェイスが右に移動して下部のメニューが表示される点であり、他の部分の実装には違いはありません。ここでは主な相違点のみを掲載します。

.main 要素が移動されるため、幅構成データが要素のタグ内に配置され、取得できるコンポーネント インスタンスが 1 つ少なくなります。

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

<view class="main" 
      データドロワー幅="150" 
      bindtouchstart="{{drawer.touchstart}}"
      bindtouchmove="{{drawer.touchmove}}" 
      bindtouchend="{{drawer.touchend}}">
</ビュー>

遷移アニメーションのプロパティも .main に配置され、.drawer のオフセットは不要になりました。

。主要 {
  高さ:100vh;
  幅: 100%;
  位置: 絶対;
  遷移: 変換 0.4 秒のイーズ;
}

.引き出し{
  高さ:100vh;
  幅: 150ピクセル;
  位置: 絶対;
}

wxs スクリプトでは、取得されるさまざまなコンポーネントを除いて、変位設定も変更する必要はありません。

関数touchMove(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  var offset = pageX - 開始マーク;
  var mainComp = ins.selectComponent('.main');
  var drawerWidth = mainComp.getDataset().drawerwidth;

  if (オフセット > 0 && ステータス == 0) {
    setCompTransX(mainComp、Math.min(drawerWidth、オフセット))
  } そうでない場合 (オフセット < 0 && ステータス == 1) {
    setCompTransX(mainComp、Math.max(0、オフセット))
  }
}

WXSを使用する理由

ミニプログラムは多くの点で Web 開発と非常に似ていますが、内部的にはいくつかの違いがあります。 Web ページでは、レンダリングとスクリプトの実行は同じスレッドで実行されます (そのため、スクリプトを実行するとページ全体がフリーズする可能性があります)。ミニプログラムは、ロジック レイヤー (JS スクリプト) とレンダリング レイヤー (WXML と WXSS) をそれぞれ異なるスレッドで実行し、スレッドはクライアント (ネイティブ) を介して通信します。

そのため、JS スクリプトを使用してイベントに応答する場合、touchmove がトリガーされるたびに 2 つのプロセス間通信が生成され (下の図の左のように)、通信のオーバーヘッドが大きくなります。同時に、「setData のレンダリングによって他のスクリプトの実行もブロックされます」(ドキュメントにはそう書かれていますが、理由はわかりません)。ジェスチャによって膨大な数の touchmove イベントがトリガーされるため、上記の理由によりアニメーションが妨害されることになります。

WXS 機能はビュー レイヤーで実行されるため、上記の問題は発生しません (下の右図を参照)。

結論と参考文献

上記は、ネイティブ アプレットのドロワー メニューを実装するいくつかの方法です。お役に立てれば幸いです。記事の抜け漏れについて議論したり修正したりしていただければ幸いです。

リンクをクリックすると、ミニプログラム開発ツールで完全なコードが表示されます (ミニプログラム開発ツールを使用してコード スニペットを共有するには、開発ツールのバージョンに特定の要件があります)。彼が共有したコード スニペットは少し謎めいています。直接開けない場合は、ログイン後に「プロジェクト - インポート コード スニペット」にリンクまたはリンクの最後の ID を直接入力してみてください。

参考文献:

ミニプログラムフレームワーク/ビューレイヤー/イベントシステム/WXSレスポンスイベント

公式デモ

ミニプログラムホスト環境

ミニプログラムでの左スライドドロワーメニューのネイティブ実装に関するこの記事はこれで終わりです。ミニプログラムでの左スライドドロワーメニューに関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • WeChatアプレットの左スライドメニュー表示機能の実装

<<:  MySQL エラー番号 1129 の解決方法

>>:  ESXI の仮想マシンにワークステーションをインストールするときに発生するネットワーク障害の解決策

推薦する

jsのディープコピーを理解しましょう

目次js ディープコピーデータ保存方法浅いコピー/深いコピーとは何か一般的なディープコピーの実装1....

NodeJSとブラウザにおけるこのキーワードの違い

序文JavaScript を学習した人なら誰でも、さまざまな環境で this がどこを指すかという問...

シンプルなフロントエンドのページング効果を実現する js

比較的シンプルな業務のプロジェクトもありますが、フロントエンドのページングを多用します。プラグインの...

wgetはウェブサイト全体(サブディレクトリ全体)または特定のディレクトリをダウンロードします

wgetコマンドを使用して、親ディレクトリの下のサブディレクトリ全体をダウンロードします。親ディレク...

実務経験7年のフロントエンドスーパーバイザーによる経験共有

今日はベテランの貴重な経験を共有します。著者は技術管理の経験が7年あり、多い時は80人以上を率いてい...

Docker Swarm クラスタ管理の使用と原理の分析

Swarm クラスター管理導入Docker Swarm は Docker 用のクラスター管理ツールで...

docker に openjdk をインストールして jar パッケージを実行する方法

画像をダウンロード docker プル openjdkデータボリュームの作成java_appデータボ...

MySQL における ${param} と #{param} の違い

${param}によって渡されるパラメータは、テーブル名やフィールド名を渡すなど、SQL文の一部と...

CentOS7でXShellとネットワーク設定を接続する方法

1. Linuxネットワーク構成ネットワークを構成する前に、まずローカル IPv4 アドレスやデフォ...

MySQL 作成ルーチン権限に関する注意事項

1. ユーザーにルーチン作成権限がある場合は、プロシージャ | 関数を作成できます。 2. ユーザー...

ページ下部のフッターを修正する方法(複数の方法)

フロントエンド Web エンジニアとして、ページ効果を作成するときに次の現象に遭遇したことがあるはず...

カルーセル例の JS 実装

この記事では、カルーセルチャートの小さなケースを実装するためのJSの具体的なコードを参考までに共有し...

CSS フロート(float, clear)の人気の解説と体験談

私はかなり昔に CSS に触れましたが、フローティングについてはいつも混乱していました。私の理解が浅...

MySQL よく使われる関数の詳細な概要

目次MySQL 共通関数1. 数値関数文字列関数3. 時間機能4. システム機能5. 集計関数MyS...

Macでのファイル権限の表示と設定の詳細な説明

序文Mac システムのターミナルでファイルの権限を変更するには、Linux の chmod コマンド...