問題の説明Teambition ソフトウェアは、エンタープライズ オフィス コラボレーション ソフトウェアです。私の友人の会社のいくつかがこのソフトウェアを使用していると思います。フィルタリング機能は非常に興味深いです。この記事ではその機能を真似てみます。最終結果を見てみましょう。 一般的な機能効果は次のとおりです。
思考分析要件 1 と 2 については、まず 2 つのフルスクリーン ポップアップ ボックスを作成し、次にデータ内に 2 つの配列を定義します。1 つはよく使用される条件用、もう 1 つは一般的でない条件用です。一般的な条件は最初のポップアップ ボックスに v-fored され、一般的でない条件は 2 番目のポップアップ ボックスに v-fored されます。配列内の各項目は、名前、年齢などのフィルタリング フィールドの名前など、対応するコンテンツで構成する必要があります。フィルター フィールドの名前の次には、タイプもあります。HTML では、入力ボックス コンポーネント、選択コンポーネント、時間セレクター コンポーネントなど、3 種類のコンポーネントを記述する必要があります。 v-show を使用して、タイプ タイプに応じて対応するフィールドを表示します。たとえば、入力タイプは 1、選択タイプは 2、時間セレクター タイプは 3 です。表示されるコンポーネントはタイプです。 対応する 2 つの配列は次のとおりです。 topData: [ //共通フィルター項目を設定する { wordTitle: "名前", type: 1, // 1 は入力、2 は選択、3 は DatePicker content: "", // content は入力ボックスにバインドされた入力データです。options: [], // options はドロップダウン ボックスのすべてのコンテンツです。リクエストを送信して取得し、保存することができます。以下はシミュレーションです。optionArr: [], // optionArr は選択されたドロップダウン ボックスのコンテンツです。timeArr: [], // timeArr は日付選択間隔です。}, { wordTitle: 「年齢」、 タイプ: 1, コンテンツ: ""、 オプション: [], オプション引数: [], 時間配列: [], }, { wordTitle: 「授業の指導」、 タイプ: 2, コンテンツ: ""、 options: [ // ドロップダウンボックスのオプションを取得するリクエストを送信します { id: 1, 値: "クラス 1", }, { id: 2, 値: "クラス 2", }, { id: 3, 値: "3シフト"、 }, ]、 オプション引数: [], 時間配列: [], }, { wordTitle: 「参加時間」、 タイプ: 3, コンテンツ: ""、 オプション: [], オプション引数: [], 時間配列: [], }, ]、 bottomData: [ // 一般的でないフィルター項目を構成する { wordTitle: "作品番号", タイプ: 1, コンテンツ: ""、 オプション: [], オプション引数: [], 時間配列: [], }, { wordTitle: 「性別」、 タイプ: 2, コンテンツ: ""、 オプション: [ { id: 1, 値: "男性", }, { id: 2, 値: "女性", }, ]、 オプション引数: [], 時間配列: [], }, ]、 対応する HTML コードは次のとおりです。 <div class="rightright"> <el-入力 v-model.trim="アイテムコンテンツ" クリア可能 v-show="item.type == 1" placeholder="入力してください" サイズ="小" :popper-append-to-body="false" </el-input> ... <el-選択 v-model="item.optionArr" v-show="item.type == 2" 複数 placeholder="選択してください" > <el-オプション v-for="item.options 内の whatItem" :key="アイテムID" :label="whatItem.値" :value="アイテムID" サイズ="小" > </el-option> </el-select> <el-日付ピッカー v-model="item.timeArr" v-show="item.type == 3" タイプ="日付範囲" 範囲区切り文字="to" start-placeholder="開始日" end-placeholder="終了日" フォーマット="yyyy-MM-dd" 値の形式="yyyy-MM-dd" > </el-date-picker> </div>
要件 3 と 4 については、上位の要件を削除して下位の要件にドロップすると言えます。下記をクリックすると先頭へ移動します。したがって、対応する操作は、上位配列の項目を下位配列に追加し、上位配列の項目を削除し、下位配列の項目を上位配列に追加し、この行を削除することです。 (インデックスもあることに注意してください) 対応するコードは次のとおりです。 /* アイテムの削除アイコンをクリックすると、そのアイテムが bottomData 配列に追加され、その後 topData 配列からそのアイテムが削除されます (インデックスに基づいてどのアイテムであるかを判断します) 最後に、1つを削除し、インデックスを初期インデックス - 1 に設定します */ クリックアイコン(i) { this.bottomData.push(this.topData[i]); this.topData.splice(i, 1); this.whichIndex = -1; }, // 一番下の項目をクリックすると、イベント オブジェクトを使用して一番下のどの項目がクリックされたかを確認し、対応する項目を topData に追加して表示し、一番下の配列の項目を削除します // clickBottomItem(event) { this.bottomData.forEach((item, index) => { if (item.wordTitle == event.target.innerText) { this.topData.push(アイテム); this.bottomData.splice(インデックス、1); } }); }, 要件 5 と 6 は単純です。対応するコードは次のとおりです。完全なコードコメントが記述されています。 完全なコード<テンプレート> <div id="アプリ"> <div class="filterBtn"> <el-button type="primary" size="small" @click="filterMaskOne = true"> データ フィルター<i class="el-icon-s-operation el-icon--right"></i> </el-button> <トランジション名="フェード"> <div クラス="filterMaskOne" v-show="フィルターマスクOne" @click="filterMaskOne = false" > <div class="filterMaskOneContent" @click.stop> <div class="フィルターヘッダー"> <span>データフィルタリング</span> </div> <div class="filterBody"> <div class="outPrompt" v-show="topData.length == 0"> フィルター条件がまだありません。フィルター条件を追加してください... </div> <div クラス="filterBodyCondition" v-for="(item, index) in topData" :key="インデックス" > <div クラス="leftleft" @mouseenter="mouseEnterItem(インデックス)" @mouseleave="mouseLeaveItem(インデックス)" > <span >{{ item.wordTitle }}: <i クラス="el-icon-error" v-show="whichIndex == index" @click="クリックアイコン(インデックス)" </i> </span> </div> <div class="rightright"> <el-入力 v-model.trim="アイテムコンテンツ" クリア可能 v-show="item.type == 1" placeholder="入力してください" サイズ="小" :popper-append-to-body="false" </el-input> ... <el-選択 v-model="item.optionArr" v-show="item.type == 2" 複数 placeholder="選択してください" > <el-オプション v-for="item.options 内の whatItem" :key="アイテムID" :label="whatItem.値" :value="アイテムID" サイズ="小" > </el-option> </el-select> <el-日付ピッカー v-model="item.timeArr" v-show="item.type == 3" タイプ="日付範囲" 範囲区切り文字="to" start-placeholder="開始日" end-placeholder="終了日" フォーマット="yyyy-MM-dd" 値の形式="yyyy-MM-dd" > </el-date-picker> </div> </div> </div> <div class="filterFooter"> <div class="filterBtn"> <el-ボタン タイプ="テキスト" アイコン="el-icon-circle-plus-outline" @click="filterMaskTwo = true" >フィルター条件を追加</el-button > <トランジション名="フェード"> <div クラス="filterMaskTwo" v-show="フィルターマスク2" @click="filterMaskTwo = false" > <div class="filterMaskContentTwo" @click.stop> <div class="innerPrompt" v-show="bottomData.length == 0"> まだコンテンツがありません... </div> <div クラス="contentTwoItem" @click="クリック下部項目" v-for="(item, index) in bottomData" :key="インデックス" > <div class="mingzi"> {{ item.wordTitle }} </div> </div> </div> </div> </トランジション> </div> <div class="resetAndConfirmBtns"> <el-button size="small" @click="resetFilter">リセット</el-button> <el-button type="primary" size="small" @click="フィルターの確認" >確認</el-button > </div> </div> </div> </div> </トランジション> </div> </div> </テンプレート> <スクリプト> エクスポートデフォルト{ 名前:「アプリ」、 データ() { 戻る { filterMaskOne: false, // 2つのポップアップボックスの表示と非表示をそれぞれ制御するために使用されます filterMaskTwo: false, whichIndex: -1, // クリックを記録するために使用されるインデックス apiFilterArr:[], // ユーザーが入力したフィルターコンテンツを保存します topData: [ // 共通フィルター項目を構成します { wordTitle: "名前", type: 1, // 1 は入力、2 は選択、3 は DatePicker content: "", // content は入力ボックスにバインドされた入力データです。 options: [], // options はドロップダウン ボックスのすべての内容です。 optionArr: [], // optionArr は選択されたドロップダウン ボックスの内容です。 timeArr: [], // timeArr は日付の選択間隔です。 }, { wordTitle: 「年齢」、 タイプ: 1, コンテンツ: ""、 オプション: [], オプション引数: [], 時間配列: [], }, { wordTitle: 「授業の指導」 タイプ: 2, コンテンツ: ""、 options: [ // ドロップダウンボックスのオプションを取得するリクエストを送信します { id: 1, 値: "クラス 1", }, { id: 2, 値: "クラス 2", }, { id: 3, 値: "3シフト"、 }, ]、 オプション引数: [], 時間配列: [], }, { wordTitle: 「参加時間」、 タイプ: 3, コンテンツ: ""、 オプション: [], オプション引数: [], 時間配列: [], }, ]、 bottomData: [ // 一般的でないフィルター項目を構成する { wordTitle: "作品番号", タイプ: 1, コンテンツ: ""、 オプション: [], オプション引数: [], 時間配列: [], }, { wordTitle: 「性別」、 タイプ: 2, コンテンツ: ""、 オプション: [ { id: 1, 値: "男性", }, { id: 2, 値: "女性", }, ]、 オプション引数: [], 時間配列: [], }, ]、 }; }, マウント() { // ロードを初期化するときに、構成したよく使用されるフィルター項目とあまり使用されないフィルター項目のコピーを保存します。// ユーザーがリセット ボタンをクリックすると、それを取得して元のフィルター条件の状態に復元します。sessionStorage.setItem("topData",JSON.stringify(this.topData)) sessionStorage.setItem("bottomData",JSON.stringify(this.bottomData)) }, メソッド: { //マウスを動かすと削除アイコンが表示されます mouseEnterItem(index) { this.whichIndex = インデックス; }, // マウスが離れると、インデックスはデフォルト値 -1 に戻ります マウスアイテムを離れる() { this.whichIndex = -1; }, /* アイテムの削除アイコンをクリックすると、そのアイテムが bottomData 配列に追加され、その後 topData 配列から削除されます (インデックスに基づいてどのアイテムであるかを判断します) 最後に、1つを削除し、インデックスを初期インデックス - 1 に設定します */ クリックアイコン(i) { this.bottomData.push(this.topData[i]); this.topData.splice(i, 1); this.whichIndex = -1; }, // 一番下の項目をクリックすると、イベント オブジェクトを使用して一番下のどの項目がクリックされたかを確認し、対応する項目を topData に追加して表示し、一番下の配列の項目を削除します // clickBottomItem(event) { this.bottomData.forEach((item, index) => { if (item.wordTitle == event.target.innerText) { this.topData.push(アイテム); this.bottomData.splice(インデックス、1); } }); }, // クリックしてフィルターを確認します async confirmFilter() { // すべての入力ボックスの内容が空で、選択されたドロップダウンボックスの配列が空で、時間セレクターによって選択された配列が空の場合、ユーザーが内容を入力していないことを意味するため、フィルタリングする前にユーザーに内容を入力するよう促します。let isEmpty = this.topData.every((item)=>{ 戻り値 (item.content == "") && (item.optionArr.length == 0) && (item.timeArr.length == 0) }) if(isEmpty == true){ this.$alert('フィルタリングする前にコンテンツを入力してください', 'フィルターのヒント', { confirmButtonText: '確認' }); }それ以外{ // パラメータを収集し、フィルタリング要求を送信します。ここでは、パラメータをタイプ別に分類し、空でないユーザー入力コンテンツをデータ フィルタリング用の配列に保存してから、バックエンドに要求を送信する必要があります。 this.topData.forEach((item)=>{ if(item.type == 1){ if(item.content != ""){ フィルターアイテム = { フィールド:item.wordTitle、 値:アイテムの内容 } this.apiFilterArr.push(フィルター項目) } }そうでない場合(item.type == 2){ if(item.optionArr.length > 0){ フィルターアイテム = { フィールド:item.wordTitle、 値:item.optionArr } this.apiFilterArr.push(フィルター項目) } }そうでない場合(item.type == 3){ if(item.timeArr.length > 0){ フィルターアイテム = { フィールド:item.wordTitle、 値:item.timeArr } this.apiFilterArr.push(フィルター項目) } } }) // フィルタリングされたコンテンツを配列に入れてバックエンドに渡します (もちろん、パラメータを必ずしも配列に入れる必要はありません) // バックエンドに渡す具体的な形式については、後で詳しく説明します。console.log("Send request with filtered content", this.apiFilterArr); } }, // リセット時に、初期設定のフィルタ項目を取り出し、対応する2つの配列に割り当てます resetFilter() { this.topData = JSON.parse(sessionStorage.getItem("topData")) this.bottomData = JSON.parse(sessionStorage.getItem("bottomData")) }, }, }; </スクリプト> <style lang="less" スコープ> .filterBtn { 幅: 114ピクセル; 高さ: 40px; .filterMaskOne{ 上: 0; 左: 0; 位置: 固定; 幅: 100%; 高さ: 100%; zインデックス: 999; 背景色: rgba(0, 0, 0, 0.3); .filterMaskOneContent { 位置: 絶対; 上: 152px; 右: 38px; 幅: 344ピクセル; 高さ: 371px; 背景色: #fff; ボックスの影: 0px 0px 4px 3px rgba(194, 194, 194, 0.25); 境界線の半径: 4px; .filterHeader { 幅: 344ピクセル; 高さ: 48px; 下境界線: 1px 実線 #e9e9e9; スパン { 表示: インラインブロック; フォントの太さ: 600; フォントサイズ: 16px; 左マージン: 24px; 上マージン: 16px; } } .filterBody { 幅: 344ピクセル; 高さ: 275px; オーバーフロー-y: 自動; オーバーフロー-x:非表示; ボックスのサイズ: 境界線ボックス; パディング: 12px 24px 0 24px; .outPrompt{ 色: #666; } .filterBodyCondition { 幅: 100%; 最小高さ: 40px; ディスプレイ: フレックス; 下部マージン: 14px; .leftleft{ 幅: 88ピクセル; 高さ: 40px; ディスプレイ: フレックス; アイテムの位置を中央揃えにします。 右マージン: 20px; スパン { 位置: 相対的; フォントサイズ: 14px; 色: #333; 私 { 色: #666; 右: -8px; 上: -8px; 位置: 絶対; フォントサイズ: 15px; カーソル: ポインタ; } ホバー{ 色: #5f95f7; } } } .rightright { 幅: calc(100% - 70px); 高さ: 100%; /deep/ 入力::プレースホルダー { 色: rgba(0, 0, 0, 0.25); フォントサイズ: 13px; } /deep/ .el-input__inner { 高さ: 40px; 行の高さ: 40px; } /deep/ .el-select { .el-input--サフィックス { /deep/ 入力::プレースホルダー { 色: rgba(0, 0, 0, 0.25); フォントサイズ: 13px; } .el-input__inner { 境界線: なし; } .el-input__inner:ホバー{ 背景: rgba(95, 149, 247, 0.05); } } } .el-date-editor { 幅: 100%; フォントサイズ: 12px; } .el-range-editor.el-input__inner { 左パディング: 2px; 右パディング: 0; } /deep/.el-range-input { フォントサイズ: 13px !重要; } /deep/ .el-range-separator { パディング: 0 !重要; フォントサイズ: 12px !重要; 幅: 8% !重要; マージン: 0; } /deep/ .el-range__close-icon { 幅: 16px; } } } } .filterFooter { 幅: 344ピクセル; 高さ: 48px; ディスプレイ: フレックス; コンテンツの両端揃え: スペースの間; アイテムの位置を中央揃えにします。 ボックスのサイズ: 境界線ボックス; 左パディング: 24px; 右パディング: 12px; 上境界線: 1px 実線 #e9e9e9; .filterBtn { .filterMaskTwo { 位置: 固定; 上: 0; 左: 0; 幅: 100%; 高さ: 100%; 背景色: rgba(0, 0, 0, 0.3); zインデックス: 1000; .filterMaskContentTwo { 幅: 240ピクセル; 高さ: 320px; 背景: #ffffff; ボックスの影: 0px 0px 4px 3px rgba(194, 194, 194, 0.25); 境界線の半径: 4px; 位置: 絶対; 上: 360ピクセル; 右: 180px; オーバーフロー-y: 自動; ボックスのサイズ: 境界線ボックス; パディング: 12px 0 18px 0; オーバーフロー-x:非表示; .innerPrompt { 色: #666; 幅: 100%; 左パディング: 20px; 上マージン: 12px; } .contentTwoItem{ 幅: 100%; 高さ: 36px; 行の高さ: 36px; フォントサイズ: 14px; 色: #333333; カーソル: ポインタ; .ミンジ { 幅: 100%; 高さ: 36px; ボックスのサイズ: 境界線ボックス; 左パディング: 18px; } } .contentTwoItem:ホバー{ 背景: rgba(95, 149, 247, 0.05); } } } } } } } } // フェードインとフェードアウト効果を制御します。fade-enter-active、 .フェードアウトアクティブ{ 遷移: 不透明度 0.3 秒; } .フェードイン、 .フェードアウト{ 不透明度: 0; } </スタイル> 要約するここで注意する必要があるのは、マウスを動かすと、対応する小さな削除アイコンが表示されることです。大体こんな感じです。コードを書くのは簡単ではないので、一緒に頑張りましょう。 以上が、vue が Ele.me UI を利用して teambition のフィルタリング機能を模倣する詳細です。vue による teambition のフィルタリング機能の模倣の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: 異なるドメイン名への PC または携帯電話のアクセスを区別するように Nginx を構成する方法
>>: 現在使用されている設定ファイル my.cnf を表示する mysql メソッド (推奨)
今日は、MySQL データベースと SQL 標準 (および他のデータベース) の UPDATE ステ...
1. MySQL マスタースレーブ非同期1.1 ネットワーク遅延MySQLのマスタースレーブレプリケ...
1. 要件の説明特定の要素については、背景background-imageを半透明にしたいが、テキス...
最近、センタリングの問題に数多く遭遇したので、後で簡単に見つけられるように、時間をかけてそれらを要約...
マシンに MySQL バージョン 5.0 がすでに存在する場合は、最新バージョンの MySQL のイ...
インターネットにはすでにこの種の記事が溢れていますが、私がこれをまだ書いている理由は単純です。それは...
1. 現象早朝、オンライン テーブルにインデックスが追加されました。テーブル内のデータ量が大きすぎた...
この記事では、参考までに、ズームインとズームアウトのドラッグ機能を実現するためのVueの具体的なコー...
FirefoxでBGMを再生するための推奨コードがテストに合格しました空のコントロールパネルを開いて...
大きな落とし穴、Linuxシステムに付属するPythonのバージョンを簡単に削除しないでください1....
Raspberry Pi は ARM アーキテクチャをベースとしているため、Docker のインスト...
目次1. Props 親コンポーネント ---> 子コンポーネント通信2. $emit 子コン...
この記事では、例を使用して、MySQL トリガーの概要、トリガーの作成方法、およびトリガーの使用上の...
従来、開発者はインスタンスで必要になる可能性のあるデータに対して JavaScript クラス内にプ...
PostgreSQL はコンパイルされインストールされるため、起動時に起動するように設定する必要があ...