これがアプリケーション全体の難しさだと思います。
visual.net を見ると、その実装は CSS3 のtransform関数のtranslateを使用しています。これは良いアイデアのように思えますが、translateに相当する値を取得するためにJSを使用するのは少し面倒であることがわかりました。
次に、別の回答の実装を調べました。彼の方法は、CSS で left を使用することです。 left の値は、position:relative が設定された親を基準とした相対値です。
上記の方法がよくわかりません。しかし、私は別の方法を考えました: left はそれ自体に対して相対的です 。つまり、それ自体を親ではなくposition:relativeに設定します。
.bar { position: relative; left: 0; /* must set, or not transition when value in falsy */ /*transition: left 1s;*/}
left を 0 に設定した理由は、CSS3 トランジションを使用してグラデーション効果を実現したいためです。
その後、交換するたびに、現在の左側に棒グラフの幅を加算/減算するだけで済みます。はい、これはこの方法の「欠点」の 1 つです。JS で縦棒グラフの幅を記述する必要があります。
swap () { // ... const getLeft = item => parseInt(item.style.left.slice(0, -2)) || 0 // rm 'px' item1.style.left = `${this.barWidth + getLeft(item1)}px` item2.style.left = `${-this.barWidth + getLeft(item2)}px`}
交換中、まず対応する DOM 要素 (上記のコードの item と item2) を見つける必要があります。
どうやって見つけますか? (大量の数値をソートしているとします) 最初に 2 つの方法を考えました。
最初の方法は、次のように、番号に基づいて一致する番号を持つ DOM 要素を見つけることです:
swap (value1, value2) { const item1 = this.el.querySelector(`[data-value='${value1}']`)}
しかし、この方法は機能しません。なぜ?
同じ数値が複数ある場合、見つかった DOM 要素が交換したいものであるとは限りません。 querySelector は常に最初に一致する要素を返すためです。
item1 の後に item2 を探し始めてもいいですか? CSS3 ~ セレクターを使用します。例:
rrree
この方法は可能な場合もあれば、不可能な場合もあります。なぜ?
DOM 構造はまったく変わっていないため、CSS をそのまま使用して視覚的に位置を変更するだけです。
したがって、2 番目の方法は、当然 left の値を変更するだけでなく、交換中に DOM の位置も交換します。
swap (value1, value2) { const item1 = this.el.querySelector(`[data-value='${value1}']`) const item2 = this.el.querySelector(`[data-value='${value2}'] ~ data-value='${value2}']`)}
しかし、この方法はまだ機能しません。 insertBefore は DOM から element2 を削除するためです。この場合、「スワップ」グラデーション効果はありません。
案の定、まだ DOM 要素を使用できません。この場合、最初のメソッドのみを返すことができます。
この時、Reactでループする際にkey属性を書かなければいけないとふと思いました。それから。 。 。次に、キーと数値をバインドするだけで、その数値に対応する DOM 要素を見つけるには、キーを使用するだけで済みます。
function swapDOM(element1, element2) { element1.parentNode.insertBefore(element2, element1);}
ついに「スワップ」アニメーションが完成しました。もっと良い実装方法はありますか?
並べ替えアルゴリズムが次のようになっているとします。
// data = [64, 39, 78, 36]this.items = data.map((d, i) => ({key: `key-${i}`, value: d}))swap (key1, key2) { const item1 = this.el.querySelector(`[data-key='${key1}']`)}
これは正しくありません。 。
ただし、「スワップ」アニメーションは実行を終了しており、グラデーション効果はまったくありません。次のスワップ アニメーションが実行される前に、前のスワップ アニメーションが完了するまで待機する必要があります。なぜこうなった?なぜなら、私たちの 2 つの for は瞬時に実行できるからです = =
この問題を解決するにはどうすればよいでしょうか?間隔を設定しますか?並べ替えアルゴリズムのロジックが混乱するようです。
突然、jQuery にはアニメーションキューがあるらしいと思いました。
つまり、最初にすべてのアニメーションをキューに入れることができます。次に、1 つずつデキューし、1 つずつ呼び出します。
sort () { const items = this.items for (let i = 0; i < items.length; i++) { for (let j = 0; j < items.length - i - 1; j++) { const item1 = items[j] const item2 = items[j + 1] if (less(item2.value, item1.value)) { swap(j, j + 1, items) } } } return this.items}
Zhihu の回答を読んだ後、この問題を実装する他の方法があります。 一般的に、非同期プログラミングの問題を解決する方法。
CSS 疑似要素 ::before と attr 関数を使用して、対応する数値を棒グラフに表示できます。
for () { for () { if (less(item2.value, item1.value)) { this.queue.push(() => this.swap(item1.key, item2.key)) } }}play () { const intervalId = setInterval(() => { if (this.queue.length === 0) { clearInterval(intervalId) } else { const swap = this.queue.shift() swap() } }, 2 * 1000)}
私たちのコードは、他の並べ替えアルゴリズムに拡張できるようにインターフェイスを設計する方法など、最適化を続けることができます。また、並べ替え前、並べ替え中、並べ替え後の状態の色を異なる色に設定するなど、ユーザー エクスペリエンスも考慮されています。