Vue でサイドスライド メニュー コンポーネントを実装する方法

亚连
リリース: 2018-06-20 10:45:05
オリジナル
3841 人が閲覧しました

この記事では、シンプルな DrawerLayout (Android の DrawerLayout に似た) レイアウト コンポーネントの実装を紹介します。この記事を通じて、Vue.js に基づくサイドスライド メニュー コンポーネントの実装コードを一緒に学びましょう

この記事では、シンプルな DrawerLayout (似たような) レイアウト コンポーネントを紹介します。 Android の DrawerLayout) レイアウト コンポーネントの実装は Vue.js に基づいています。導入した内容はvue-drawer-layoutコンポーネント化されています。

前書き

ご興味がございましたら、まず携帯電話でこの QR コードをスキャンするか、私

をクリックしてから、ページの左上隅にあるアバターをクリックしてドロワーを開くか、右または左にドラッグして確認してください。携帯電話で QQ を開いたときの以下の GIF の効果は非常によく似ています:)

Google は正式にこのレイアウトを DrawerLayout (ドロワー ナビゲーション バー) と呼んでいます。では、どうやってそれを達成するのでしょうか? メインムービーを始めましょう!

HTML 構造

ページ構造は非常にシンプルで、ドロワーとメイン コンテナーがあり、コンテンツはスロットを使用して外部からカスタマイズできます。

<p class="drawer-layout">
  <!--抽屉-->
  <p class="drawer-wrap">
    <slot name="drawer"></slot>
  </p>
  <!--主容器-->
  <p class="content-wrap">
    <!--遮罩-->
    <p class="drawer-mask"></p>
    <slot name="content"></slot>
  </p>
</p>
ログイン後にコピー

最初は引き出しが左画面の外に隠れているので、左:-100%にして外に完全に隠します

Touchを使用

まず、ブラウザがtouchEvent

let isTouch = &#39;ontouchstart&#39; in window;
  let mouseEvents = isTouch ?
    {
      down: &#39;touchstart&#39;,
      move: &#39;touchmove&#39;,
      up: &#39;touchend&#39;,
      over: &#39;touchstart&#39;,
      out: &#39;touchend&#39;
    } :
    {
      down: &#39;mousedown&#39;,
      move: &#39;mousemove&#39;,
      up: &#39;mouseup&#39;,
      over: &#39;mouseover&#39;,
      out: &#39;mouseout&#39;
    };
ログイン後にコピー

をサポートしているかどうかを確認しますタッチダウン イベントをバインドします

document.addEventListener(mouseEvents.down, initDrag, false);
ログイン後にコピー

まず、押された指の x 座標は startX としてマークされ、スライド中の指の x 座標は nowX としてマークされ、ドロワーの x 座標オフセットを定義します。 startPos

let startX, nowX, startPos;
ログイン後にコピー

としてマークされています。 touchstart がトリガーされると、開始位置を記録し、touchmove をバインドします。 touchEvent の場合は、e.clientX を通じて現在の x 座標を取得します。 [0].clientX

const initDrag = function (e) {
  startX = e.clientX || e.changedTouches[0].clientX; //记录手指按下的位置
  startPos = this.pos; //记录drawer的上次位置
  document.addEventListener(mouseEvents.move, drag, false);
  document.addEventListener(mouseEvents.up, removeDrag, false);
}.bind(this);
const drag = function (e) {
  nowX = e.clientX || e.changedTouches[0].clientX; //滑动中手指的位置x坐标
  let pos = startPos + nowX - startX; 
  pos = Math.min(width, pos); //不能超过滑动最大值
  pos = Math.max(0, pos); //不能小于0
  this.pos = pos; //设置滚动距离为拖动的距离
}.bind(this);
ログイン後にコピー

すると、指のスライド距離はnowX - startX、現在のドロワーの位置はstartPos + nowX - startXになります。 このように、ドロワーは指に追従して右に移動します。設定した最大抗力値を超えないこと。

垂直スライドと水平スライドを区別してください

次に、指でメインコンテンツを垂直にスクロールするときに、指を右にスライドすると引き出しもドラッグされます。やるべきことは一つ:縦方向のスライドと横方向のスライドを区別する

もちろん方法はたくさんありますが、ここでは三角関数を使って決定する方法をご紹介します

上の図の各矢印が指のスライド方向であると仮定します。 、緑の矢印はドラッグできることを意味します。ドロワーでは、赤い矢印はドラッグできないことを意味します (赤い矢印には x 座標のオフセットもあることに注意してください)。つまり、ドロワーをドラッグできない場合は、垂直スクロールなどのデフォルトのイベントをトリガーする必要があります。

