1. Vue๋ž€?

Vue๋Š” Facebook์˜ React, Google์˜ Angular์™€ ๋”๋ถˆ์–ด

๋Œ€ํ‘œ์ ์ธ Single Page Application(SPA) ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค.

 

๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋น„ํ•ด ํ•™์Šต ๊ณก์„ ์ด ๋‚ฎ์•„

๋ˆ„๊ตฌ๋‚˜ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ผ๊ณ  ํ•˜์ง€๋งŒ

๋ญ... ์„ธ์ƒ ๋งŒ๋ฌผ์ด ๊ทธ๋ ‡๋“ฏ์ด ์ฒ˜์Œ ์ ‘ํ•˜๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์–ด๋ ต๊ธฐ๋งˆ๋ จ ใ…Ž

 

 

 

2. ๋ฒ„์ „

Vue๋Š” Evan You๋ผ๋Š” ๊ฐœ๋ฐœ์ž์— ์˜ํ•ด 2014๋…„ ๋ฐœํ‘œ๋˜์—ˆ๊ณ , ๋ฐœํ‘œ๋œ ์ดํ›„๋กœ ํ˜„์žฌ๊นŒ์ง€ ๊พธ์ค€ํžˆ ๋ฆด๋ฆฌ์ฆˆ ๋˜๊ณ  ์žˆ๋‹ค.

Vue 2.0์€ 2016๋…„์— Ghost in the Shell์ด๋ผ๋Š” ์ฝ”๋“œ๋ช…์œผ๋กœ, 2.6์€ 2019๋…„์— Macross๋ผ๋Š” ์ฝ”๋“œ๋ช…์œผ๋กœ,

๊ทธ๋ฆฌ๊ณ  ๋“œ๋””์–ด 3.0์€ 2020๋…„ 9์›” 19์ผ์— One Piece๋ผ๋Š” ์ฝ”๋“œ๋ช…์œผ๋กœ ๊ณต๊ฐœ๋˜์—ˆ๋‹ค.

ํ˜„ ์‹œ์ ์˜ ์ตœ์‹  ๋ฒ„์ „์€ 3.2.37์ด๋‹ค.

 

 

 

3. ๊ธฐ์กด ๋ฒ„์ „์—์„œ ๋‹ฌ๋ผ์ง„ ์ 

Vue 3๋Š” ๊ธฐ์กด ๋ฒ„์ „๋ณด๋‹ค ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋˜์—ˆ๊ณ  ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ์—…๋ฐ์ดํŠธ ๋˜์—ˆ๋‹ค.

๋งŽ์€ ์—…๋ฐ์ดํŠธ๋“ค ์ค‘์— ๊ฐ€์žฅ ํ•ต์‹ฌ์ ์ธ 4๊ฐ€์ง€๋งŒ ์ •๋ฆฌํ–ˆ๋‹ค ๐ŸŽ

 

3.1. Compisition API ๊ธฐ๋ณธ ์ง€์›

์ฒซ ๋ฒˆ์งธ๋Š” Composition API๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

 

// Vue 2
export default {
  data() {
    return {
      username: '',
      password: ''
    }
  },
  methods: {
    login() {
      // login method
    }
  },
  computed: {
    lowerCaseUsername() {
      return this.username.toLowerCase()
    }
  }
}

Vue 2์—์„œ๋Š” Component์˜ ์˜ต์…˜์„ Data, Methods, Computed, Watch๋กœ ๊ตฌ๋ถ„ํ–ˆ๋‹ค.

๊ฐ ํŠน์ง•์— ๋”ฐ๋ผ ๊ตฌ๋ถ„๋˜์–ด ์žˆ์–ด ํ”„๋กœ์ ํŠธ ์ดˆ๋ฐ˜์—๋Š” ๋” ์ง๊ด€์ ์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ์ง€๋งŒ

ํ”„๋กœ์ ํŠธ ํฌ๊ธฐ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก, ์ฝ”๋“œ๋Ÿ‰์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๋‹จ์ ์ด ์žˆ์—ˆ๋‹ค.

 

// Vue 3
import { reactive } from 'vue';
export default {
  setup() {
    const state = reactive({
      username: '',
      password: '',
      lowerCaseUsername: computed(() => state.username.toLowerCase()),
    })
    const login = () => {
      // login method
    }
    return {
      login,
      state,
    }
  }
}

Composition API๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ•˜์˜€๋‹ค.

Data, Methods, Computed ๋“ฑ์ด ๊ฐ์ž ๋ถ„์‚ฐ๋˜์–ด ๋‹ด๋‹นํ–ˆ๋˜ ๊ธฐ๋Šฅ๋“ค์„ Setup ๋ฉ”์„œ๋“œ์— ํ•˜๋‚˜๋กœ ๋ชจ์œผ๋Š” ๊ฒƒ์ด๋‹ค.

๋งŽ์€ ์–‘์˜ ์ฝ”๋“œ๋“ค์„ ์„œ๋กœ์˜ ๊ด€๋ จ์„ฑ ๋”ฐ๋ผ ๊ฐœ๋ฐœ์ž ์Šค์Šค๋กœ ๋ฐฐ์น˜ํ•˜์—ฌ, ์ฝ”๋“œ๋ฅผ ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

Vue 2์—์„œ๋„ Composition ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ ์šฉํ•ด์„œ ๋˜‘๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•  ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ

