결과 화면

https://heejae0811.github.io/nuxt3-todo/

 

오늘의 할 일

오늘의 할 일은 무엇인가요?

heejae0811.github.io

 


버전

node v.20.8.1

nuxt v.3.8.1

vue v.3.3.8

 

1. nuxt.config.ts

head 태그 아래에 추가하고 싶은 메타태그를 작성한다. (title, meta, link가 HTML 태그로 변환된다.)

name, content, property 등 작성한 값들이 메타태그 속성으로 들어가기 때문에 다른 메타태그를 추가하고 싶다면 속성에 맞는 값들을 입력한다.

 

메타태그 이미지와 파비콘 이미지 경로는 절대 경로를 사용한다.

깃허브 페이지를 통해 빌드된 파일을 배포하고 있기 때문에 메타태그 이미지는 assets 폴더가 아닌 public 폴더에 넣는다.

export default defineNuxtConfig({
  app: {
    head: {
      title: 'ToDo List',
      meta: [
        { name: 'description', content: '오늘의 할 일은 무엇인가요?' },
        { property: 'og:title', content: '오늘의 할 일' },
        { property: 'og:description', content: '오늘의 할 일은 무엇인가요?' },
        { property: 'og:image', content: 'https://heejae0811.github.io/nuxt3-todo/meta.jpg' }
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: 'https://heejae0811.github.io/nuxt3-todo/favicon.ico' }
      ]
    },
  },
  
  ...
})

 

2. 페이지 별 메타태그 설정하기

nuxt.config.ts에 정의한 메타태그는 모든 페이지에서 공통으로 적용된다.

 

각 페이지 별로 메타태그를 다르게 설정하고 싶으면 아래 링크를 참고한다.

https://jae-study.tistory.com/129

 

[Nuxt3] #16 Nuxt 3 SEO (메타태그 설정하기)

SEO & metas with Nuxt 3 — Course part 16 https://www.youtube.com/watch?v=PpyXtoM5HWQ&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=16 유튜브 강의를 참고하고 있습니다. 공통 메타태그 설정하기 nuxt.config.ts 모든 페이지에서

jae-study.tistory.com

결과 화면

https://heejae0811.github.io/nuxt3-todo/

 

오늘의 할 일

오늘의 할 일은 무엇인가요?

heejae0811.github.io

 


버전

node v.20.8.1

nuxt v.3.8.1

vue v.3.3.8

 

1. gh-pages 설치하기

터미널에서 아래 명령어를 실행한다.

설치된 버전은 package.json 파일에서 확인할 수 있다.

npm install gh-pages

또는

yarn add gh-pages

 

2. package.json

package.json 파일의 scripts 부분에 "deploy": "~~"를 추가한다.

-f 옵션은 gh-pages 브랜치 깃 히스토리를 삭제한다. 깃 히스토리를 남기고 싶다면 해당 옵션을 제외한다.

"scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare",
    "deploy": "gh-pages --dotfiles -d .output/public -f"
},

 

3. nuxt.config.ts

nuxt.config.ts 파일의 app 부분에 baseUrl과 buildAssetsDir를 추가한다.

이때 baseUrl은 깃허브 레포지토리 이름으로 한다.

export default defineNuxtConfig({
  app: {
    baseURL: '/깃 레포지토리 이름/',
    buildAssetsDir: 'assets'
  },
  
  ...
})

 

4.  깃허브 페이지 배포하기

터미널에서 npm run generate 명령어를 실행하면 .output 폴더와 dist 폴더가 생기는 것을 볼 수 있다.

npm run deploy 명령어를 실행하면 깃허브에 배포된다.

npm run generate
npm run deploy

 

5. 깃허브 Settings

위의 과정을 수행했음에도 깃허브 페이지가 배포가 되지 않는다면 깃 레포지토리 Settings을 확인해 본다.

깃 레포지토리 - Settings - Pages에서 Branch가 gh-pages로 되어있는지 확인한다.

목표

  • Pinia 설치하기
  • Pinia store에서 데이터 불러오기
  • toDo 추가 및 삭제하기

 


결과 화면

 


버전

node v.20.8.1

nuxt v.3.8.1

vue v.3.3.8

 

1. Pinia 설치하기

https://jae-study.tistory.com/123

 

[Nuxt3] #10 Nuxt 3 State Management (일반 변수, useState, pinia 상태 관리 비교)

State management with Nuxt 3 — Course part 10 https://www.youtube.com/watch?v=IkpoAKS1s-k&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=10 유튜브 강의를 참고하고 있습니다. State Management란 상태 관리(State Management)에서 상태(Sta

jae-study.tistory.com

Pinia 및 Nuxt3 state에 대한 자세한 설명은 위의 링크를 참고한다.

 

2. json 데이터 만들기

  • server/api/toDoList.json

api가 없기 때문에 json 파일로 빈 배열을 만든다.

[]

 

3. Pinia store 만들기

  • stores/toDoStore.ts
  1. pinia를 import 한다.
  2. 만든 toDoList.json 파일을 import 한다.
  3. useToDoStore 변수를 만들고, state를 정의한다. (초기값은 toDoList.json 파일의 빈 배열)
  4. Nuxt3은 타입스크립트 기반이기 때문에 interface을 이용해 state의 타입을 정의한다. (배열 안에 객체가 있는 형태)
import { defineStore } from 'pinia'
import toDoList from '../server/api/toDoList.json'

interface ItoDo {
  id: number,
  content: string
}

export const useToDoStore = defineStore('toDo', {
  state: () => ({
    toDoList: toDoList as ItoDo[]
  }),

  actions: {}
})

 

4. actions 정의하기

4-1. toDoList 추가하기 (addToDo())

  1. 입력한 toDo(content)를 배열에 push한다. 
  2. 이때 id는 고유한 값을 나타내기 위해 현재 시간(Date.now())으로 한다.

 

4-2. toDoList 삭제하기 (deleteToDo())

  1. findIndex 메서드와 id를 이용해 삭제할 toDo의 index를 찾는다.
  2. splice 메서드를 이용해 배열에서 해당 index의 toDo를 자른다.

 

4-3. toDoList 전체 삭제하기 (clearToDo())

  1. toDoList를 빈 배열로 만든다.
  2. 전체 삭제이기 때문에 window.confirm 창을 통해 알럿 메세지를 보여준다.
...

export const useToDoStore = defineStore('toDo', {
  state: () => ({
    toDoList: toDoList as ItoDo[]
  }),

  actions: {
    addToDo(content: string) {
      this.toDoList.push({ id: Date.now(), content: content })
    },

    deleteToDo(id: number) {
      const index = this.toDoList.findIndex(list => list.id === id)

      if(index > -1) {
        this.toDoList.splice(index, 1)
      }
    },

    clearToDo() {
      if(window.confirm('리스트를 모두 삭제하시겠습니까?')) {
        this.toDoList = []
      }
    }
  }
})

 

5. 페이지에서 Pinia store 불러오기

  • pages/index.vue
  1. toDoStore를 import 한다.
  2. newToDo 변수를 만들고, v-model를 이용해 input에 입력한 내용이 양방향 바인딩 될 수 있게 한다.
  3. Pinia store에 만든 actions을 클릭 이벤트로 만들어 toDo를 추가, 삭제, 전체 삭제한다. (toDo.addToDo(), toDo.deleteToDo(), toDo.clearToDo())
<script setup lang="ts">
import { useToDoStore } from '@/stores/toDoStore'

const toDo = useToDoStore()
const newToDo = ref('')

function addToDo() {
  if(newToDo.value) {
    toDo.addToDo(newToDo.value)
    newToDo.value = ''
  }
}
</script>

<template>
  <section class="w-full max-w-screen-lg m-auto">
    <h1 class="mb-10 text-5xl font-bold text-center">ToDo List</h1>

    <form
        class="mb-5"
        @submit.prevent="addToDo()">
      <label for="toDo" class="block mb-3 text-xl font-bold">New ToDo</label>

      <div class="flex justify-between gap-5">
        <input
            v-model="newToDo"
            type="text"
            id="toDo"
            class="w-3/4 px-3 py-4 rounded text-black"
            placeholder="할 일을 입력해 주세요."/>
        <button class="w-1/4 bg-slate-500 rounded">추가하기</button>
      </div>
    </form>

    <div v-if="toDo.toDoList.length > 0">
      <div class="flex gap-2">
        <button>등록순</button>
        <i>|</i>
        <button>최신순</button>
      </div>

      <ul>
        <li
            v-for="(list, key) in toDo.toDoList"
            :key="key"
            class="flex justify-between items-center gap-5 mt-5 px-5 py-2 border rounded">
          <p class="flex gap-5 text-lg">
            <span>{{ key + 1 }}.</span> {{ list.content }}
          </p>
          <button
              @click="toDo.deleteToDo(list.id)"
              class="px-5 py-2 bg-slate-500 rounded">
            삭제
          </button>
        </li>
      </ul>

      <button
          @click="toDo.clearTodo()"
          class="block w-1/3 mt-10 m-auto px-3 py-4 bg-slate-400 rounded">
        전체 삭제하기
      </button>
    </div>
  </section>
</template>

 

toDoStore를 콘솔로 확인하면 store에 만든 state와 action 등 모든 정보를 확인할 수 있다.

목표

  • Nuxt3 설치 및 테일윈드 CSS 설치
  • 투두 리스트 마크업
  • 투두 리스트 테일윈드 css 적용

 


결과 화면

 


버전

node v.20.8.1

nuxt v.3.8.1

vue v.3.3.8

 

1. Nuxt3 설치 및 테일윈드 CSS 설치하기

https://jae-study.tistory.com/114

 

[Nuxt3] #1 Nuxt 3 설치 및 테일윈드 CSS 적용하기

Create an app with Nuxt 3 — Course part 1 https://www.youtube.com/watch?v=hj3NNlTqIJg&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=1 유튜브 강의를 참고하고 있습니다. Nuxt는 Vue.js를 사용하여 안전하고 성능이 뛰어난 풀 스

jae-study.tistory.com

Nuxt3 설치 및 테일윈드 CSS 설치에 대한 설명은 위의 링크를 참고한다.

 

 

2. 테일윈드 CSS를 이용해서 마크업 하기

  • pages/index.vue
  1. 새로운 toDo를 입력할 <form> 태그를 만들고, 입력한 toDo들이 나타날 수 있게 <ul> 태그로 목록을 만든다.
  2. 테일윈드를 사용해 CSS를 적용한다.
  3. toDoList 변수와 v-for를 이용해 toDoList를 보여준다.
<script setup lang="ts">
const toDoList = [
  {
    id: 1,
    content: '첫번째 할 일'
  },
  {
    id: 2,
    content: '두번째 할 일'
  },
  {
    id: 3,
    content: '세번째 할 일'
  }
]
</script>

<template>
  <section class="w-full max-w-screen-lg m-auto">
    <h1 class="mb-10 text-5xl font-bold text-center">ToDo List</h1>

    <form class="mb-5">
      <label for="toDo" class="block mb-3 text-xl font-bold">New ToDo</label>

      <div class="flex justify-between gap-5">
        <input
            type="text"
            id="toDo"
            class="w-3/4 px-3 py-4 rounded text-black"
            placeholder="할 일을 입력해 주세요."/>
        <button class="w-1/4 bg-slate-500 rounded">추가하기</button>
      </div>
    </form>

    <div>
      <div class="flex gap-2">
        <button>등록순</button>
        <i>|</i>
        <button>최신순</button>
      </div>

      <ul>
        <li
            v-for="(list, key) in toDoList"
            :key="key"
            class="flex justify-between items-center gap-5 mt-5 px-5 py-2 border rounded">
          <p class="flex gap-5 text-lg">
            <span>{{ key + 1 }}.</span> {{ list.content }}
          </p>
          <button class="px-5 py-2 bg-slate-500 rounded">
            삭제
          </button>
        </li>
      </ul>

      <button class="block w-1/3 mt-10 m-auto px-3 py-4 bg-slate-400 rounded">
        전체 삭제하기
      </button>
    </div>
  </section>
</template>

+ Recent posts