VueはElementUIのフォームサンプルコードを模倣する

VueはElementUIのフォームサンプルコードを模倣する

実装要件

ElementUI を模倣したフォームは、インデックス コンポーネント、Form フォーム コンポーネント、FormItem フォーム項目コンポーネント、Input および CheckBox コンポーネントの 4 つのレイヤーに分かれています。具体的な分担は次のとおりです。

インデックスコンポーネント:

  • 実装: アセンブリを実現するために、Form コンポーネント、FormItem コンポーネント、Input コンポーネントをそれぞれ導入します。

フォームフォームコンポーネント:

  • 実装: 予約済みスロット、管理データ モデル モデル、カスタム検証ルール、グローバル検証メソッドの検証。

FormItem フォーム項目コンポーネント:

  • 実装: スロットを予約し、ラベルを表示し、データ検証を実行し、検証結果を表示します。

入力およびチェックボックスコンポーネント:

  • 実装: データ モデル v-model をバインドし、FormItem コンポーネントに検証を実行するように通知します。

入力コンポーネント

具体的な実装は以下のとおりです。

1. カスタム コンポーネントは、v-model を実装するために :value と @input を実装する必要があります。

2. 入力ボックスのデータが変更されたら、親コンポーネントに通知して検証を実行します。

3. 入力コンポーネントのタイプがパスワードの場合、コンポーネント内で v-bind="$attrs" を使用して、props 以外のコンテンツを取得します。

4. 最上位コンテナーが属性を継承しないようにするには、inheritAttrs を false に設定します。

入力コンポーネントの実装:

<テンプレート>
 <div>
 <input :value="値" @input="onInput" v-bind="$attrs" />
 </div>
</テンプレート>

<スクリプト>
エクスポートデフォルト{
 inheritAttrs: false, // トップレベルのコンテナがプロパティを継承しないようにする props: {
 価値: {
 タイプ: 文字列、
 デフォルト: ""
 }
 },
 データ() {
 戻る {};
 },
 メソッド: {
 入力時(e) {
 // 親コンポーネントに値の変更を通知します this.$emit("input", e.target.value);
 
 // FormItem に検証を実行するよう通知します // Input コンポーネントと FormItem コンポーネントの間に世代が存在する可能性があるため、この記述方法は堅牢ではありません this.$parent.$emit("validate");
 }
 }
};
</スクリプト>

<スタイル スコープ></style>

注: コードでは、イベントをディスパッチするために this.$parent を使用します。この記述方法は堅牢ではなく、Input コンポーネントと FormItem コンポーネントの間に世代のギャップがある場合に問題が発生します。具体的な解決策については、記事の最後にあるコード最適化のセクションを参照してください。

チェックボックスコンポーネント

1. input と同様に、checkBox の双方向データ バインディングをカスタマイズします。:checked と @change を実装する必要があります。

CheckBox コンポーネントの実装:

<テンプレート>
 <セクション>
 <input type="checkbox" :checked="チェック済み" @change="onChange" />
 </セクション>
</テンプレート>

<スクリプト>

エクスポートデフォルト{
 小道具: {
 チェック済み:
 タイプ: ブール値、
 デフォルト: false
 }
 },
 モデル: {
 プロパティ: "チェック済み",
 イベント: 「変更」
 },
 メソッド: {
 onChange(e) {
 this.$emit("change", e.target.checked);
 this.$parent.$emit("検証");
 }
 }
};
</スクリプト>
<style スコープ lang="less"></style>

FormItem コンポーネント

具体的な実装は以下のとおりです。

1. Input コンポーネントまたは CheckBox コンポーネント用のスロットを予約します。

2. ユーザーがコンポーネントにラベル属性を設定すると、ラベル タグが表示されます。

3. 検証イベントをリッスンし、検証を実行します (検証には async-validator プラグインを使用します)。

4. 検証ルールが満たされていない場合は、検証結果を表示する必要があります。

開発プロセスでは、いくつかの問題について考える必要があります。

1. コンポーネント内で検証する必要があるデータと検証ルールを取得するにはどうすればよいですか?

2. フォームには、ユーザー名、パスワード、電子メールなど、複数のメニュー項目があります。FormItem コンポーネントは、どのメニューが検証されているかをどのように認識するのでしょうか?

FormItem コンポーネントの実装:

<テンプレート>
 <div class="formItem-wrapper">
 <div class="content">
 <label v-if="label" :style="{ width: labelWidth }">{{ label }}:</label>
 <スロット></スロット>
 </div>
 <p v-if="errorMessage" class="errorStyle">{{ errorMessage }}</p>
 </div>
</テンプレート>

<スクリプト>
「async-validator」からスキ​​ーマをインポートします。

