ヘリピンメニューのクローンを使用して


Note: this post was originally published on my personal blog


Web開発の基礎を強化するか、正確に良いフロントエンド開発者になる最良の方法は、HTML、CSS、およびJavaScriptをたくさん練習することです、そして、これらのテクノロジーを学ぶ最善の方法は、それらを使用している多くのサイドプロジェクトを作ることによってです.ほとんどの場合、バニラJavaScript、バニラCSS、および通常のHTMLマークアップを使用します.

この記事では、HeyのPINメニュー(メニューをセットする)をクローニングすることによって、私の最初の挑戦を始めています.COMのウェブサイトは、私は無料トライアルを行った後、私はそれを探索した後、私はそこに非常に多くの良いデザインの決定を見つけたが、私を最もポークは、彼らはそれに到達するためのショートカットとして電子メール用に実装されたピンメニューであったが、上記の例で見ることができるようにそれを作成する目的に関係なく、私はアイデアを気に入って、それを複製し、それを複製を作成することを決めた.

仮定


以下のように純粋なJavaScriptにロードされたデータの配列です.
const listOfItems = [
  "semicolon.academy",
  "twitter@SemicolonA",
  "FB.com/semicolonAcademy",
  "YT.com/SemicolonAcademy",
  "twitter@med7atdawoud",
  "IG/medhatdawoud",
  "medhatdawoud.net",
]

const stack = document.getElementById("stack")
for (let i = 0; i < listOfItems.length; i++) {
  let div = document.createElement("div")
  div.classList.add("single-block")
  div.innerHTML = `
      <div class="content">
        <img src="${path / to / heyLogo}" />
        <div><h3>${listOfItems[i]}</h3><p>description</p></div>
      </div>`
  stack.append(div)
}
行11から20まで私たちは通常のステートメントを持って、その中に、我々は毎回新しいdiv要素を作成し、それにクラスを与えるsingle-block それはヘイに似ていることができるようにデータのブロックのスタイルを適用するために使用されます.COMメニュー項目.
心に留めておきなさいstack それは行1で選択されます11 は、全体のデザインを保持するHTMLファイルのdivです.すべてのCSSは、完全な例で後で提供されます.
さて、次の結果を得た

これはスタート状態と考えられ、ここから次のような課題を理解する必要がある.

チャレンジ


1 -上記の項目の一覧をスタックのように見えます.
2 -クリックして展開の動作を行います.
3 -スタック以外の何かをクリックすると、折り返されます(折りたたみ).

実装


1 - divのリストからスタックに回してみましょう.
divのリストをスタックビューにするには、まずCSSで遊ぶ必要があります.まず最初に、別の層にあるdivのリストであるスタックを見てみて、それぞれ異なる位置を持っているように見えます
body {
  font-family: sans-serif;
  font-size: 16px;
}

#stack {
  position: absolute;
  height: 80vh;
  bottom: 30px;
  left: 40%;
  text-align: center;
  cursor: pointer;
}

.single-block {
  position: absolute;
  bottom: 0;
  background: #fff;
  box-shadow: 0 0 10px #eee;
  border-radius: 10px;
  transition: ease-in-out 0.2s;
}

.single-block .content {
  display: flex;
  padding: 11px 20px 9px;
}

.single-block .content img {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
}

.single-block .content > div {
  text-align: left;
  margin-left: 10px;
  width: 180px;
}