Vue 3์—์„œ๋Š” Composition API๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ ์ด ํฐ ์ฐจ์ด์ ์ด๋‹ค.

 

 

3.2. Lifecycle ๋ณ€ํ™”

๋‘ ๋ฒˆ์งธ๋Š” Lifecycle์˜ ๋ณ€ํ™”์ด๋‹ค.

 

// Vue 2
export default {
  created() {
    console.log('created')
  },
  mounted() {
    console.log('mounted')
  },
}

Vue 2์—์„œ๋Š” Created, Mounted, Updated ๋“ฑ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด ๋ฉ”์„œ๋“œ๋“ค์ด Composition API์˜ Setup ๋ฉ”์„œ๋“œ ์•ˆ์œผ๋กœ ๋“ค์–ด๊ฐ€๋ฉด์„œ ๋ช…์นญ ๋“ฑ์ด ๋ฐ”๋€Œ์—ˆ๋‹ค.

 

// Vue 3
import { onMounted } from 'vue';
export default {
  setup() {
    // ..
    onMounted(() => {
      console.log('onMounted')
    })
    // ...
  }
}

Created๋Š” Setup ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ์‹คํ–‰ํ•˜๋„๋ก ๋ฐ”๋€Œ์—ˆ๊ณ ,

Mounted๋Š” onMounted๋กœ, Updated๋Š” onUpdated๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค.

์œ„์น˜์™€ ์ด๋ฆ„์ด ์กฐ๊ธˆ ๋ฐ”๋€Œ์—ˆ์„ ๋ฟ ๊ธฐ๋Šฅ์€ ํฐ ์ฐจ์ด ์—†๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

 

์ด ์™ธ์—๋„ BeforeUnmount, Unmounted๋“ฑ์˜ ๋‚ด์šฉ์ด ๋ฐ”๋€Œ์—ˆ๋Š”๋ฐ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ฒ€์ƒ‰!

 

 

3.3. ๋ฉ€ํ‹ฐ ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ

์„ธ ๋ฒˆ์งธ๋Š” ํ…œํ”Œ๋ฆฟ์„ ์ƒ์„ฑํ•  ๋•Œ ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค.

 

Vue 2์—์„œ๋Š” ํ…œํ”Œ๋ฆฟ ์•ˆ์— ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํ•˜๋‚˜๋งŒ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ Vue 3๋ถ€ํ„ฐ๋Š” ํ…œํ”Œ๋ฆฟ ์•ˆ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

<template>
  <h1>Title</h1> <!-- Vue 2์—์„œ๋Š” h1๊ณผ div ๋‘๊ฐœ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ -->
  <div>Content</div> <!-- Vue 3์—์„œ๋Š” ๊ฐ€๋Šฅ -->
</template>

 

 

3.4. IE ์ง€์› ์ค‘๋‹จ

๋งˆ์ง€๋ง‰์œผ๋กœ ๋” ์ด์ƒ Internet Explorer(IE)๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค.

๊ผญ ์ง€์›ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด ์ด์ „ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

 

 

 

1. Delete Todo ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

๋จผ์ € ๋ฐ์ดํ„ฐ๋ฅผ store์—์„œ ๊ด€๋ฆฌ ์ค‘์ด๋‹ˆ๊นŒ actions์™€ mutations๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

 

// src/store/index.js
mutations: {
    mutationsAddTodo(state, todo) {
      state.todos.push(todo);
      console.log(todo);
    },
    mutationsDelTodo(state, id) {
      state.todos = state.todos.filter((todo) => todo.id != id);
    }
  },
  actions: {
    actionsAddTodo({commit}, todo) {
      commit('mutationsAddTodo', todo);
    },
    actionsDelTodo({commit}, id) {
      commit('mutationsDelTodo', id);
    }
  },

actions์— actionsDelTodo ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๊ณ , todo์˜ id๋ฅผ ๋ฐ›๋Š”๋‹ค.

mutations์— mutationsDelTodo์—์„œ๋Š” ํ•ด๋‹น id๊ฐ€ ์•„๋‹Œ ๊ฒƒ๋งŒ ๊ฐ€์ ธ์˜ค๋Š” ํ•„ํ„ฐ ํ•จ์ˆ˜๋ฅผ ์ง ๋‹ค.

 

 

// src/components/TodoItem.vue
export default {
    props: {
        todo: {}
    },
    methods: {
        ...mapActions(['actionsDelTodo'])
    },
}

TodoItem์— mapActions๋ฅผ ์ž‘์„ฑํ•˜์—ฌ store actions์™€ ์—ฐ๊ฒฐํ•ด์ฃผ๊ณ 

 

 

<!-- src/components/TodoItem.vue -->
<v-btn @click="actionsDelTodo(todo.id)" block color="error">Delete</v-btn>

์ž‘์„ฑํ•ด๋‘” Delete ๋ฒ„ํŠผ์— ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  todo์˜ id๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ์ž˜ ์ž‘๋™ํ•œ๋‹ค !

 

 

 

 

2. Edit Todo ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

์ด์ œ Add์™€ Delete๊นŒ์ง€ ๊ฐ€๋Šฅํ•˜๋‹ˆ Edit ๊ธฐ๋Šฅ๋งŒ ๋„ฃ์œผ๋ฉด

๊ธฐ๋ณธ์ ์ธ TodoList App ์ž‘์„ฑ์€ ๋์ด ๋‚œ๋‹ค !

 

 

