반응형
SMALL
뷰포트를 ref로 인식한 값을 이용해서 뷰포트 넓이에 따라 Vuetify의 Hamburger Icon와 네비게이션메뉴를 조건부 렌더링하도록 하는 로직을 구현해보았습니다
<template>
<header class="header" ref="refs">
<div class="logo-title-box">
<p class="logo-title">ALLIGHT</p>
</div>
<nav class="nav-list">
<v-app-bar-nav-icon v-if="show"></v-app-bar-nav-icon>
<a-button v-else :key="headerButton" v-for="headerButton in headerList">
{{ headerButton }}
</a-button>
</nav>
</header>
</template><script>
import { onMounted, onUnmounted, ref } from '@vue/composition-api';
import AButton from './AButton.vue';export default {
name: 'a-header',
components: {
'a-button': AButton,
},
setup() {
const BUTTONS = ['상담받기', '피드', '나의 일기장', '로그인', '회원가입'];
const headerList = ref(BUTTONS); const refs = ref(null); const show = ref(false); const handleWidth = () => {
if (refs.value.clientWidth < 640) {
show.value = true;
} else {
show.value = false;
}
}; onMounted(() => {
handleWidth();
window.addEventListener('resize', handleWidth);
}); onUnmounted(() => {
window.removeEventListener('resize', handleWidth);
}); return {
refs,
show,
headerList,
};
},
};
</script>
<style lang="scss">
.header {
display: flex;
width: 100%;
justify-content: space-between;
margin: 24px 0;@media (max-width: 625px) {
margin: 24px 0;
}
}.nav-list {
display: flex;
justify-content: space-evenly;
gap: 16px;
align-items: center;
}.logo-title-box {
display: flex;
align-items: center;
}.logo-title {
display: inline-block;
font-size: 24px;
font-weight: 600;
}
</style>
header width가 640px이 넘은 경우
header의 width가 640px 이하인 경우
resize를 하는 로직을 react의 hook처럼 외부화 시킬 수 있습니다.
// @/hooks/useResize.ts
import { onMounted, onUnmounted, Ref } from '@vue/composition-api';
interface IRefs {
clientWidth: number;
}
function useResize(refs: Ref<IRefs>, result: Ref<boolean>): void {
const handleWidth = () => {
const refsObject = result;
if (refs.value.clientWidth < 640) {
refsObject.value = true;
} else {
refsObject.value = false;
}
};
onMounted(() => {
handleWidth();
window.addEventListener('resize', handleWidth);
});
onUnmounted(() => {
window.removeEventListener('resize', handleWidth);
});
}
export default useResize;
// @/components/AHeader.vue
<template>
<header class="header" ref="refs">
<div class="logo-title-box">
<p class="logo-title">ALLIGHT</p>
</div>
<nav class="nav-list">
<v-app-bar-nav-icon v-if="show"></v-app-bar-nav-icon>
<a-button
v-else
:key="headerButton.id"
v-for="headerButton in headerList"
@clickHandler="handleRoute(headerButton.link)"
>
{{ headerButton.name }}
</a-button>
</nav>
</header>
</template><script>
import { ref } from '@vue/composition-api';
import router from '@/router';
import { HEADER_BUTTONS } from '@/constants/constants';
import AButton from './AButton.vue';
import useResize from '../hooks/useResize';export default {
name: 'a-header',
components: {
'a-button': AButton,
},
setup() {
const headerList = ref(HEADER_BUTTONS); const refs = ref(null);
const show = ref(false); useResize(refs, show);
const handleRoute = (link) => {
if (window.location.pathname !== link) {
router.push(link);
}
}; return {
refs,
show,
headerList,
handleRoute,
};
},
};
</script>
반응형
LIST
'Vue' 카테고리의 다른 글
Vue Test Utils로 Unit Testing (0) | 2022.06.19 |
---|---|
setup에서 CSS Module에 접근하는 방법 (0) | 2022.06.18 |
버튼 컴포넌트에서 상위 컴포넌트의 함수 실행시키는 방법 - emit (0) | 2022.06.18 |
Quasar CSS를 Override 하는 방법 (0) | 2022.06.18 |
Quasar에서 Reset CSS 하는 방법 (0) | 2022.06.18 |