環境
Vue.js 2.6.12
Vuetify 2.3.21
事象
開発中のアプリケーションの一部にVuetifyのexpanded付きv-data-tableを利用しています。expandedの配列の中にs3にアップロードした画像URLが含まれています。まずデバッグツールでテスト操作を行い問題ないことを確認後にデプロイ、スマホ端末で実際にサイトにアクセスし確認してみるとレスポンシブデザインが崩れるという問題が発生していました。
Qiitaやstackoverflowなど色々当たっても同様の報告が見当たらなかったので、ご参考まで私自身の回避策を共有させていただきます。
具体的には下の動作を見ていただいた方が早いかと思います。(横方向へのスライド操作は想定していません)
(説明)
スマートフォンではユーザー毎の投稿を下方向にスライドして見ることが出来、かつ「^」の展開ボタンをクリックすると投稿に紐づくさらに詳細なグラフやコメントが確認できるようになります。
本来は下方向にしかスライドできないはずなのに、1:展開ボタンをクリックして投稿の詳細を展開 2:展開ボタンをさらにクリックして展開された行を閉じると、何故か次の投稿が横方向に並んでしまいます。原因がハッキリしておらず推測ですが、expandedに画像データを含めると発生してしまうため、展開されるexpandedの情報の中に画像データが最初にURLとしてレンダリングされる事と関係しているのかと考えています。
回避策
モバイル端末での閲覧時には展開ボタンをクリック時に強制的に再レンダリングを行うように変更する強制的にtableタグのwidthを固定させる事で解決しました。(styleでのwidth指定やvue.jsのwatchを使ったwidth操作は色々試しましたがうまくい機能しませんでした・・・)
ポイントは
- mixinによる
window.addEventListener
を使ったisMobile
props(boolean型)による閲覧端末がモバイル端末か否かの判定 -
v-data-table
タグ内の:key
propsの設定です
isMobileの判定
私は以下のmixinをapp.vue
にimportをして常にisMobile
の情報を取得するようにしました。
export default {
data: () => ({
isMobile: false,
}),
beforeDestroy () {
if (typeof window === 'undefined') return
window.removeEventListener('resize', this.onResize, { passive: true })
},
mounted () {
this.onResize()
window.addEventListener('resize', this.onResize, { passive: true })
},
created () {
},
methods: {
onResize () {
this.isMobile = window.innerWidth < 450
},
},
}
v-data-tableのprops
ここの:key
にisMobile
がtrueの時のみexpanded.length
がバインドされ、変更時にv-data-table
が再レンダリングされます。expanded.length
は現在展開している行数となるので、つまり、展開ボタン『^』をクリックするたびに再レンダリングされtable
タグのwidth
が強制的に固定されます。
<v-data-table
<!-- 省略 -->
:single-expand="singleExpand"
:expanded.sync="expanded"
show-expand
<!-- ポイント -->
:key="isMobile ? expanded.length : ''"
calculate-widths
widths="100%"
>