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

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

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

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

最近、ネイティブフレームワークでスライドドロワーメニュー効果を実装する方法を勉強しました。とても面倒だと思っていましたが、数十行のコードで済み、類推によって多くの柔軟な効果を実現できることが分かりました。インターネット上には関連情報があまりないと感じたので、ここで共有したいと思います。記事に掲載されているコードブロックに加え、リンクをクリックして効果をプレビューしたり、ミニプログラム開発ツールでコードスニペットを表示したりすることもできます。ここでは、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 の仮想マシンにワークステーションをインストールするときに発生するネットワーク障害の解決策

推薦する

Java は Apache.POI を使用して HSSFWorkbook を Excel にエクスポートします

Apache.POI の HSSFWorkbook を使用して Excel にエクスポートします。具...

MySQL で高性能なインデックスを作成するための完全な手順

目次1. インデックスの基本1. インデックスの種類1.1 Bツリーインデックス1.2 ハッシュイン...

MySQLで時間を判定条件として使用する方法

背景: 開発プロセスでは、現在の月、現在の日、現在の時間、今後数日など、時間を判断条件としてデータを...

Kali Linux インストール VMware ツールのインストール プロセスと VM インストール vmtools ボタン グレー

Xiaobai は vmtools のインストールを記録します。 1. 意義と機能: VMWARE ...

あまり多くのコードを書かずに、ハイパーリンクを使ってシンプルで美しいカスタムチェックボックスを実装できます。

今日ふと、HTML でチェックボックスのスタイルを変更できる範囲が限られていることと、チェックボック...

Vue命令の実装原理の分析

目次1. 基本的な使い方2. 指示の動作原理2.1. 初期化2.2 テンプレートのコンパイル2.3....

JS配列メソッドの詳細な説明

目次1. 元の配列が変更されます1. プッシュ(): 2.ポップ(): 3. シフト(): 4.un...

Linux lsコマンドの使用

1. はじめにls コマンドはディレクトリの内容を表示するために使用され、Linux で頻繁に使用さ...

geoip を使用して nginx で地域を制限する方法

このブログは仕事のメモです環境: nginx バージョン: nginx/1.14.0 Centos ...

h5入力ボックスプロンプト+通常のテキストボックスプロンプトを実装する方法

XML/HTML コードコンテンツをクリップボードにコピー<入力 id = "ユーザ...

Spring Boot のパッケージ化と Docker リポジトリへのアップロードの詳細な手順

重要な注意: この記事を読む前に、Docker コンテナに関する知識と、一般的な Docker 操作...

今日、私は非常に奇妙なクリックの問題に遭遇し、自分で解決しました

...こんな感じで、今日はポップアップウィンドウを作ろうと思ったのですが、バックエンド PHP によ...

MySQLの共通関数の概要

序文: MySQL データベースは、よく使用される集計関数、日付および文字列処理関数など、幅広い関数...

Zenコーディングリソース更新機能強化

公式サイト: http://code.google.com/p/zen-coding/ Zen コー...