0513
꼭 cd todo-with-vuex
해서 설치하기..
vue create todo-with-vuex
vue add vuex
npm run serve
Helloworld 관련 삭제
UI
All:
- Complted : count
- Inprogress: count
TodoList
TodoForm
TodoList
vues.js 에 가보시면 이름을 만드는 방법도 나와있다.
오늘 우리는 아래와 같은 컴포넌트를 만들어준다.
components
- TodoForm
- TodoList
- TodoListItem
TodoForm
<template> <div> <input type="text" @keyup.enter="onEnter"> <button @click="onClick">Add</button> </div> </template> <script> export default { name: 'TodoForm', methods: { onEnter() { console.log('oke') }, onClick() { console.log('okc') }, } } </script> <style> </style>
- App.vue
부트스트랩사용하기
부트스트랩 접속(https://getbootstrap.com/)
publick 폴더안의 index.html의 head안에 넣어줍니다.
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
store의 index.js 로
state 밑에 getters 만들어주고 todoList 정의하고 이를 컨트롤 하려면
mutations 에 업데이트 함수를 만들어준다
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todoList: [],
},
getters: {
},
mutations: {
CREATE_TODO(state, newTodo) {
state.todoList.push(newTodo)
},
},
actions: {
},
modules: {
}
})
그러면 Create_TODO를 TODOform 에서 가져다 사용할수있따
this.$store.commit('CREATE_TODO', this.userInput)
추가해주기
data를 사용하여 양방향 바인딩해주기 v-model
<template>
<div>
<input
type="text"
v-model="userInput"
@keyup.enter="onEnter">
<button @click="onClick">Add</button>
</div>
</template>
<script>
export default {
name: 'TodoForm',
data() {
return {
userInput: '',
}
},
methods: {
onEnter() {
//console.log('oke')
this.$store.commit('CREATE_TODO',this.userInput)
},
onClick() {
// console.log('okc')
this.$store.commit('CREATE_TODO',this.userInput)
},
}
}
</script>
<style>
</style>
가공을 해서 넘겨줘보자
const newTodo = {
id: '',
content: '',
completed: false,
}
서버에서 가져오면 PK값이있다.
content는 this.userInput
으로 넣어주자.
UUID 사용해보자(유효id: 지문)
참고 : https://github.com/VitorLuizC/vue-uuid
npm i vue-uuid
설치가 완료됐다면 main.js에 등록해주자.
import Vue from 'vue'
import App from './App.vue'
import store from './store'
import UUID from 'vue-uuid'
Vue.use(UUID)// 등록
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App)
}).$mount('#app')
그리고 버전마다 다른 uuid를 적용시켜주자(홈페이지 맨아래 v1~v5 참고)
TodoForm 으로가자 id에 this.$uuid.v1(),
를 추가시켜주고
아래 this.$store.commit('CREATE_TODO',this.newTodo)
로 넘겨준다.
<template>
<div>
<input
type="text"
v-model="userInput"
@keyup.enter="onEnter">
<button @click="onClick">Add</button>
</div>
</template>
<script>
export default {
name: 'TodoForm',
data() {
return {
userInput: '',
}
},
methods: {
onEnter() {
//console.log('oke')
const newTodo = {
id: this.$uuid.v1(),
content: this.userInput,
completed: false,
}
this.$store.commit('CREATE_TODO',newTodo)
},
onClick() {
// console.log('okc')
const newTodo = {
id: this.$uuid.v1(),
content: this.userInput,
completed: false,
}
this.$store.commit('CREATE_TODO',newTodo)
},
}
}
</script>
<style>
</style>
그리고 TodoForm 에서 newTodo 함수를 만들어주자.
<template>
<div>
<input
type="text"
v-model="userInput"
@keyup.enter="onEnter"
>
<button @click="onClick">Add</button>
</div>
</template>
<script>
export default {
name: 'TodoForm',
data() {
return {
userInput: '',
}
},
methods: {
onEnter() {
//console.log('oke')
const newTodo = {
id: this.$uuid.v1(),
content: this.userInput,
completed: false,
}
this.$store.commit('CREATE_TODO',newTodo)
},
onClick() {
// console.log('okc')
const newTodo = {
id: this.$uuid.v1(),
content: this.userInput,
completed: false,
}
this.$store.commit('CREATE_TODO',newTodo)
},
newTodo(content) {
return {
id: this.$uuid.v1(),
content,
completed: false,
}
},
}
}
</script>
<style>
</style>
이렇게 되면 onclick과 onEnter의 newTodo를 삭제하고 옆으로 넘길수있다.
const 를 삭제하고 this.$store.commit('CREATE_TODO', this.newTodo(this.userInput) )
를 적어준다.
<template>
<div>
<input
type="text"
v-model="userInput"
@keyup.enter="onEnter"
>
<button @click="onClick">Add</button>
</div>
</template>
<script>
export default {
name: 'TodoForm',
data() {
return {
userInput: '',
}
},
methods: {
onEnter() {
//console.log('oke')
this.$store.commit('CREATE_TODO', newTodo(this.userInput) )
},
onClick() {
// console.log('okc')
this.$store.commit('CREATE_TODO', this.newTodo(this.userInput) )
},
newTodo(content) {
return {
id: this.$uuid.v1(),
content,
completed: false,
}
},
}
}
</script>
<style>
</style>
그리고 어차피 함수가 겹치니 하나로 통일시켜주자 onSumbit
<template>
<div>
<input
type="text"
v-model="userInput"
@keyup.enter="onSubmit"
>
<button @click="onSubmit">Add</button>
</div>
</template>
<script>
export default {
name: 'TodoForm',
data() {
return {
userInput: '',
}
},
methods: {
onSubmit() {
this.$store.commit('CREATE_TODO', this.newTodo(this.userInput) )
},
newTodo(content) {
return {
id: this.$uuid.v1(),
content,
completed: false,
}
},
}
}
</script>
<style>
</style>
index.js의 getters 로가자
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todoList: [],
},
getters: {
getTodoList(state) {
return state.todoList
},
},
mutations: {
CREATE_TODO(state, newTodo) {
state.todoList.push(newTodo)
},
},
actions: {
},
modules: {
}
})
다음 TodoList.vue로가자
- 반복문 돌리면서 출력해주기
<template>
<div>
<div
v-for="todo in todoList"
:key="todo.id"
>
{{ todo.content }}
</div>
</div>
</template>
<script>
export default {
name: 'TodoList',
computed: {
todoList() {
return this.$store.getters.getTodoList
},
},
}
</script>
<style>
</style>
app.vue
<template>
<div id="app">
<TodoForm/>
<TodoList/>
</div>
</template>
<script>
import TodoForm from '@/components/TodoForm'
import TodoList from '@/components/TodoList'
export default {
name: 'App',
components: {
TodoForm,
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>
TodoListItem.vue로 이동해주자
객체 형태로 적어주고
명시적으로 적어주기
<template>
<div>
<input type="checkbox" v-model="todo.completed">
<span>{{ todo.content }}</span>
</div>
</template>
<script>
export default {
name: 'TodoListItem',
props: {
todo: {
type: Object,
required: true,
},
},
}
</script>
<style>
</style>
TodoList에서 불러와주자
<template>
<div>
<TodoListItem
v-for="todo in todoList"
:key="todo.id"
:todo="todo"
/>
</div>
</template>
<script>
import TodoListItem from '@/components/TodoListItem'
export default {
name: 'TodoList',
components: {
TodoListItem,
},
computed: {
todoList() {
return this.$store.getters.getTodoList
},
},
}
</script>
<style>
</style>
클릭했을때 완료 표시
체크박스에 체크를하면 완료가되게!
2가지 방법이있다. TodoList 의 div에서 하는방법
- @click.native 를 사용해야한다
TodoListItem에서 하는방법 컴포넌트에서하기
- div @click="onClick"
- 아래 methods 를 만들어서 추가하자
index.js 의 create_todo 아래에 update_todo를 만들어주자
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todoList: [],
},
getters: {
getTodoList(state) {
return state.todoList
},
},
mutations: {
CREATE_TODO(state, newTodo) {
state.todoList.push(newTodo)
},
UPDATE_TODO(state, targetTodo) {
// todoList에서 targetTodo를 찾고
// targetTodo의 complted 값을 변경
state.todo = state.todoList.map((todo)=> {
if (todo.id == targetTodo.id) {
// 참이면 거짓으로, 거짓이면 참으로 변경
todo.completed = !todo.completed
}
return todo
})
},
},
actions: {
},
modules: {
}
})
TodoListItem
- props에서 data로 넘긴다.
this.$store.commit('UPDATE_TODO', this.todo)
값확인 잘되는지 확인은 홈페이지에서 add 해보고 개발자 옵션 vue에서 competed에서 체크후 참으로바뀌면 잘동작
<template>
<div @click="onClick">
<input type="checkbox" v-model="todo.completed">
<span :class="{ completed: todo.completed }">{{ todo.content }}</span>
</div>
</template>
<script>
export default {
name: 'TodoListItem',
props: {
todo: {
type: Object,
required: true,
},
},
methods: {
onClick() {
// 1. mutation 호출
this.$store.commit('UPDATE_TODO', this.todo)
// 2. store에서 todo의 completed 값 변경
},
},
}
</script>
<style>
</style>
삭제 로직 만들기
Todo listitem 에 버튼을 만든다.
- @click="deleteClick"
- methods 에 delete click 함수만들고
this.$stroe.commit('DELETE_TODO', this.Todo)
mutations 안에 delete_todo(대문자)
state, targetTodo
cosnt targetTodoIdx = state.todoList.indexOf(targetTodo)
state.todoList.splice(targetTodoIdx, 1)
클릭해서 삭제되면 삭제 라고 띄우기
TodoListItem
배포하기
새로운 폴더로 node module 뺴고 옮긴다음
git bash
ls
git init
git add .
git commit -m " 이름"
까지만해주고 git hub 르가서 rep 만든다
빈칸 입력안되게하기
TodoForm
Dom 조작을 강제할때
querySelector을 vue 한테 좋은방향으로 쓰는것
ref="todoInput"
input 에 추가해주자.
onSubmit에
this.$refs.todoInput
인풋 셀럭터를 찍어서 온다음
<template>
<div>
<div class="d-flex">
<input
type="text"
ref="todoInput"
autofocus
@input="onUserInput"
@keyup.enter="onSubmit"
class="form-control"
>
<button
@click="onSubmit"
class="btn btn-primary btn-custom-sm"
>
Add
</button>
</div>
<div> {{ userInput.length }}/ 50자</div>
</div>
</template>
<script>
export default {
name: 'TodoForm',
data() {
return {
userInput: '',
}
},
methods: {
onUserInput(e) {
if (e.target.value.length > 50){
e.target.value = this.userInput
return
}
this.userInput = e.target.value
},
onSubmit() {
// 검증( 글자수 100자 제한 )
if (this.userInput.length > 50) {
const errorMsg = '검색어는 50자 이하로 작성해주세요.'
this.$store.commit('UPDATE_ERROR', errorMsg)
this.userInput=''
return
}
this.$store.commit('UPDATE_ERROR', '')
this.$store.commit('CREATE_TODO', this.newTodo(this.userInput) )
//검색창 검색후 초기화
this.userInput=''
this.$refs.todoInput.value=''
},
newTodo(content) {
return {
id: this.$uuid.v1(),
content,
completed: false,
}
},
}
}
</script>
<style>
.btn-custom-sm {
width: 100px !important;
height: 36px !important;
font-size: 75%
}
</style>