エクスポートデフォルト{
 挿入: ["formModel"],
 小道具: {
 ラベル: {
 タイプ: 文字列、
 デフォルト: ""
 },
 プロパティ: 文字列
 },
 データ() {
 戻る {
 エラーメッセージ: "",
 ラベル幅: this.formModel.labelWidth
 };
 },
 マウント() {
 // 検証イベントをリッスンし、検証を実行します this.$on("validate", () => {
 これを検証します。
 });
 },
 メソッド: {
 検証() {
 // コンポーネント検証を実行する // 1. データを取得する const values ​​= this.formModel.model[this.prop];
 // 2. 検証ルールを取得する const rules = this.formModel.rules[this.prop];
 // 3. 検証を実行する const schema = new Schema({
 [this.prop]: ルール
 });

 // パラメータ 1 は値、パラメータ 2 は検証エラー オブジェクトの配列です。// 検証は Promise<Boolean> を返します。
 schema.validate({ [this.prop]: values ​​}, errors => { を返します。
 if (エラー) {
 this.errorMessage = エラー[0].メッセージ;
 } それ以外 {
 this.errorMessage = "";
 }
 });
 }
 }
};
</スクリプト>

<style スコープ lang="less">
@ラベル幅: 90px;

.formItemラッパー{
 パディング下部: 10px;
}
。コンテンツ {
 ディスプレイ: フレックス;
}
.errorStyle {
 フォントサイズ: 12px;
 色: 赤;
 マージン: 0;
 左パディング: @labelWidth;
}
</スタイル>

まず、上記の 2 つの質問に答えてみましょう。これには、コンポーネント間の値の転送が含まれます。前回の記事「コンポーネントの値の転送と通信」を参照してください。
まず、フォーム データと検証ルールがインデックス コンポーネント内で定義され、Form コンポーネントにマウントされます。フォーム検証項目は FormItem コンポーネントで発生します。Form コンポーネントは最初に props を通じて渡されたデータを受け取り、次に provide/inject を通じて FormItem コンポーネントの子孫コンポーネントに渡します。

日常生活で ElementUI のフォーム検証を使用すると、検証が必要な各フォームに prop 属性が設定され、その属性値がバインドされたデータと一致していることがわかります。ここでの目的は、FormItem コンポーネントで検証を実行するときに、相対的な検証ルールとデータ オブジェクトを取得できるようにすることです。

FormItem コンポーネントでは、inject を使用して注入された Form インスタンスを取得し、prop 属性と組み合わせることで、フォーム データと検証ルールを取得できます。

// 1. データを取得する const values ​​= this.formModel.model[this.prop];

// 2. 検証ルールを取得する const rules = this.formModel.rules[this.prop];

async-validator プラグインを使用して、検証用のスキーマ オブジェクトをインスタンス化します。schema.validate は 2 つのパラメータを渡す必要があります。パラメータ 1 は、現在検証対象のフィールドと対応するルールで構成されるキーと値のペアのオブジェクトです。パラメータ 2 は、エラー情報 (配列) を取得するために使用されるコールバック関数です。検証メソッドは Promise<Boolean> を返します。

注: このコンポーネントの検証メソッドで、最後に return を使用する目的は、Form コンポーネントでグローバル検証を実行することです。

フォームコンポーネント

具体的な実装は以下のとおりです。

1. FormItem コンポーネント用のスロットを予約します。

2. Form インスタンスを FormItem などの子孫に渡して、検証データとルールを取得します。

3. グローバル検証を実行する

フォームコンポーネントの実装:

<テンプレート>
 <div>
 <スロット></スロット>
 </div>
</テンプレート>

<スクリプト>
エクスポートデフォルト{
 提供する() {
 戻る {
 formModel: this // 検証データとルールを取得するために、Form インスタンスを FormItem などの子孫に渡します};
 },
 小道具: {
 モデル: {
 タイプ: オブジェクト、
 必須: true
 },
 ルール:
 タイプ: オブジェクト
 },
 ラベル幅: 文字列
 },
 データ() {
 戻る {};
 },
 メソッド: {
 検証(cb) {
 // グローバル検証を実行します // マップの結果は Promise の配列です const tasks = this.$children.filter(item => item.prop).map(item => item.validate());
 // 検証済みとみなされるには、すべてのタスクが正常に検証される必要があります。Promise.all(tasks)
 .then(() => {
 cb(真);
 })
 .catch(() => {
 cb(偽);
 });
 }
 }
};
</スクリプト>

<スタイル スコープ></style>

Form コンポーネントで provide を使用して現在のコンポーネント オブジェクトを注入し、後続の子孫がデータやメソッドを取得しやすくします。