// src/components/TodoItem.vue
<script>
import { mapActions } from 'vuex';

export default {
    props: {
        todo: {}
    },
    data() {
        return {
            editing: null
        }
    },
    methods: {
        ...mapActions(['actionsDelTodo'])
    },
}
</script>

TodoItem์— editing์ด๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ํ•˜๋‚˜ ์„ ์–ธํ•ด๋‘”๋‹ค.

์ €๊ฑธ๋กœ EDIT๋ผ๋Š” ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ํŽธ์ง‘ ๋ฐ•์Šค๋ฅผ ์ผœ๊ณ  ๋„๋Š” ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ๊ฑฐ๋‹ค.

 

 

<!-- src/components/TodoItem.vue -->
<template>
    <v-container fluid>
        <v-row class="mb-3" justify="center" align="center">
            <v-col cols="4">
                <h3 v-if="!editing">{{ todo.title }}</h3>
                <v-text-field
                    label="Edit"
                    outlined
                    dense
                    hide-details
                    v-else
                ></v-text-field>
            </v-col>
            <v-col cols="1">
                <v-btn @click="editing = !editing" block large color="primary">
                    {{ editing ? 'Save' : 'Edit' }}
                </v-btn>
            </v-col>
            <v-col cols="1">
                <v-btn @click="actionsDelTodo(todo.id)" block large color="error">Delete</v-btn>
            </v-col>
        </v-row>
    </v-container>
</template>

๊ทธ๋ฆฌ๊ณ  v-if์™€ v-else๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ todo.title์„ ๋ณด์—ฌ์ค„ ๊ฑด์ง€,

ํŽธ์ง‘ ํ…์ŠคํŠธ ํ•„๋“œ๋ฅผ ๋ณด์—ฌ์ค„ ๊ฑด์ง€ ์ž‘์„ฑํ•œ๋‹ค.

๐Ÿšจ outlined, dense, hide-details๋Š” v-text-field์˜ style ์†์„ฑ

 

v-btn์— text๋„ editing์ด true์ผ ๋•Œ๋Š” Save, false์ผ ๋•Œ๋Š” Edit๊ฐ€ ๋œจ๊ฒŒ ์ž‘์„ฑํ•˜๊ณ 

ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋‹ฌ์•„์„œ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค true, false๊ฐ€ ๋ฐ”๋€Œ๊ฒŒ ์ž‘์„ฑํ•œ๋‹ค.

๐Ÿšจ ์‚ผํ•ญ์—ฐ์‚ฐ์ž → ์กฐ๊ฑด ? true : false

 

 

state์— ์ €์žฅํ•ด๋†“๊ณ  ์‚ญ์ œ, ์ˆ˜์ •์„ ํ•˜๋ ค๋ฉด ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’์„ ๋ฐ›์•„์•ผ ํ•˜๋Š”๋ฐ

// src/components/TodoItem.vue
data() {
    return {
        todoText: '',
        editing: null
    }
},

script ์•ˆ์— data์— todoText๋ฅผ ์„ ์–ธํ•ด๋‘”๋‹ค.

 

 

<!-- src/components/TodoItem.vue -->
<v-text-field
    v-else
    v-model="todoText"
    label="Edit"
    outlined
    dense
    hide-details
></v-text-field>

์œ„์—์„œ ์„ ์–ธํ•œ todoText๋ฅผ ๊ฐ™์€ ํŒŒ์ผ ๋‚ด์˜ text field์— v-model๋กœ ์—ฐ๊ฒฐ์‹œ์ผœ๋‘”๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์ž…๋ ฅ๊ฐ’์ด v-model๋กœ ์—ฐ๊ฒฐํ•ด๋‘” todoText๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.

 

 

<!-- src/components/TodoItem.vue -->
<v-col cols="1">
    <v-btn @click="modTodo(todo)" block large color="primary">
        {{ editing ? 'Save' : 'Edit' }}
    </v-btn>
</v-col>

์•„๊นŒ ๋งŒ๋“ค์—ˆ๋˜ Save / Edit button์— ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ modTodo๋ผ๋Š” ํ•จ์ˆ˜์— todo๋ฅผ ๋„ฃ์€ ๊ฑธ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

 

 

// src/components/TodoItem.vue
methods: {
    ...mapActions(['actionsDelTodo', 'actionsModTodo']),
    modTodo(todo) {
        this.editing = !this.editing;
        if(this.editing) this.actionsModTodo(todo);
        else todo.title = this.todoText;
    }
},

๊ฐ™์€ ํŒŒ์ผ์— mapActions์— actionsModTodo๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ ,

modTodo์—๋Š” editing์„ true, false๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ตฌ๋ฌธ๊ณผ

if(this.editing)์œผ๋กœ ๊ฐ’์„ ํ™•์ธํ•˜๊ณ  actions๋กœ ๋„˜์–ด๊ฐˆ ๊ฑด์ง€,

todo.title์„ todoText๋กœ๋งŒ ๋ฐ”๊ฟ”์ค„ ๊ฑด์ง€ ๋น„๊ต ์ž‘์„ฑํ•œ๋‹ค.

 

 