指を押してタッチスタートをトリガーすると、最初の位置 P 0 が記録されます。指をスライドすると、最初のタッチ移動がトリガーされ、位置 P 1 が記録されます。P 0 から P 1 までのベクトルを S (これは許してください) Soul Painter)

この時、∠θが一定の値、例えば30度より大きい場合、ドロワーのドラッグではなく縦スクロール操作である可能性があることが容易に分かります。したがって、判定条件はy/x>tan30°で求めることができます

:

if (isVerticle === undefined) isVerticle = Math.abs(nowY - startY) / Math.abs(nowX - startX) > (Math.sqrt(3) / 3);
ログイン後にコピー

isVerticleがtrueの場合、引き出しのドラッグは行われません

引き出しを動かしてみましょう

css3のtransition属性を利用しますドロワーに遷移アニメーションを持たせるには、ここに移動クラスを記述します

.moving
  transition transform .3s ease
ログイン後にコピー

ドラッグ時に遷移アニメーションを追加する必要はありません (指をたどる必要があります)。指を離すときに必要です。

<p class="drawer-wrap" :class="{&#39;moving&#39;:moving,&#39;will-change&#39;:willChange}"
   :style="{width:`${width}px`,left:`-${width)}px`,transform:`translate3d(${pos}px,0,0)`}">
  <slot name="drawer"></slot>
</p>
ログイン後にコピー

そのため、touchend イベント メソッドをバインドするときは、次の手順を実行する必要があります

const removeDrag = function (e) {
  if (isVerticle !== undefined) {
    if (!isVerticle) {//当判定为抽屉拖动才进入
      let pos = this.pos;
      this.visible = pos > width * 3 / 5 //当前位置如果大于总宽度的3/5就判定为全部展开抽屉,否则将抽屉弹回隐藏
      if (this.pos > 0 && this.pos < width) this.moving = true;//如果位置已经处于最小值或最大值处,不需要有动画效果了
    }
    this.pos = this.visible ? width : 0;
  }
  if (!this.moving) {
    this.willChange = false; //留个悬念
  }
  isVerticle = undefined;
  //取消touchmove和touchend事件绑定
  document.removeEventListener(mouseEvents.move, drag, false);
  document.removeEventListener(mouseEvents.up, removeDrag, false);
}.bind(this);
ログイン後にコピー

上記のコードには this.willChange = false が表示されますが、これは何を行うのでしょうか?以下では、css の will-change メソッドを紹介します

。will-change
will-changetransform

CSS 属性 will-change は、要素にどのような変更が加えられるかをブラウザーに伝える方法を Web 開発者に提供します。プロセッサは、要素の属性が実際に変更される前に、対応する最適化の準備を事前に行うことができます。 この種の最適化により、複雑な計算作業の一部を事前に準備できるため、ページの応答がより速く、より敏感になります。

実際、ブラウザ ドロワーが touchstart で移動する可能性があることを事前にブラウザ ドロワーに通知できます

const initDrag = function (e) {
  //...
  this.willChange = true;
}.bind(this);
ログイン後にコピー

もちろん、transitionend イベントの後にトランジションと will-change を削除することを忘れずに、ブラウザをしばらく休ませます。しばらくお待ちください~

他に最適化できるものは何ですか?

上記の主な機能は基本的に実装されていますが、他に最適化できる点はありますか?

え?パッシブ

って一体何?

网站使用被动事件侦听器以提升滚动性能,在您的触摸和滚轮事件侦听器上设置 passive 选项可提升滚动性能具体看这里

原来这是现代浏览器的一个新特性,我们需要以新的方式来绑定我们的touch事件,当然首先先检测一下是否支持 passive

const supportsPassive = (() => {
  let supportsPassive = false;
  try {
    const opts = Object.defineProperty({}, &#39;passive&#39;, {
      get: function () {
        supportsPassive = true;
      }
    });
    window.addEventListener("test", null, opts);
  } catch (e) {
  }
  return supportsPassive;
})();
ログイン後にコピー

于是我们的绑定事件代码变成这样

document.addEventListener(mouseEvents.move, drag, supportsPassive ? {passive: true} : false);
ログイン後にコピー

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

Bootstrap栅格系统(详细教程)

在jQuery中如何实现点击DIV触发点击CheckBox

在React Native中使用prop-types如何实现属性确认

在jQuery中如何实现弹窗下底部页面禁止滑动效果

$refs访问Vue中的DOM(详细教程)

以上がVue でサイドスライド メニュー コンポーネントを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート