Vue CLI + TypeScript로 오미 복권을 당겼습니다.

qnote Advent Calendar 의 7일째입니다.

소개



요 전날 회사의 LT 에서 JavaScriptOptionalChainingNull合体演算子 에 대해 발표했습니다만, 그것이 계기로 TypeScript 사용하고 싶게 되었습니다.
어쨌든 뭔가 만들고 싶다고 생각했기 때문에 이번에는 Vue CLI 를 사용하여 Vue + TypeScript 로 오미쿠지를 끌 수 있는 정적인 web 앱을 만들어 보겠습니다.

초기 설정



환경


  • Vue CLI v4.1.1
  • TypeScript 의 지원은 v3.0 계에서 있는 것 같기 때문에, v3.0 계에서도 괜찮습니다.Vue CLI 설치는 여기서 생략됩니다.

    프로젝트 만들기


    $ vue create neko-omikuji
    

    대화 형식으로 초기 설정을 할 수 있습니다. 아래의 선택에서는 이번은 TypeScript 를 사용하고 싶으므로, 매뉴얼로 설정합니다.
    ? Please pick a preset: 
      default (babel, eslint) 
    ❯ Manually select features 
    

    그런 다음 설치할 기능을 선택합니다. 이번은 심플하게 사용하고 싶었으므로 아래와 같이 선택했습니다.
    ? Check the features needed for your project: 
     ◯ Babel
     ◉ TypeScript
     ◯ Progressive Web App (PWA) Support
     ◉ Router
     ◯ Vuex
     ◯ CSS Pre-processors
    ❯◉ Linter / Formatter
     ◯ Unit Testing
     ◯ E2E Testing
    

    그리고 여러가지 설정이 계속됩니다만 기호로 선택해 갑니다.
    ? Use class-style component syntax? Yes
    ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX
    )? No
    ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
    ? Pick a linter / formatter config: Airbnb
    ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selectio
    n)Lint on save
    ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
    ? Save this as a preset for future projects? No
    
    🎉  Successfully created project neko-omikuji.
    👉  Get started with the following commands:
    

    이 메시지가 나오면 작성 완료입니다!
    조속히 움직이자.
    $ cd neko-omikuji
    $ npm run serve
    



    예제 화면이 나왔습니다!

    구현



    오미쿠지를 당기면 당사의 고양이 직원의 이미지가 무작위로 표시되는 것을 목표로 했습니다.



    메인이 되는 페이지로부터 구현해 갑니다.
    데코레이터를 사용하여 Vue 를 작성하는 방법을 시도해 봅니다.

    Omikuji.vue
    <template>
      <div>
        <p>運試しにゃ🐱</p>
        <a
          href="#"
          @click="onLightboxOpen">
          <img
            alt="omikuji"
            class="omikuji"
            src="../assets/omikuji.png">
        </a>
    
        <lightbox
          v-if="isLightboxActive"
          :is-active="isLightboxActive"
          :src="src"
          :result="resultList[result]"
          @lightbox-close="onLightboxClose" />
      </div>
    </template>
    
    <script lang="ts">
    import { Component, Vue } from 'vue-property-decorator'
    import Lightbox from './Lightbox.vue'
    
    @Component({
      components: {
        Lightbox,
      },
    })
    export default class Omikuji extends Vue {
      // data
      isLightboxActive: boolean = false
    
      resultList: {} = {
        daikichi: '大吉',
        kichi: '',
        chukichi: '中吉',
        syokichi: '小吉',
        suekichi: '末吉',
        kyo: '',
        daikyo: '大凶',
      }
    
      result: string = ''
    
      number: number = 1
    
      // computed
      get src(): string {
        return `./img/${this.result}_${this.number}.png`
      }
    
      // methods
      getResult(): void {
        const keys = Object.keys(this.resultList)
        this.result = keys[Math.floor(Math.random() * keys.length)]
        this.number = Math.floor(Math.random() * 3) + 1
      }
    
      onLightboxOpen(): void {
        this.getResult()
        this.isLightboxActive = true
      }
    
      onLightboxClose(): void {
        this.isLightboxActive = false
      }
    }
    </script>
    
    ...
    

    템플릿이야말로 변하지 않지만,
    스크립트는 평상시의 Vue 의 작성법과는 상당히 다릅니다.
    data 는 클래스의 속성으로,computedgetset 접근자를 사용하여,method 는 클래스의 메소드로서,

    각각 정의됩니다.
    또한 components 옵션은 데코레이터를 사용합니다.

    그런 다음 이미지가 표시됩니다. Lightbox 구성 요소를 만듭니다.

    Lightbox.vue
    ...
    
    <script lang="ts">
    import {
      Component, Prop, Vue, Emit,
    } from 'vue-property-decorator'
    import FadeTransition from './FadeTransition.vue'
    
    @Component({
      components: {
        FadeTransition,
      },
    })
    export default class Lightbox extends Vue {
      @Prop({ default: false })
        isActive!: Boolean
    
      @Prop({ default: '' })
        src!: String
    
      @Prop({ default: '' })
        result!: String
    
      @Emit('lightbox-close')
      // eslint-disable-next-line class-methods-use-this
      onLightboxClick() {}
    }
    </script>
    
    ...
    

    부모 컴퍼넌트로부터 건네받는 props 도 데코레이터를 사용해 썼습니다.
    음, 솔직히 속성에 쓰는 것이 더 쉽습니다.$emit 또한 데코레이터를 사용합니다.

    완성



    네, 완성한 것이 이쪽이 됩니다.

    qnote 고양이 오미쿠지

    결론



    그래서 VueTypeScript에서 쉽게 놀아 보았습니다.
    처음에는 평소와 다른 기술 방법에 당황했습니다만, 형태를 명확하게 하면서 실장해 가는 것으로 기능의 이미지가 잡기 쉬우거나, 에디터의 서포트가 짙어지거나, 확실히 메리트는 있다고 느꼈습니다 .
    이번에 사용하고 싶었던 OptionalChaining 는 사용할 기회가 없었던 것과 Vue CLITypeScript 때때로, 3.5.3 를 공부하고 싶습니다!

    이번 작성한 코드는 여기 에 있으므로, 필요하면 봐 주세요.

    마지막으로, 소재를 빌린 원한다면 야님, 언제나 귀여운 사진을 찍어 주시는 qnote 여러분, 치유를 주는 폐사 고양이 사원의 분들, 감사합니다!

    좋은 웹페이지 즐겨찾기