// src/store/index.js
mutations: {
  mutationsAddTodo(state, todo) {
    state.todos.push(todo);
    console.log(todo);
  },
  mutationsDelTodo(state, id) {
    state.todos = state.todos.filter((todo) => todo.id != id);
  },
  mutationsModTodo(state, todo) {
    let idx = state.todos.findIndex(x=>x.id == todo.id);
    if(idx > -1) {
      state.todos[idx] = todo;
    }
  }
},
actions: {
  actionsAddTodo({commit}, todo) {
    commit('mutationsAddTodo', todo);
  },
  actionsDelTodo({commit}, id) {
    commit('mutationsDelTodo', id);
  },
  actionsModTodo({commit}, todo) {
    commit('mutationsModTodo', todo);
  }
},

store ๋‚ด์˜ actions์™€ mutations์— Mod๊ด€๋ จ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

mutationsModTodo์—์„œ๋Š” ๋ฐ›์€ todo์˜ ์•„์ด๋””์™€ ๊ฐ™์€ ๊ฐ’์„ state์—์„œ ์ฐพ๊ณ ,

๊ทธ Index์— ํ•ด๋‹นํ•˜๋Š” todo๋ฅผ ๋ฐ›์€ todo๋กœ ๊ต์ฒดํ•ด์ฃผ๋ฉด ์ˆ˜์ • ์™„๋ฃŒ !

 

 

3. ๊ฒฐ๊ณผ

 

 

๋‹ค์Œ์€ ๋ญ˜ ๋งŒ๋“ค์–ด๋ณผ๊นŒ ๐Ÿค”

์ด์ „๊ธ€๋ณด๊ธฐ


1. Vuex ์ถ”๊ฐ€ํ•˜๊ธฐ

vue add vuex

์„œ๋ฒ„๊ฐ€ ์ผœ์ ธ์žˆ๋‹ค๋ฉด ์„œ๋ฒ„๋ฅผ ์ข…๋ฃŒ์‹œํ‚ค๊ณ (VSCode ๋‹จ์ถ•ํ‚ค : Ctrl + c)

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— vuex๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

 

์„ฑ๊ณต์ ์œผ๋กœ ์ถ”๊ฐ€๋˜๊ณ ๋‚˜๋ฉด src ํด๋” ์•„๋ž˜์— store ํด๋”๊ฐ€ ์ƒˆ๋กœ ์ƒ๊ฒจ์žˆ๋‹ค.

์ด์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์ƒํƒœ๊ด€๋ฆฌ๋Š” ์ด store๋กœ ํ•˜๋ฉด ๋œ๋‹ค!

๐Ÿค” vuex๋„ ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด์•ผ๊ฒ ๋‹ค ๐Ÿค”

 

 

2. Vuex ํ™œ์šฉํ•˜๊ธฐ

src/store/index.js์˜ ๊ธฐ๋ณธ ํ˜•ํƒœ๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

 

ํšŒ์‚ฌ์—์„œ๋Š” ๊ด€๋ฆฌํ•ด์•ผ ํ•  ์ข…๋ฅ˜๊ฐ€ ๋งŽ์•„์„œ ๋”ฐ๋กœ ๋ชจ๋“ˆ๋กœ ๋นผ์„œ

index.js๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰์ค‘์ด์ง€๋งŒ,

์ง€๊ธˆ์€ ๊ด€๋ฆฌ ํ•  ๋ฐ์ดํ„ฐ ์ข…๋ฅ˜๊ฐ€ ๋งŽ์ง€์•Š์œผ๋‹ˆ ํ•œ๊ณณ์—์„œ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.

 

 

// index.js state
state: {
    todos: [
      {
        id: 1,
        title: 'One'
      },
      {
        id: 2,
        title: 'Two'
      },
      {
        id: 3,
        title: 'Three'
      }
    ]
  }

state์— ๋ฏธ๋ฆฌ ๋‹ด๊ฒจ์žˆ์„ 3๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ž‘์„ฑํ•˜๊ณ ,

 

 

// index.js getters, mutations, actions
getters: {
  allTodos: (state) => state.todos,
},
mutations: {
  mutationsAddTodo(state, todo) {
    state.todos.push(todo);
    console.log(state.todos);
  }
},
actions: {
  actionsAddTodo({commit}, todo) {
    commit('mutationsAddTodo', todo);
  }
}

getters์—๋Š” state์— ์ €์žฅ๋œ ๋ชจ๋“  todos๋ฅผ ๊ฐ€์ ธ์˜ฌ allTodos๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

mutations์—๋Š” actions์—์„œ ๋„˜์–ด์˜จ ๋ฐ์ดํ„ฐ๋ฅผ state์— pushํ•  mutationsAddTodo๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

actions์—๋Š” vue ์†Œ์Šค์—์„œ ์ด๊ฑฐ ์ €์žฅ์‹œ์ผœ!ํ•˜๊ณ  ํ˜ธ์ถœ๋  actionsAddTodo๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

commit('mutationsAddTodo', todo)๋ฅผ ์‹คํ–‰ํ•˜๋ฉด mutations์— ํ•ด๋‹น ์ด๋ฆ„์˜ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค.

- mutations์—๋Š” ์ˆœ์ฐจ์ ์ธ ๋กœ์ง์„ ์ž‘์„ฑํ•˜๊ณ ,

  actions์—๋Š” ๋น„์ˆœ์ฐจ์  ๋˜๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ์ž‘์„ฑํ•œ๋‹ค.

  ์ด ๋ถ€๋ถ„๋„ vuex ์ •๋ฆฌํ•˜๋ฉด์„œ ๋‹ค๋ฃฐ ์˜ˆ์ •!

 

