Open2

【Vue3】CompositionAPIでGitHubのTodoリストCloneに挑戦した履歴

shoetshoet

画面サイズの固定 & 部分スクロール

以下を実現する必要がある。

  • ボートの領域の高さを100%に固定する
  • 各TodoList領域をスクロールさせる
shoetshoet

ボートの領域の高さを100%に固定する

  • 子要素(各TodoList)内でスクロールを発生させるために、ボートの外枠となる部分が画面内の収まるように固定する必要がある。
  • 外枠となるtodo-view__todoheight: 100vhを指定。
<div class="todo-view__header" ref="header">
  <div class="todo-view__title">
    GitHub TODO Clone
  </div>
</div>
<div class="todo-view__todo" v-bind:style="diffHeaderHeight">
  <div class="todo-view__todo-list">
    <div class="todo-view__todo-list__title">
      Todo
    </div>
    <TodoList/>
  </div>
  <div class="todo-view__todo-list">
    <div class="todo-view__todo-list__title">
      InProgress
    </div>
    <TodoList/>
  </div>
  <div class="todo-view__todo-list">
    <div class="todo-view__todo-list__title">
      Done
    </div>
    <TodoList/>
  </div>
</div>
.todo-view__todo {
  height: 100vh;
  display: flex;
  padding-left: 30px;
  padding-right: 30px;
  border: 1px solid rgba(128, 128, 128, 0.817);
  background-color: rgb(39, 43, 50);
}

しかし、これではヘッダー部分(todo-view__header)の高さが考慮されていないので、ヘッダー部の高さを画面の高さから除外した高さをボード部分の高さとしてvueからv-bind:styleで埋め込む方法を取った。

  • headerをrefとしてHTML側に埋め込む
  • headerの高さをViewPortの割合として計算するheaderVhLoad()を作成
  • onMounted時と画面のリサイズ時にheaderVhLoad()の実行とwatchを使ってdiffHeaderHeight変数を更新
  • diffHeaderHeight変数をボード部分の高さにv-bind:styleで埋め込み
import { ref, onMounted, watch } from 'vue';

import TodoList from './TodoList.vue';

const header = ref(null);
const headerVhPercentage = ref(0.0);
const diffHeaderHeight = ref('height: 100vh');
const marginHeaderVh = 3;

watch(headerVhPercentage, (newValue) => {
  const ret = Math.round(newValue*100);
  console.log(ret);
  diffHeaderHeight.value = `height: calc(100vh - ${ret}vh - ${marginHeaderVh}vh)`
})

const headerVhLoad = (): void => {
  if (header.value) {
    // calc header ViewPort HeightPercentage
    const element = header.value as HTMLElement;
    const headerHeight = element.offsetHeight;
    const viewportHeight = window.innerHeight;
    const percentage = headerHeight / viewportHeight;
    headerVhPercentage.value = percentage;
  }
}

onMounted(() => {
  headerVhLoad();
  window.addEventListener('resize', headerVhLoad);
})

各TodoList領域をスクロールさせる

先述で親要素のtodo-view__todoの高さを固定したので、
todo-view__todo-listoverflow-y: autoを指定して、親要素の高さを超えたらスクロールさせるようにする。

.todo-view__todo-list {
  flex-grow: 1;
  margin: 5px;
  border: 1px solid rgba(128, 128, 128, 0.817);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  background-color: black;
  border-radius: 3px;
}

コード全体(2023/05/20 時点)
https://github.com/shoet/github-todo-clone-vue