1番大切なこと
pagesでは「配置」と「状態」を考えることが大事。
この記事で知れること
1.フッターを1番下に固定する方法(inset)
2.mx-auto(中央に寄せられるTailwindCSS)
3.vueにおけるv-model(これから学びなおす、親と子を連携させるもの)
4.プロフィール編集画面のつくりかた(editing)
5.ref(状態)の中身はvalueでさわる
6.状態設計のしかた
目次
1.はじめに
2.担当部分と学んだことpages編
3.まとめ
4.おわりに
1. はじめに
1つ前のcomponents編の続きです。今回はpagesの部分を整理します。
前編でプロジェクト概要などについては書いたので、
〇pages(実際に表示する画面/ここに画面の1部としてコンポーネントをよんでくる)
- home.vue(チャット相手一覧ページ)
- serch.vue(検索画面ページ)
- chat/[id].vue(チャット画面ページ、会いたい度はここに表示したい)
- my-profile.vue(自分のプロフィール/編集できるようにする)
- other-profile.vue(相手のプロフィール/チャットに飛ぶボタン作る)
これらについて書く。前編で書いたコンポーネントをやっと画面に表示する段階となりました。
2. 担当部分と学んだこと(pages編)
home.vue
まずはhome.vueからみていきます。。
home.vueの完成イメージデザインはこれです。
この中で私がさわったところはフッターを呼ぶところだけだからシンプルです。
今はまだどの画面にも表示されていないので、home.vueに読びます。
ここで、問題が発生しました。
フッターが1番下に来ない!
①divタグの外側に出してみた
divタグの中に入っているとぎゅっと固まってしまう、ということを教えてもらい、外側に置いてみました。ですが、無理でした。
②Tailwindを学ぶ
先輩に教えてもらった内容が↓です。
tailwindは単語だけで定義付けられるもの。
class:どんな要素か決めている。CSSかくよ~って言ってる感じ。
min-h-screen:hはheigh(高さ)のことで、画面いっぱいの高さにするという意味。
flex:横並びにする。flexと指定した下の要素を一括に持っているイメージ
items-center justify-center:centerの部分で画面中央と決めている。
fixed:固定する
今回のフッターでは、横幅は画面いっぱいにして、高さは1番下によせたいです。
right:画面の右側からの距離
left:画面の左側からの距離
↑この隙間はどちらも0にしてあげたい。
position : fixed
1.right:0
2.left:0
3.bottom:0
これらをTailwindで指定すると、insetというものを使えます。x軸、つまり横幅の話をしていて、それを0にすると横幅が画面いっぱいになる。(rightとleftを同時に0にできる)
では、実際のコードを見ていきます。
script setupタグ、つまりJavascript(HTMLとCSSだけでは書けない部分をかける)を書くところの中に
import Footer from '~/components/Footer.vue'
次に、templeteタグ、つまりHTMLの中の1番したに、
<Footer class="fixed inset-x-0 bottom-0"/>
↑これが先ほどの一番下に固定するためのコードです。
①fixed:画面に固定する
②inset-x-0:左右を0にして横幅いっぱいにする
③bottom-0:下に固定する
serch.vueでもフッターを読んでくる以外は先輩たちがしてくださったのでこれから1行ずつ理解していく予定です。
chat/[id].vue
ここでは、components編で作成した会いたい度を表示します。
画面の完成イメージデザインはこれです。↓
こんな感じでヘッダー部分を除いたチャット画面の1番上に最初は表示されるようにするのが目標です。
まずは、フッターの時と同様、コンポーネント編で作った会いたい度のコンポーネントを、script setupタグの中に書くことで呼び出す必要があります。
import MeetDesireSlider from '~/components/MeetDesireSlider.vue'
次に、呼び出しただけでは表示できないので、HTMLを書くtemplateタグの中にもコードを書きます。
<div class=" border-b border-gray-100">
<div class="max-w-md mx-auto">
<MeetDesireSlider v-model="desire" />
</div>
</div>
↑のコードは2つのdivタグで構成されているので外側と内側で分けてみていきます。
①外側のタグ
レイアウトをまとめるための箱です。TailwindCSSを使っています、
border-bの部分で、下にだけ線を引いています。(border-bottom)
border-gray-100の部分でその下の線をグレーにしています。
つまり、会いたい度の下にうっすら線を引くための箱です。
②内側のタグ
中身を中央に寄せるための箱です。
div class="max-w-md mx-auto"
mdはmidiumで、最大幅maxをmidiumサイズまでに制限しています。
mx-autoでは、中央に寄せています。
MeetDesireSlider v-model="desire"
この部分!これがとっても大切です。
これはもともとのコンポーネントのconst desire = ref(...)とつながっています。
vueの v-modelというのは変数とフォームを都度入力しなくてもデータを簡単に連携できるものです。
親 desire
↓ props
子 modelValue
↓ ユーザー操作(スライダー)
子が emit('update:modelValue', 新しい値)
↓
親 desire が更新される
こんな流れになっているのがここのv-modelという書きやすくした省略形で書いています。まとめるとv-modelは「値を渡す+変更を親に返す」を1行で書ける省略記法ということです。
これは、
この記事を見ながら書きました。
こうすることで、会いたい度を表示するだけではなく、スライダーの値はdesireという状態と同期できました!
この部分あんまり理解できてないから復習する
my-profile.vue
ここでは、プロフィール編集画面を表示します。
デザインの完成イメージ、つまり目標はこれです。
この画面で特に学んだところ
①プロフィール編集ボタンを押したら 編集できる・保存、キャンセル が出てくる。
②編集モードの時に▼ボタンを押したら選択肢リストを展開する(学部とか)
この2点に絞って書き残しておきます。
①編集できる + 「保存・キャンセル」が出てくる仕組み
キーワードはediting。
const editing = ref(false)
まずはこの部分から復習します。
①const editing = ...
editingという名前の変数を定義している。constなので変数そのものは入れかえれない。
でも、中身、値は変えることができる。
②ref(false)
編集しているかどうかを監視する関数。これは初期値=編集していない状態です。
だから、
false:編集していない閲覧モード
true:編集モード
ということがわかります。
これを実際どうつかうかというと
editing.value = true // 編集開始
editing.value = false // 編集終了
このように、refの中身はvalueでさわります。これは、保存・キャンセルするときに
async function save() {
...
editing.value = false
}
function cancel() {
Object.assign(form.value, original.value)
editing.value = false
}
けれどtempleteタグの中の場合、vueでは.valueを使わないらしいです。
プロフィール編集ボタンのコードをみてみると、
<button
v-if="!editing && !isLoading"
...
@click="toggleEdit"
>
プロフィール編集
</button>
こんな感じで、v-if="!editing"の部分で編集していないときだけ表示する。
このボタンのコードを1つずつ見ていきます。
①v-if
これは条件つき表示です。条件がtrueこのボタンが存在する。
②!editing
editingは編集モードかどうか。
!は否定(NOT)
editing === false → !editing === true
編集していないときという意味を表しているコードです。
③&&!isLoading
&&はAND(かつ)→両方trueじゃないとだめ
isLoadingは「処理中・通信中かどうか」。それに否定の!がついているから今は読み込み中じゃないってこと。
〇v-if="!editing && !isLoading"
これは、編集していない && 読み込み中でない。
このときだけボタンを表示するということ。
①▼ボタンを押したら選択肢リストを展開する(学部とか)
ここは、
<label class="flex flex-col gap-1">
<!--学部の見出しはここ-->
<div class="text-sm text-yellow-900">学部 <span class="text-red-500">*</span></div>
<!-- 値はコードに統一(make-profile準拠) -->
<select :disabled="!editing || isLoading" v-model="form.department"
class="border-2 border-[var(--meetupr-sub)] p-2 rounded disabled:opacity-50 disabled:cursor-not-allowed bg-white text-sm outline-none focus:border-orange-500 focus:ring-2 focus:ring-orange-200 appearance-none ">
<option value="" disabled>学部を選択</option>
<option value="business">経営学部</option>
<option value="production_science">政策科学部</option>
<option value="information_science">情報理工学部</option>
<option value="film_studies">映像学部</option>
<option value="psychology">総合心理学部</option>
<option value="global_liberal_arts">グローバル教養学部</option>
</select>
</label>
こんなコードです。ここだけ見ると結構理解しやすそうって思えます。
この部分は本当に最初らへんに担当したところなので、AIに聞きまくってたところです。今ここでしっかり理解して、これから自分で使えるようにしておきます。
また1行ずつ見ていきます。
①<label class="flex flex-col gap-1">
flex-col
TailwindCSSで、カラム(縦に並べる)という意味です。今回は選択肢を縦に並べる。
gap-1
要素同士のすきまをあけるということ。
②<select>ここが本体!
〇disabled="!editing || isLoading"
編集していないという意味の!editingと、通信中という意味のisLoading
このどちらも無効にするという意味。
このカラムを出しているときは編集していて通信中だからですね。
〇<option value="○○">学部名</option>
value="":まだ選ばれていない状態
表示されるのは「学部名」
中身は○○の部分で名前が付けられている。
で、この編集できる部分をすべて手取り除いたのがother-profile.vue、ほかの人のプロフィール画面です。
3. まとめ
ここでは、componentsで作成した部品を「どの画面で・どう配置するか」を復習した。
特に、フッターを画面下に固定する方法(fixed/inset-x-0/bottom-0)、会いたい度を中央に配置するためのmx-auto、v-modelw使った親子コンポーネント間の状態共有、そしてrefとeditingを使った編集モードの切り替えが学んだ点でした。
componentsは「何を作るか」、pagesは「どう使うか」を考える場所です。
4. これからどうすべきか
この記事をAIに送って、私は何ができていないのか、それはどうやったら成長できるのか聞いてみた。
①設計はまだあと追い
今は「動かしたい→書く→あ、足りないや→足す」って流れになりがち。
コード書く前に30秒だけ考えてみる。
・この画面(orコンポーネント)は何のため?
・ここが持つ責任は1つ?複数?
・「表示」だけ?「操作」も持つ?
例:会いたい度
・役割:会いたい度を表示・変更する
・状態:開いてる/閉じてる、移動中/移動してない
こんな感じで最低限の設計をしてから実装するようにしてみる。
②「最初に状態を整理する」が遅い
状態を日本語で書くようにする。
今までは、
・とりあえず書く
・バグ出る
・状態が足りないと気づく
これからやることは、
実装前に必ずこれを書く。
このUIにはどんな状態がある?
-Aのとき
-Bのとき
-押している最中とき
今回だったら「最小化ボタンをさわっているとき」と「そうでないとき」に気づけた。
これが状態設計できた瞬間。
これを次からはコードを書く前に書く
そうすることでrefやifが自然に決まる。
③JavaScriptの基礎(条件分岐・イベント)が感覚寄り
イベントを言葉で説明する練習。
たとえば「もし開いてたらこれをして、そうじゃなかったらこれ」というように、説明できたらOK、できなかったら理解不足ということ。
たしかに、これをしたら成長してみんなに少しでも近づける気がしました。
この②の状態設計で、名前の付け方もあるらしい。
1.状態は「事実」を書く
×clickFlag
×tmp
◎isOpen
◎isDragging
「今どうなってる?」にこたえる名前にするということ。
2.is/has/canから始める
これは世界共通ルールみたいなものらしい。
is ... 状態を表す(isActiveとか)
has ... 所有を表す(hasFileとか)
can ... 可能を表す(canMoveとか)
should ... すべきかどうか(shouldChangeとか)
3.状態は「2択」で考える
trueのとき、日本語で自然に読めるか?と考えるといいらしい。
isOpen→開いてるなら、とわかる。
flag1→???となる。
4.計算結果は状態にしない
const isLeftTooMuchとかはだめ。
const leftならOK。
状態=入力
状態設計の黄金フレーズ 「今このUIにはどんな状態が存在しうる?」
・開いてる/閉じてる
・動かしてる/止まってる
・選ばれてる/されてない
これを変数にするだけ。
これからコードを書く前に考えていきたいことは、
①この画面(orコンポーネント)は何のため?
②「表示」だけ?「操作」も持つ?
③このUIにはどんな状態がある?
-Aのとき
-Bのとき
-押している最中とき
これを考えて、ある程度の流れをイメージしてからコードを書き始めるとよくなれるとわかった。書くだけではなく、設計をできるようになることを目標としてこれからやっていきたい。