ํ•จ์ˆ˜ ์•ž์— mutations์™€ actions๋Š” ์•Œ์•„๋ณด๊ธฐ ์‰ฝ๊ฒŒ ๋ถ™์—ฌ๋†“์€๊ฒƒ์ด๋ฏ€๋กœ ์ƒ๋žตํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

 

 

<!-- src/components/TodoInput.vue -->
<template>
    <v-container fluid>
        <v-row class="mt-6" justify="center">
            <v-col cols="4">
                <v-text-field outlined></v-text-field>
            </v-col>
            <v-col cols="1">
                <v-btn @click="actionsAddTodo('12345')" block x-large color="primary">Add</v-btn>
            </v-col>
        </v-row>
    </v-container>
</template>

<script>
import { mapActions } from 'vuex';

export default {
    methods: {
        ...mapActions(['actionsAddTodo'])
    },
}
</script>

TodoInput์— vuex์˜ actions๋ฅผ import ์‹œํ‚ค๋ฉด ...mapActions๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

import ์‹œํ‚ค์ง€ ์•Š๋”๋ผ๋„ this.$store.dispatch('actionsAddTodo')๋กœ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•˜๋‹ค.

vue → store actions ํ˜ธ์ถœ : dispatch
actions → mutations ํ˜ธ์ถœ : commit

 

 

Add ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด actionsAddTodo๋ฅผ '12345'๋ผ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰์‹œํ‚จ๋‹ค.

mutatilnsAddTodo์—์„œ state todos์— push ์‹œํ‚ค๊ณ  state์˜ todos๋ฅผ ์ฝ˜์†”๋กœ ์ฐ์–ด๋ณด๋ฉด

๊ฐ™์ด ๋„˜๊ฒจ์คฌ๋˜ 12345๊ฐ€ ๋‹ด๊ฒจ์žˆ๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ทธ๋ ‡๋‹ค๋ฉด ์ด์ œ ์‹ค์ œ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ text-field์—์„œ ์ ์€ ๊ฐ’์„ ๋„˜๊ฒจ๋ด…์‹œ๋‹ค ๐Ÿ˜˜

<!-- src/components/TodoInput.vue -->
<script>
import { mapActions } from 'vuex';

export default {
    data() {
        return {
            todoText: ''
        }
    },
    methods: {
        ...mapActions(['actionsAddTodo'])
    },
}
</script>

๋จผ์ € TodoInput script์— ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’์„ ๋ฐ›์„ ๋นˆ todoText๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

 

 

<!-- src/components/TodoInput.vue -->
<template>
    <v-container fluid>
        <v-row class="mt-6" justify="center">
            <v-col cols="4">
                <v-text-field v-model="todoText" outlined></v-text-field>
            </v-col>
            <v-col cols="1">
                <v-btn @click="actionsAddTodo(todoText)" block x-large color="primary">Add</v-btn>
            </v-col>
        </v-row>
    </v-container>
</template>

๊ทธ๋ฆฌ๊ณ  ํ…์ŠคํŠธ ํ•„๋“œ ํƒœ๊ทธ์— v-model์— todoText๋ฅผ ๋„ฃ์–ด์ค€๋‹ค!

๊ทธ๋Ÿฌ๋ฉด ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ todoText๋ฅผ ๋ฐ”๋ผ๋ณด๊ฒŒ ๋˜๊ณ ,

๊ทธ ๊ฐ’์„ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ  actionsAddTodo๊ฐ€ ์‹คํ–‰๋ ๋•Œ ๊ฐ™์ด ๋„˜๊ฒจ์ค€๋‹ค.

 

๋ฐ์ดํ„ฐ ์ž…๋ ฅ ํ›„ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ  ์ฝ˜์†”์— ์ฐํžŒ ๊ฐ’์„ ํ™•์ธํ•ด๋ณด๋ฉด ์ž˜ ๋„˜์–ด์˜จ๋‹ค!

 

 

3. UUID๋กœ ID ๋ถ€์—ฌํ•˜๊ธฐ

npm i --save uuid

์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•˜๋Š” todoText๋Š” store์—์„œ title๋กœ ๊ด€๋ฆฌ๋  ๊ฒƒ์ด๊ณ ,

ID์—๋Š” ๊ณ ์œ ํ•œ key๊ฐ’์„ ๋„ฃ๊ธฐ ์œ„ํ•ด์„œ UUID๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

 

 

<!-- src/components/TodoInput.vue -->
<template>
    <v-container fluid>
        <v-row class="mt-6" justify="center">
            <v-col cols="4">
                <v-text-field v-model="todoText" outlined></v-text-field>
            </v-col>
            <v-col cols="1">
                <v-btn @click="addTodo" block x-large color="primary">Add</v-btn>
            </v-col>
        </v-row>
    </v-container>
</template>

<script>
import { mapActions } from 'vuex';
import { v1 } from 'uuid';

export default {
    data() {
        return {
            todoText: ''
        }
    },
    methods: {
        ...mapActions(['actionsAddTodo']),
        addTodo() {
            this.actionsAddTodo({
                id: v1(),
                title: this.todoText
            });
        }
    },
}
</script>

uuid๋ฅผ import ์‹œ์ผœ์ฃผ๊ณ , addTodo()๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ,

