この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
前回に引き続き VeeValidate ネタです。
現象
以下のような感じで <v-dialog>
に scrollable
を設定した上で、<ValidationObserver>
と <v-form>
<v-card>
を組み合わせると、
ダイアログのレイアウトが崩れます。
レイアウトが崩れるダイアログ
<v-dialog v-model="dialog" scrollable max-width="300px">
:
:
<ValidationObserver v-slot="{ invalid }" ref="obs" immediate>
<v-form>
<v-card>
<v-card-title>Select Country</v-card-title>
<v-divider></v-divider>
<v-card-text style="height: 300px;">
<ValidationProvider v-slot="{ errors, valid }" name="country" rules="required">
<v-radio-group v-model="country" column :error-messages="errors" :success="valid">
<v-radio label="Bahamas, The" value="bahamas"></v-radio>
<v-radio label="Bahrain" value="bahrain"></v-radio>
:
:
</v-radio-group>
</ValidationProvider>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-btn color="blue darken-1" text @click="dialog = false">Close</v-btn>
<v-btn color="blue darken-1" text @click="dialog = false" :disabled="invalid">Save</v-btn>
</v-card-actions>
</v-card>
</v-form>
</ValidationObserver>
</v-dialog>
VeeValidate 適用前:
VeeValidate 適用後:
環境情報
- Node.js: 12.18.2
- Vue.js: 2.6.11
- Vuetify: 2.3.3
- VeeValidate: 3.3.7
- Vue CLI: 4.4.6
原因
issues にも上がっていましたが、あらゆるパターンに対応しているわけではないので、その場合は自分で実装すべき、という回答でクローズされていました。
See #3713. It isn't realistic to support every possible combination, you'll have to implement it yourself.
HTMLを確認したところ、VeeValidate の <ValidationObserver>
が発行する <span>
が原因で、Vuetify が定義している CSS にマッチしなくなっていました。
対処方法1
VuetifyのCSSは、以下のように .v-dialog--scrollable
と <form>
または .v-card
が親子関係である前提となっています。
VDialog.sass
.v-dialog--scrollable,
.v-dialog--scrollable > form
display: flex
> .v-card
display: flex
flex: 1 1 100%
flex-direction: column
max-height: 100%
max-width: 100%
> .v-card__title,
> .v-card__actions
flex: 0 0 auto
> .v-card__text
backface-visibility: hidden
flex: 1 1 auto
overflow-y: auto
上記の <span>
はこの間に挟まれる構造のため、scrollable
関係の CSS が効かなくなっていました。
そこで、親子ではなく子孫関係でも適用されるような別CSSを書いて適用することで、レイアウト崩れはなくなりました。
対処方法1の問題点
レイアウト崩れはなくなったのですが、Vuetify 標準とは別のCSSを定義したことにより将来的な変更に追従できなくなる、というリスクがあります。
そのため、保守性を重視したいシステムの場合はあまり取りたくない方法です。
対処方法2
方法1で最低限の保険は掛けた状態ですが、他に方法はないかと考え、改めて VeeValidate のドキュメントを確認したところ、なんとそのまんまの情報がありました。
A slim prop can be used to force the component to be renderless, by default it is set to false.
<ValidationObserver>
に slim
を適用するだけで、レイアウト崩れはなくなりました。
まずは一次ソースに当たれ、という原則を改めて思い知ることになりました…(Vuetify側でなんとかすべきと考えて、VeeValidate 側で対処されているという想像に至らなかった)。
例によって、上記確認出来るソースを以下リポジトリに置いています。