좌측 메뉴 리스트 - 반응형

손대중·2022년 6월 26일
0

블로그가 반응형을 지원하도록, 모바일 사이즈인 경우 좌측 메뉴 리스트 노출 로직을 달리 적용해 보자.

  • pc 화면
    • 헤더 메뉴 아이콘 미노출
    • 좌측 메뉴 리스트 계속 노출
  • mobile 화면
    • 헤더 메뉴 아이콘 노출
    • 기본적으로 좌측 메뉴 리스트 숨김 상태
    • 헤더 메뉴 아이콘 클릭시, 좌측 메뉴 리스트 toggle

일단 Header.svelte, Aside.svelte 화면을 반응형으로 만들어보고, 이후에 toggle 기능을 추가하자.

사실 Header.svelte 는 이미 반응형이 적용되어 있는 상태이므로 Aside.svelte 만 수정하면 됨.(블로그 틀 만들기 - svelte & material ui 참조)

  • Aside.svelte

    <!-- Don't include fixed={false} if this is a page wide drawer.
        It adds a style for absolute positioning. -->
    <Drawer variant={drawerVariant} fixed={false} bind:open={drawerOpen}>
        ...
    </Drawer>
    
    <svelte:window bind:innerWidth={innerWidth}/>
    
    <script>
        import Drawer, { Content, Header, Title, Subtitle, Scrim } from '@smui/drawer';
        import List from '@smui/list';
    
        let innerWidth;
    
        let drawerVariant = 'static';
        let drawerOpen = false;
    
        ...
    
        const setVisible = () => {
            if (innerWidth > 480) {
                drawerVariant = 'static';
                drawerOpen = true;
            } else {
                drawerVariant = 'modal';
                drawerOpen = false;
            }
        };
    
        $: setVisible(innerWidth);
    </script>

단순히 노출 여부 뿐 아니라 <Drawer /> 컴포넌트의 variant 값도 바꿔야 한다.

참고로 variant 값이 static 인 경우 고정된 화면 영역을 가지고 다른 element 들의 위치에 영향을 주고, modal 인 경우에는 다른 element 들 위치에 영향을 주지 않고 위에 겹쳐서 노출한다. (https://sveltematerialui.com/demo/drawer/ 참조)

따라서 Aside.svelte 에서 window 의 innerWidth 를 체크 & 감지할 필요가 있고, <svelte:window />innerWidth 를 bind 함으로서 체크 & 감지할 수 있다.

<!-- window 의 innerWidth 값 bind -->
<svelte:window bind:innerWidth={innerWidth}/>

<script>
	...
    
    let innerWidth;
    
    ...

	// innerWidth 의 변화 감지하고 setVisible 함수 실행
    $: setVisible(innerWidth);
</script>

참고로 <svelte:window />innerWidth 뿐만 아니라 여러 프로퍼티들을 bind 할 수 있고 click 과 같은 이벤트도 걸 수도 있고, 또한 svelte 에서는 window 뿐 아니라 self, body, head 등등 여러개의 special element 를 제공한다. (https://svelte.dev/tutorial/svelte-self 참조)


이제 toggle 기능을 추가하자.

Header.svelte 에서 click event 가 발생하면 Aside.svelte 에 전달해줘야 한다.

다만 svelte 에서는 부모 - 자식 컴포넌트 관계가 아니라면 event 전달이 쉽지 않다.

걍 복잡하게 머리 굴리지 말고 store 를 통해 asideOpen 변수를 만들고 관리하자.

  • Header.svelte 에서는 click event 발생시 storeasideOpen 업데이트
  • Aside.svelte 에서는 asideOpen 가 변경되면 화면 갱신

먼저 store/aside.js 를 만들고 위 로직에 맞춰 Header.svelte, Aside.svelte 를 수정하자.

  • store/aside.js

    import { writable } from 'svelte/store';
    
    export default asideOpen = writable(false);
  • Header.svelte

    <script>
        ...
    
        import asideOpen from '../store/aside.js';
    
        const onClick = () => {
            asideOpen.update(open => !open);
        };
    </script>
  • Aside.svelte

    <!-- Don't include fixed={false} if this is a page wide drawer.
        It adds a style for absolute positioning. -->
    <Drawer variant={drawerVariant} fixed={false} bind:open={drawerOpen}>
        ...
    </Drawer>
    
    <!-- Don't include fixed={false} if this is a page wide drawer.
        It adds a style for absolute positioning. -->
    <Scrim fixed={false} />
    
    <svelte:window bind:innerWidth={innerWidth}/>
    
    <script>
        import Drawer, { Content, Header, Title, Subtitle, Scrim } from '@smui/drawer';
        import List from '@smui/list';
    
        import asideOpen from '../../store/aside.js';
    
        let innerWidth;
    
        let drawerVariant = 'static';
        let drawerOpen = false;
    
        const setVisible = () => {
            if (innerWidth > 480) {
                drawerVariant = 'static';
                asideOpen.update(open => false);
            } else {
                drawerVariant = 'modal';
            }
        };
    
        asideOpen.subscribe(value => {
            drawerOpen = value;
        });
    
        $: setVisible(innerWidth);
    </script>

최종 화면은 아래와 같다.

모바일 버전일때 헤더 메뉴 아이콘 클릭시 좌측 메뉴 리스트도 잘 toggle 되는 것 확인~.

  • pc 화면

  • mobile 화면

    숨김 상태노출 상태

0개의 댓글