actionsAddTodo๋ฅผ ์‹คํ–‰ํ• ๋•Œ id์™€ title์„ ๋„ฃ์–ด์„œ ๋ณด๋‚ด์ฃผ๊ฒŒ ์ž‘์„ฑํ•œ๋‹ค.

 

๋ฒ„ํŠผ ํด๋ฆญ์‹œ์—๋„ addTodo๊ฐ€ ์‹คํ–‰๋˜๊ฒŒ ์ˆ˜์ •ํ•ด์ค€๋‹ค.

 

 

test1์ด๋ผ๋Š” ๊ฐ™์€ ๊ฐ’์„ ๋‘๋ฒˆ ๋„˜๊ฒจ์คฌ์ง€๋งŒ id๋Š” ๊ณ ์œ ํ•˜๊ฒŒ ๋ถ€์—ฌ๋˜๊ธฐ ๋•Œ๋ฌธ์—

๋งค๋ฒˆ ๋‹ค๋ฅธ id๊ฐ€ ๋„˜์–ด๊ฐ€๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

4. Text Field ์ดˆ๊ธฐํ™” ๋ฐ TodoList, TodoItem ์ˆ˜์ •

๊ธฐ์กด์—๋Š” Add ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋„˜์–ด๊ฐ€์ง€๋งŒ ํ…์ŠคํŠธ ํ•„๋“œ์— ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๋Š” ์ƒํƒœ์˜€๋‹ค.

ํ•˜์ง€๋งŒ Add ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด store์— ์ €์žฅ์ด ๋˜๊ธฐ๋•Œ๋ฌธ์—, ํ…์ŠคํŠธ ํ•„๋“œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™” ์‹œ์ผœ์ค„ ๊ฑฐ๋‹ค!

 

 

<!-- src/components/TodoInput.vue -->
<v-text-field @change="todoTextChg" :value="todoText" outlined></v-text-field>

๋จผ์ € TodoInput.vue์— ์žˆ๋Š” ํ…์ŠคํŠธ ํ•„๋“œ ์†์„ฑ์„ ์ข€ ๋ฐ”๊ฟ”์ค€๋‹ค.

@change="todoTextChg" ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์„œ ํ…์ŠคํŠธ ํ•„๋“œ์˜ ๊ฐ’์ด ๋ฐ”๋€”๋•Œ๋งˆ๋‹ค todoTextChg๋ฅผ ์‹คํ–‰์‹œํ‚ค๋„๋ก ํ•œ๋‹ค.

 

 

// src/components/TodoInput.vue
methods: {
    ...mapActions(['actionsAddTodo']),
    todoTextChg(e) {
        this.todoText = e;
    },
    addTodo() {
        this.actionsAddTodo({
            id: v1(),
            title: this.todoText
        });
        this.todoText = '';
    }
},

methods์— todoTextChg ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ  todoText ๊ฐ’์„ e๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  addTodo๊ฐ€ ์‹คํ–‰๋ ๋•Œ actionsAddTodo๊ฐ€ ์‹คํ–‰๋˜๊ณ ๋‚˜์„œ todoText๊ฐ’์„ ๋นˆ๊ฐ’์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด

 

 

abcd๋ผ๋Š” ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ณ  Add ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด

์ฝ˜์†”์— ์ฐํžŒ ๋ฐ์ดํ„ฐ์— abcd๊ฐ€ ์ฐํ˜€์žˆ๊ณ 

ํ…์ŠคํŠธ ํ•„๋“œ๋Š” ๊ฐ’์ด ์ดˆ๊ธฐํ™”๊ฐ€ ๋œ๋‹ค.

 

 

์ด์ œ ๊ธฐ์กด์— TodoList.vue์—์„œ ํ•˜๋“œ์ฝ”๋”ฉ์œผ๋กœ ๋„ฃ์–ด๋†จ๋˜ ๋ฐ์ดํ„ฐ๋ฅผ

store getters allTodos๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์™€์„œ ๋„ฃ์–ด์ค„๊ฑฐ๋‹ค.

<!-- src/components/TodoList.vue ๋ณ€๊ฒฝ ์ „ -->
<template>
    <v-container>
        <TodoItem/>
        <TodoItem/>
        <TodoItem/>
    </v-container>
</template>

<script>
import TodoItem from '@/components/TodoItem';

export default {
    components: {
        TodoItem
    }
}
</script>
<!-- src/components/TodoList.vue ๋ณ€๊ฒฝ ํ›„ -->
<template>
    <v-container>
        <v-row v-for="todo in allTodos"
               :key="todo.id"
        >
            <TodoItem :todo='todo'/>
        </v-row>
    </v-container>
</template>

<script>
import TodoItem from '@/components/TodoItem';
import { mapGetters } from 'vuex';

export default {
    components: {
        TodoItem
    },
    computed: {
        ...mapGetters(['allTodos'])
    },
}
</script>

v-container ์•ˆ์— v-row๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ , mapGetters๋กœ ๋ถˆ๋Ÿฌ์˜จ allTodos์˜ ์ˆ˜๋งŒํผ for๋ฌธ์„ ๋Œ๋ฆฐ๋‹ค.

allTodos์˜ ์ˆ˜๋งŒํผ TodoItem์ด ๋‚˜์˜ฌ๊ฑฐ๊ณ , ์ž์‹ ์ปดํฌ๋„ŒํŠธ์ธ TodoItem์— todo๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.

 

 