.single-block .content h3 {
  margin: 0;
  font-size: 16px;
  font-weight: normal;
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.single-block .content p {
  color: #aaa;
  margin: 0;
}
現在、transform CSSのプロパティでは、変換を使用して、アイテムを上下にスケールしたり、Y軸でそれらを翻訳することができます.
基本的に、我々はスケール1で最初のアイテムを始めます1 と翻訳0 フォロー
transform: scale(1) translateY(0);
上記のCSSを使用して、リスト内の各項目にそれを注入することができますが、スケールと変換の別の値で、私は数学を行い、結論はスケーリングダウン値は0.033333333 そのため、各項目の値は、その前の1よりも小さくする必要があります0.7 各項目のスケーリングと同じです.
また、我々のreferent(hey . com PINメニュー)ごとに、私たちは逆でその効果をする必要があるので、逆のインデックスを得る必要があります.
const reverseIndex = listOfItems.length - 1 - i
今、我々は各項目のためのバリアントとして使用することができます、項目を追加する前に、最後に追加されたコードは
const baseScaleChange = 0.033333333
const baseTranslateChange = 0.7
const reverseIndex = listOfItems.length - 1 - i
div.style.transform = `scale(${1 - reverseIndex * baseScaleChange}) 
     translateY(-${baseTranslateChange * reverseIndex}rem)`
Append行の前にコードを適用した後、次の結果を得る必要があります

2 -今すぐスタックをクリックして展開する次のタスクを開始しましょう
そのためには、基本的にTransformプロパティに小さな変更をする必要があります.この場合、各項目を軸のxとyの両方で特定の値で翻訳する必要があります.また、私たちは、使用する必要がありますrotate 関数は、Transformプロパティで提供され、項目のリストにその曲線を作成します.
私は再び数学を行いました、そして、回転変化はそうです1.1 Xの変更に関する翻訳は0.4 アイテムごとに、最後にY上の翻訳は4 最初のパラメータをとる関数の翻訳はXの値で、BTWはxの値であり、2番目の要素はYです.これを適用するには、現在の利用可能なリストのスタックdivとloopのClickイベントをlistenする必要があります.
stack.addEventListener("click", function(e) {
  const blocks = this.querySelectorAll(".single-block")
  blocks.forEach((block, i) => {
    const reverseindex = blocks.length - 1 - i
    block.style.transform = `rotate(${reverseindex * 1.1}deg) 
    translate(-${reverseindex * 0.2}rem, -${reverseindex * 4}rem)`
  })
})
私はコードがそれ自体を説明するので、私はこの部分に多くの時間を費やすつもりではないと思います、しかし、今、このコードを加えて、スタックdivをクリックした後に、すべてのアイテムはちょうどHeyの振舞いと同じくらい拡大しなければなりません.COMメニュー.
3 -今、我々は再びメニューを崩壊させる最後のタスクに達した.
我々は最初にアイテムの前に行った同じことを行うことによって簡単に行うことができますdocument , 次のようにします.
document.addEventListener("click", function(e) {
  const blocks = document.querySelectorAll(".single-block")
  blocks.forEach((block, i) => {
    const reverseIndex = listOfItems.length - 1 - i
    block.style.transform = `scale(${1 - reverseIndex * baseScaleChange}) 
      translateY(-${baseTranslateChange * reverseIndex}rem)`
  })
})
上記のコードを実際に追加した後、メニュー自体がもう動作しなくなり、その理由はEvent Bubbling これは、クリックイベントをスタックdivに適用した後、その親に適用されたイベントを親プロセスで処理し、それから既にクリックイベントの実装をしているドキュメント要素まで、親プロセスで処理します.非常に簡単な解決方法は、次の行をスタックdiv clickのイベント渡しの先頭に追加することです.
e.stopPropagation()
JSファイルの最終コードは次のようになります.
const heyLogoSrc =
  "https://production.haystack-assets.com/assets/avatars/defaults/hey-84b6169bf4060a76a94a072fe96b5fef7970b02d19507e2ab3952c042c21b154.svg"
const listOfItems = [
  "semicolon.academy",
  "twitter@SemicolonA",
  "FB.com/semicolonAcademy",
  "YT.com/SemicolonAcademy",
  "twitter@med7atdawoud",
  "IG/medhatdawoud",
  "medhatdawoud.net",
]

const baseScaleChange = 0.033333333
const baseTranslateChange = 0.7
document.addEventListener("DOMContentLoaded", function() {
  const stack = document.getElementById("stack")
  for (let i = 0; i < listOfItems.length; i++) {
    let div = document.createElement("div")
    div.classList.add("single-block")
    div.innerHTML = `
      <div class="content">
        <img src="${heyLogoSrc}" />
        <div><h3>${listOfItems[i]}</h3><p>description</p></div>
      </div>`
    const reverseIndex = listOfItems.length - 1 - i
    div.style.transform = `scale(${1 -
      reverseIndex * baseScaleChange}) translateY(-${baseTranslateChange *
      reverseIndex}rem)`
    stack.append(div)
  }

  stack.addEventListener("click", function(e) {
    e.stopPropagation()
    const blocks = this.querySelectorAll(".single-block")
    blocks.forEach((block, i) => {
      const reverseindex = blocks.length - 1 - i
      block.style.transform = `rotate(${reverseindex *
        1.1}deg) translate(-${reverseindex * 0.2}rem, -${reverseindex * 4}rem)`
    })
  })

  document.addEventListener("click", function(e) {
    const blocks = document.querySelectorAll(".single-block")
    blocks.forEach((block, i) => {
      const reverseIndex = listOfItems.length - 1 - i
      block.style.transform = `scale(${1 -
        reverseIndex * baseScaleChange}) translateY(-${baseTranslateChange *
        reverseIndex}rem)`
    })
  })
})
それはかなり多く、私たちが実装したものは、Heyで実装されているものに非常に近いです.comウェブサイト.

結果と結論


今、我々は挑戦を完了し、最終的な結果は次のとおりです

最後のコードはchallenges Github repo , そして、あなたがコードまたはどんな別の挑戦でもどんな提案をするならば、あなたは私に手を差し伸べることができます😉 Twitterでは、今日は何か役に立つことを学びました.
トットジーンズ👋

Side Note: If you are an arabic speaker or understand arabic, you can also watch me coding that in an arabic tutorials in the following video on my technical arabic channel on Youtube