グローバル検証を実行する場合、まずフィルターを使用して検証する必要のないコンポーネントを除外し (FormItem コンポーネントに設定した prop 属性は、この属性がある限り検証する必要があります)、次にコンポーネント内で個別に検証メソッドを実行し (FormItem コンポーネントで戻りデータが使用されない場合、最終的に取得されるすべてのデータは未定義になります)、Promise の配列を返します。

Promise.all() メソッドを簡単に紹介します。

Promise.all() メソッドは、反復可能なタイプの Promise (注: Array、Map、Set はすべて ES6 の反復可能なタイプに属します) の入力を受け取り、1 つの Promise インスタンスのみを返します。その入力のすべての Promise の解決コールバックの結果は配列です。この Promise の解決コールバックは、すべての入力 Promise の解決コールバックが完了したとき、または入力反復可能オブジェクトに Promise が存在しないときに実行されます。拒否コールバックが実行され、入力プロミスの拒否コールバックが実行されるか、無効なプロミスが入力されると、エラーが直ちにスローされ、スローされた最初のエラーメッセージが拒否されます。

インデックスコンポーネント

モデルデータ、検証ルールなどを定義し、Form コンポーネント、FormItem コンポーネント、Input コンポーネントをそれぞれ導入してアセンブリを実装します。

インデックスコンポーネントの実装:

<テンプレート>
 <div>
 <フォーム:model="formModel":rules="rules"ref="loginForm"label-width="90px">
 <FormItem label="ユーザー名" prop="ユーザー名">
 <Input v-model="formModel.username"></Input>
 </フォーム項目>
 <FormItem label="パスワード" prop="パスワード">
 <入力タイプ="パスワード" v-model="formModel.パスワード"></入力>
 </フォーム項目>
 <FormItem label="パスワードを記憶する" prop="記憶する">
 <チェックボックス v-model="formModel.remember"></チェックボックス>
 </フォーム項目>
 <フォーム項目>
 <button @click="onLogin">ログイン</button>
 </フォーム項目>
 </フォーム>
 </div>
</テンプレート>

<スクリプト>
「@/components/form/Input」からInputをインポートします。
'@/components/form/CheckBox' から CheckBox をインポートします。
"@/components/form/FormItem" から FormItem をインポートします。
"@/components/form/Form" からフォームをインポートします。

エクスポートデフォルト{
 データ() {
 const validName = (ルール、値、コールバック) => {
 if (!値) {
 callback(new Error("ユーザー名は空にできません"));
 } そうでない場合 (値 !== "admin") {
 callback(new Error("ユーザー名エラー - admin"));
 } それ以外 {
 折り返し電話();
 }
 };
 const validatePass = (ルール、値、コールバック) => {
 if (!値) {
 コールバック(false);
 } それ以外 {
 折り返し電話();
 }
 };
 戻る {
 フォームモデル: {
 ユーザー名: "",
 パスワード: "",
 覚えておいてください: 間違いです
 },
 ルール:
 ユーザー名: [{ 必須: true、バリデータ: validatorName }],
 パスワード: [{ 必須: true, メッセージ: "パスワードが必要です" }],
 記憶: [{ 必須: true、メッセージ: "パスワードを記憶する必要があります", 検証: v​​alidator: validPass }]
 }
 };
 },
 メソッド: {
 ログイン時() {
 this.$refs.loginForm.validate(isValid => {
 有効かどうか
 alert("ログインに成功しました");
 } それ以外 {
 alert("ログインに失敗しました");
 }
 });
 }
 },
 コンポーネント:
 入力、
 チェックボックス、
 フォーム項目、
 形状
 }
};
</スクリプト>

<スタイル スコープ></style>

ログイン ボタンをクリックすると、グローバル検証メソッドが実行され、this.$refs.xxx を使用して DOM 要素とコンポーネント インスタンスを取得できます。

~ の上にも少し余白を残していますが、これは Input コンポーネントで検証を行うように親コンポーネントに通知するためのものです。現在は this.$parent.$emit() が使用されています。この方法には欠点があります。Input コンポーネントと FormItem コンポーネントが世代で離れている場合、this.$parent を使用して FormItem コンポーネントを取得することはできません。
親要素を見つけてイベントをディスパッチするための上向きループを主に実装するディスパッチ メソッドをカプセル化できます。コードは次のとおりです。

ディスパッチ(イベント名、データ) {
 親を this.$parent とします。
 // 親要素を検索する while (parent) {
 // 親要素は $emit parent.$emit(eventName, data); によってトリガーされます。
 // 親要素を再帰的に検索します。parent = parent.$parent;
 }
}

このメソッドはミックスインを使用して導入できます: mixins/emmiters.js