<!-- src/components/TodoItem.vue -->
<template>
    <v-container fluid>
        <v-row class="mb-3" justify="center" align="center">
            <v-col cols="4">
                {{ todo.title }}
            </v-col>
            <v-col cols="1">
                <v-btn block color="primary">Edit</v-btn>
            </v-col>
            <v-col cols="1">
                <v-btn block color="error">Delete</v-btn>
            </v-col>
        </v-row>
    </v-container>
</template>

<script>
export default {
    props: {
        todo: {}
    }
}
</script>

TodoItem์— props๋ฅผ ๋งŒ๋“ค์–ด์ค˜์„œ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ›์€ ๊ฐ’์ธ todo๋ฅผ ์„ ์–ธํ•ด๋‘”๋‹ค.

{{ todo.title }}์„ ์ ์–ด๋‘๋ฉด ๋ถ€๋ชจ์—๊ฒŒ ๋ฐ›์€ todo์˜ title์„ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

 

5. ๊ฒฐ๊ณผ ๐Ÿคฃ

store index.js์— ์ฒ˜์Œ ์ ์–ด๋‘” One Two Three๊ฐ€ ๋จผ์ € ๋‚˜์˜ค๊ณ ,

์ž…๋ ฅํ•œ Four Five๋„ ์ž˜ Add ๋œ๋‹ค.

 

 

์‚ญ์ œ ๊ธฐ๋Šฅ์€ ๋‹ค์Œ ๊ธ€์—์„œ ๐Ÿ˜Š

1. Vue.js Project ์ƒ์„ฑ

vue create todoapp

๋ฏธ๋ฆฌ Git Clone ์‹œ์ผœ๋†“๊ณ  ๊ทธ ํด๋” ์•ˆ์— Vue.js ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

(Git Clone : GitHub Code ๋ณต์‚ฌ → VSCode์—์„œ Ctrl + Shift + P → Git: Clone → GitHub Code ๋ถ™์—ฌ ๋„ฃ๊ธฐ)

 

 

cd todoapp
npm run serve

ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ๋ณด๊ณ  ์‹คํ–‰์ด ์ž˜ ๋œ๋‹ค๋ฉด

Defalut ํŒŒ์ผ src/component/HelloWorld.vue ํŒŒ์ผ์„ ์‚ญ์ œํ•œ๋‹ค.

src/App.vue์— HelloWorld.vue ๊ด€๋ จ ๋‚ด์šฉ์„ ๋‹ค ์ง€์šด๋‹ค. (์•„๋ž˜ ์ฃผ์„ ๋ถ€๋ถ„)

<!-- src/App.vue -->
<template>
  <div id="app">
    <!-- <img alt="Vue logo" src="./assets/logo.png"> -->
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    // HelloWorld
  }
}
</script>

 

 

2. Components ์ƒ์„ฑ ๋ฐ import (TodoInput, TodoList, TodoItem)

src/components ์•„๋ž˜์— 3๊ฐœ์˜ vue ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ๊ณ ,

์ผ๋‹จ ํŒŒ์ผ ๋‚ด์šฉ์€ <h3> ํƒœ๊ทธ๋กœ ํŒŒ์ผ๋ช…๋งŒ ์ž‘์„ฑ์„ ํ•ด๋‘”๋‹ค.

 

 

<!-- src/App.vue -->
<template>
  <div id="app">
    <TodoInput/>
    <TodoList/>
  </div>
</template>

<script>
import TodoInput from '@/components/TodoInput';
import TodoList from '@/components/TodoList';

