実装要件ElementUI を模倣したフォームは、インデックス コンポーネント、Form フォーム コンポーネント、FormItem フォーム項目コンポーネント、Input および CheckBox コンポーネントの 4 つのレイヤーに分かれています。具体的な分担は次のとおりです。 インデックスコンポーネント:
フォームフォームコンポーネント:
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 つの質問に答えてみましょう。これには、コンポーネント間の値の転送が含まれます。前回の記事「コンポーネントの値の転送と通信」を参照してください。 日常生活で 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> を返します。
フォームコンポーネント具体的な実装は以下のとおりです。 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() メソッドを簡単に紹介します。
インデックスコンポーネントモデルデータ、検証ルールなどを定義し、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、メッセージ: "パスワードを記憶する必要があります", 検証: validator: 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 を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
<<: Linux システムでの virtuoso データベースの詳細なインストールと使用
>>: Mybatis ページングプラグイン pageHelper の詳細な説明と簡単な例
vue スキャフォールディング -> vue.cli大規模で完全に機能する Vue プロジェク...
MySql データベース システムをインストールして構成します。 1. ダウンロード http://...
使用シナリオ既存のサーバー A と B の場合、サーバー A の指定されたディレクトリ (たとえば、...
目次序文: 1. インデックスメソッドを作成する2. インデックスを作成するために必要な権限序文: ...
1. カーディナリティとは何ですか?カーディナリティとは、MySQL テーブルの列内の異なる値の数を...
証明書チェーンを生成するスクリプトを使用して、ルート証明書、中間証明書、および 3 つのクライアント...
行ごとに、暗い境界線の色を個別に定義できます。基本的な構文<TR 境界線の色を暗くする=col...
次のサンプル コードでは、Tomcat が XML を解析し、リフレクションを通じてオブジェクトを作...
(Web ページの読み込み中に、コンテンツが多すぎて読み込みと待機が続くことがあります。このとき、...
以下は、HTML で正規表現を使用してテーブルをチェックするサンプル コードです。具体的なコードの内...
最近、ビジネス側から、一部のユーザー情報の挿入に失敗し、エラー メッセージが「不正な文字列値:&qu...
序文フロントエンドページを書くとき、小さなアイコンなどの画像を使うことが多いです。画像を使うとコード...
序文Vue で要素を初回取得できない問題の解決方法は、ポップアップ ウィンドウで要素を取得するために...
導入:スライダー ドラッグ検証は現在、多くの場所で使用されています。週末に 1 つ作成しようと思い、...
1. タイトルHTML では、<h1></h1> から <h6>...