エクスポートデフォルト{
 メソッド: {
 ディスパッチ(イベント名、データ) {
 親を this.$parent とします。
 // 親要素を検索する while (parent) {
 // 親要素は $emit parent.$emit(eventName, data); によってトリガーされます。
 // 親要素を再帰的に検索します。parent = parent.$parent;
 }
 }
 }
};

入力コンポーネントを変更します。

<テンプレート>
 <div>
 <input :value="値" @input="onInput" v-bind="$attrs" />
 </div>
</テンプレート>

<スクリプト>
emmiter を "@/mixins/emmiter" からインポートします。

エクスポートデフォルト{
 inheritAttrs: false, // トップレベルのコンテナ継承属性を避ける mixins: [emmiter],
 小道具: {
 価値: {
 タイプ: 文字列、
 デフォルト: ""
 }
 },
 データ() {
 戻る {};
 },
 メソッド: {
 入力時(e) {
 // 親コンポーネントに値の変更を通知します this.$emit("input", e.target.value);
 
 // FormItem に検証を実行するように通知します // Input コンポーネントと FormItem コンポーネントの間に世代が存在する可能性があるため、この方法は堅牢ではありません // this.$parent.$emit("validate");
 
 this.dispatch("validate"); // レベル間の問題を解決するために、mixin で emmiter のディスパッチを使用します}
 }
};
</スクリプト>

<スタイル スコープ></style>

要約する

Vue で ElementUI のフォームを模倣する記事はこれで終わりです。Vue で ElementUI のフォームを模倣する関連コンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Vue ElementUI フォームのフォーム検証
  • Vue elementUI フォームのネストされた検証サンプルコード
  • Vue elementUI フォーム検証関数配列の多層ネスト
  • Vue elementui フォーム検証の実装
  • Vueの基本 ElementUIのフォームの詳しい説明

<<:  Linux システムでの virtuoso データベースの詳細なインストールと使用

>>:  Mybatis ページングプラグイン pageHelper の詳細な説明と簡単な例

推薦する

ネイティブ js はフォームの定期的な検証を実装します (検証後にのみ送信)

以下の機能が実装されています。 1. ユーザー名: onfouc は msg ルールを表示します。o...

Docker イメージのエクスポート、インポート、コピーの例の分析

最初の解決策は、イメージを公開イメージリポジトリにプッシュし、それをプルダウンすることです。 2 番...

MySQL統計の概要

MySQL は、SQL 解析とクエリ最適化のプロセスを通じて SQL を実行します。パーサーは SQ...

Nginx を使用してグレースケール リリースを実装する

グレースケールリリースとは、白と黒をスムーズに移行できるリリース方法を指します。 ABテストとは、グ...

MySQL全文インデックスの原理と欠点

MySQL フルテキスト インデックスは、特定のテーブルの特定の列に表示されるすべての単語のリストを...

Vue.jsはアイコンをクリックしてズームインし、

前回の記事では、Vue で画像の切り抜きや拡大・縮小、回転を実現する方法を紹介しました。今回は、アイ...

MySQL 8.0.23 無料インストールバージョンの設定詳細チュートリアル

最初のステップは、MySQL 8.0.23の無料インストールバージョンをダウンロードすることです。 ...

MySQL ベースのストレージエンジンとログの説明 (包括的な説明)

1.1 ストレージエンジンの概要 1.1.1 ファイルシステムストレージファイル システム: オペ...

ウェブページのメモリとCPU使用量を削減する方法

<br />Web ページによっては、サイズは大きくないように見えても開くのに非常に時間...

ネイティブ js カプセル化シームレスカルーセル機能

ネイティブjsカプセル化シームレスカルーセルプラグイン、参考までに、具体的な内容は次のとおりです。例...

MySQL で特殊文字を含むデータベース名を作成する方法の例

序文この記事では、MySQL で特殊文字を使用してデータベース名を作成する方法について説明します。こ...

Dockerコンテナを停止および削除できない問題の解決策

実行中のコンテナIDを見つける ドッカーps上記のコンテナの物理的な場所を見つける /var/lib...

MySQL 8.0.13 で日付を 0000-00-00 00:00:00 に設定すると発生する問題を解決する

データベース操作を学び始めたばかりです。今日、データを保存していたところ、エラーが発生していることに...

Vue ダイナミック バインディング アイコンの完全な手順

0 アイコンと画像の違いアイコンは文字であり、画像はバイナリ ストリームです。つまり、画像はアイコン...

ストリーマーボタンの効果を実現するCSS3アニメーション

CSS3 を学習する過程で、CSS3 属性を使用すると多くのクールな効果を簡単に実現できることが分か...