export default {
  name: 'App',
  components: {
    TodoInput,
    TodoList
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

TodoInput๊ณผ TodoList ํŒŒ์ผ์€ App.vue์— import ์‹œ์ผœ์ฃผ๊ณ ,

 

 

<!-- src/components/TodoList.vue -->
<template>
    <div>
        <h3>Todo List</h3>
        <TodoItem/>
        <TodoItem/>
        <TodoItem/>
    </div>
</template>

<script>
import TodoItem from '@/components/TodoItem';

export default {
    components: {
        TodoItem
    }
}
</script>

<style>

</style>

TodoItem์€ TodoList์— import ์‹œ์ผœ์ค€๋‹ค.

์ผ๋‹จ ์˜ˆ์‹œ๋กœ TodoItem์„ 3๊ฐœ ํ‘œ์‹œํ•ด์ค˜ ๋ดค๋‹ค.

 

์ €๋ ‡๊ฒŒ import ์‹œํ‚ค๊ณ  ์‹คํ–‰์„ ํ•˜๋ฉด ์ด๋Ÿฐ ํ™”๋ฉด์ด ์ถœ๋ ฅ๋  ๊ฑฐ๋‹ค.

 

 

3.  Vuetify ์ถ”๊ฐ€ ํ›„ UI ์ˆ˜์ •

์ด์ œ ๊ฐ์ž ํŒŒ์ผ๋ช…์ด ์•„๋‹Œ ์—ญํ• ์„ ์ฃผ๊ธฐ๋กœ ๐Ÿ˜‰

 

 

๋จผ์ € TodoInput.vue ํŒŒ์ผ์— <input>๊ณผ <button>์„ ์ƒ์„ฑํ•œ๋‹ค.

<!-- src/components/TodoInput.vue -->
<template>
    <div>
        <input type="text"/>
        <button>Add</button>
    </div>
</template>
<!-- script, style ๊ทธ๋Œ€๋กœ -->

 

 

TodoList.vue์—๋Š” <h3> ์ œ๋ชฉ ํƒœ๊ทธ๋ฅผ ์ง€์›Œ์ฃผ๊ณ  <TodoItem>๋งŒ ๋‹ด๋Š”๋‹ค.

<!-- src/components/TodoList.vue -->
<template>
    <div>
        <TodoItem/>
        <TodoItem/>
        <TodoItem/>
    </div>
</template>
<!-- script, style ๊ทธ๋Œ€๋กœ -->

 

 

TodoItem.vue์—๋Š” <button> ๋‘ ๊ฐœ์™€ ๊ธฐํƒ€ ๋“ฑ๋“ฑ ์ƒ์„ฑ ๐Ÿ˜‹

<!-- src/components/TodoItem.vue -->
<template>
    <div>
        <h5>#1</h5>
        <h3>Todo Title</h3>
        <button>Edit</button>
        <button>Delete</button>
    </div>
</template>
<!-- script, style ๊ทธ๋Œ€๋กœ -->

 

 

์ด๋ ‡๊ฒŒ ๋‚˜์˜ค๋ฉด ๋œ๋‹ค.

๊ทผ๋ฐ UI๊ฐ€ ๋งˆ์Œ์— ์•ˆ๋“ค์–ด์„œ ์ด์ œ์•ผ Vuetify ์ถ”๊ฐ€... ^^

 

 

Vuetify ์ถ”๊ฐ€ํ•˜๋ฉด์„œ App.vue๊ฐ€ ์•„์˜ˆ ๋ฐ”๋€Œ์–ด๋ฒ„๋ ค์„œ

App.vue์— import ํ–ˆ๋˜ ๊ฑฐ ๋‹ค ์‚ฌ๋ผ์ง!

(vuetify ์ถ”๊ฐ€ํ•  ๊ฑฐ๋ฉด ๋ฏธ๋ฆฌ ํ•˜๊ธฐ ๐Ÿ™„)

 

 

ํŒŒ์ผ๋“ค์„ Vuetify Tag๋กœ ๋ฐ”๊พธ๊ณ  ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์ˆ˜์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค ,,, ^^

<!-- src/App.vue -->
<v-main>
  <TodoInput/>
  <TodoList/>
</v-main>
.
.
.
<script>
import TodoInput from '@/components/TodoInput';
import TodoList from '@/components/TodoList';

export default {
  name: 'App',

  components: {
    TodoInput,
    TodoList
  },

  data: () => ({
    //
  }),
};
</script>
<!-- src/components/TodoInput.vue -->
<template>
    <v-container fluid>
        <v-row class="mt-6" justify="center">
            <v-col cols="4">
                <v-text-field outlined></v-text-field>
            </v-col>
            <v-col cols="1">
                <v-btn block x-large color="primary">Add</v-btn>
            </v-col>
        </v-row>
    </v-container>
</template>

<script>
export default {

}
</script>

<style>

</style>
<!-- src/components/TodoList.vue -->
<template>
    <v-container>
        <TodoItem/>
        <TodoItem/>
        <TodoItem/>
    </v-container>
</template>

<script>
import TodoItem from '@/components/TodoItem';

export default {
    components: {
        TodoItem
    }
}
</script>

<style>

</style>
<!-- src/components/TodoItem.vue -->
<template>
    <v-container fluid>
        <v-row class="mb-3 text-center" justify="center">
            <v-col cols="1">
                #1
            </v-col>
            <v-col cols="2">
                Todo Title
            </v-col>
            <v-col cols="1">
                <v-btn block color="primary">Edit</v-btn>
            </v-col>
            <v-col cols="1">
                <v-btn block color="error">Delete</v-btn>
            </v-col>
        </v-row>
    </v-container>
</template>

<script>
export default {

}
</script>

<style>

</style>

 

 

์ €์žฅ ํ›„ ์‹คํ–‰ํ•˜๋ฉด Vuetify Tag๊ฐ€ ์ ์šฉ๋œ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋ฅธ UI ์ž‘์—…์€ ํ•˜์ง€ ์•Š๊ณ , ์˜ˆ์ œ๋ผ ๊ฐ„๋‹จํ•œ Vuetify ์†์„ฑ๋งŒ ์‚ฌ์šฉํ–ˆ๋‹ค.

 

 

๋‹ค์Œ ๊ธ€์€ Vuex ์—ฐ๊ฒฐํ•ด์„œ store ๊ด€๋ฆฌ๊นŒ์ง€ ๐Ÿ˜Š

1. Vue ์„ค์น˜

npm install -g @vue/cli

์œ„ ๋ช…๋ น์–ด๋กœ vue ์„ค์น˜๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์—์„œ Vuetify ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ!

 

 

2. Vuetify ์ถ”๊ฐ€

npm install vuetify

node_modules ๋ฐ‘์— vuetify๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

์ด์ œ vue์— ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

 

 

3. Vuetify ์‚ฌ์šฉ ์„ค์ •

vue add vuetify

src/main.js ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„

 

 

src/plugins/vuetify.js ํŒŒ์ผ ์ƒ์„ฑ

 

 

ํ‹ˆํ‹ˆ์ด Vue ๊ด€๋ จ ๊ธ€๋„ ์˜ฌ๋ ค์•ผ์ง€ ๐Ÿคฉ

+ Recent posts