서버주소 => http://1.234.5.158:23000/
회원가입 => /member101/insert.json => 키정보 {id:"a", pw:"b", name:"c", email:"a@a.com", age:13 }
아이디중복확인 => /member101/idcheck.json?id=a
로그인 => /member101/select.json => 키정보 {"id":"a", "pw":"a"}
회원정보수정 => /member101/update.json 토큰(headers에 auth키) + {"name":"변경이름", "age":1234}
암호변경 => /member101/updatepw.json 토큰(headers에 auth키) + {"pw":"aaa", "newpw":"bbb"}
조회(select) => await axios.get(url, {headers});
추가(insert) => await axios.post(url, body, {headers});
수정(update) => await axios.put(url, body, {headers});
삭제(delete) => await axios.delete(url, {headers:headers, data:body});
vue에서 화면상에 조작하고 싶으면 (templates에)
1. 스크립트에 변수를 미리 만든다.
2. 마지막에 리턴
3. 위에서 사용
결국 스크립트에서 만든걸 화면에 던져준것. 사용해!
뷰의 관점은 스크립트 중심!
로그인 수정_백엔드 연동, autofocus, vuex
// 파일명 : LoginPage.vue
<template>
<div class="container">
{{ user }}
<h3>로그인</h3>
<div>
<label class="lbl">아이디</label>
<input type="text" ref="userid" v-model="user.userid" />
</div>
<div>
<label class="lbl">암호</label>
<input type="password" ref="userpw" v-model="user.userpw" />
</div>
<div>
<button @click="handleLogin()">로그인</button>
</div>
</div>
</template>
<script>
import axios from 'axios';
import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
export default {
setup () {
// 로그인 한 타이밍을 알려주기 위한 컴포넌트 공통 변수
const store = useStore();
// 페이지 이동
const router = useRouter();
// 공통변수 영역 상수 object로 만듬, reactive
const user = reactive({
userid : 'a1',
userpw : 'a1'
});
// 레퍼런스 변수 생성(focus 시키기 위함). import 해야해!
const userid = ref();
const userpw = ref();
// 함수들 영역
const handleLogin = async () => {
console.log('handleLogin');
if(user.userid === ''){
alert('아이디 입력하세요.');
userid.value.focus();
return false;
}
if(user.userpw === ''){
alert('암호를 입력하세요.');
userpw.value.focus();
return false;
}
// 벡엔드 연동 위치-> 함수 안에 짜야한다!
// 여기 왔다는 말은 위쪽에서 if문이 수행된적 없다는 뜻. 즉, 필터하고자 한것을 다 통과했다!
// if문이 수행됐으면 return false로 종료되니까.
const url = `/member101/select.json`;
const headers = {"Content-Type" : "application/json"};
const body = {
id : user.userid,
pw : user.userpw,
};
const { data } = await axios.post(url, body, {headers});
console.log(data);
if(data.status === 200) {
// 다른컴포넌트에서 로그인 검증 위해 저장(토큰값을 넣어주는것)
sessionStorage.setItem("TOKEN", data.result);
// 컴포넌트 공통 변수 값 변경(함수, 변경값)
store.commit('setLogged', true);
alert('로그인 성공했습니다.');
router.push({path:'/'});
}
else {
alert('아이디 또는 암호가 틀립니다.');
}
};
// 리턴 영역( 변수, 함수 등 templates에 사용하는 모든것)
return {
user, //reactive
handleLogin, //함수
userid, //ref
userpw //ref
};
}
}
</script>
<style lang="css" scoped>
.container {
width : 600px;
padding : 20px;
border : 2px solid #cccccc;
}
.lbl {
display : inline-block;
width : 100px;
}
</style>
// 파일명 : LogoutPage.vue
<template>
<div>
// 화면을 만들 필요는 없음. 로그아웃 할건지 알림창만 띄우면 되니까.
</div>
</template>
<script>
import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
export default {
setup () {
const store = useStore();
const router = useRouter();
// 페이지 로딩될때 바로 실행되도록
onMounted(() => {
if(confirm('로그아웃 할까요?')) {
sessionStorage.removeItem("TOKEN");
store.commit('setLogged', false);
// 로그아웃 됐다는걸 컴포넌트 공통 변수에 알려줌
}
router.push({path:'/'});
});
return {
};
}
}
</script>
<style lang="css" scoped>
</style>
회원가입 수정_백엔드 연동, autofocus, 아이디 중복확인
// 파일명 : JoinPage.vue
<template>
<div class="container">
<h3>회원 가입</h3>
{{ user }}
<div>
<label class="lbl">아이디</label>
<input type="text" ref="uid" v-model="user.userid" @keyup="handleIDCheck()" />
<label class="lbl" v-html="user.idcheck"></label>
// html태그 작성한것 해석해서 출력
</div>
<div>
<label class="lbl">암호</label>
<input type="password" ref="upw" v-model="user.userpw" />
</div>
<div>
<label class="lbl">암호 확인</label>
<input type="password" ref="upw1" v-model="user.userpw1" />
</div>
<div>
<label class="lbl">이름</label>
<input type="text" ref="uname" v-model="user.username" />
</div>
<div>
<label class="lbl">나이</label>
<input type="number" ref="uage" v-model="user.userage" />
</div>
<div>
<label class="lbl">이메일</label>
<input type="text" ref="uemail" v-model="user.useremail" />
<label>@</label>
<select v-model="user.useremail1">
<option>이메일 주소 선택</option>
<option>google.com</option>
<option>naver.com</option>
<option>daum.net</option>
</select>
</div>
<div>
<button @click="handleJoin()">회원 가입</button>
</div>
</div>
</template>
<script>
import axios from 'axios';
import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
export default {
setup () {
const router = useRouter();
// 상태변수
const user = reactive({
userid : '',
userpw : '',
userpw1 : '',
username : '',
userage : '',
useremail : '',
useremail1 : '이메일 주소 선택',
idcheck : '<label style="color:#000000">중복 확인</label>'
});
// 묶어서 표현하고 싶다...어떻게?
const uid = ref();
const upw = ref();
const upw1 = ref();
const uname = ref();
const uage = ref();
const uemail = ref();
// 함수들
const handleJoin = async() => {
if(user.userid === '') {
alert('아이디를 입력하세요.')
uid.value.focus();
return false;
}
if(user.userpw === '') {
alert('암호를 입력하세요.')
upw.value.focus();
return false;
}
if(user.userpw1 === '') {
alert('암호를 다시 입력하세요.')
upw1.value.focus();
return false;
}
if(user.userpw !== user.userpw1) {
alert('암호를 확인 하세요.')
upw1.value.focus();
return false;
}
if(user.username === '') {
alert('이름를 입력하세요.')
uname.value.focus();
return false;
}
if(user.userage === '') {
alert('나이를 입력하세요.')
uage.value.focus();
return false;
}
if(user.useremail === '') {
alert('이메일을 입력하세요.')
uemail.value.focus();
return false;
}
if(user.useremail1 === '이메일 주소 선택') {
alert('이메일 주소를 입력하세요.')
return false;
}
// 유효성 성공하면 백엔드 연동
const url = `/member101/insert.json`;
const headers = {"Content-Type":"application/json"};
const body = {
id : user.userid,
pw : user.userpw,
name : user.username,
email : `${user.useremail}@${user.useremail1}`,
// 변수와 문자를 동시에 입력하고 싶다면 이런 꼴로!
age : user.userage
};
const { data } = await axios.post(url, body, {headers});
console.log(data);
if(data.status === 200) {
alert('회원 가입 성공!');
router.push({path:'/'});
}
}
// 아이디를 입력할때 마다 호출되는 함수
const handleIDCheck = async() => {
console.log('handleIDCheck');
// user.idcheck = '중복확인'; 이렇게 걸면 else 두개를 생략 가능 하지만 중간중간(백엔드로 왔다갔다 하는 시간차) 중복확인이 떠서 거슬림...
// 프론트에서 검증 다하고 백엔드로 날리는게 맞다. 아니면 백엔드에서 부하 걸려!
if(user.userid.length > 0) { // 내용 입력
const url=`/member101/idcheck.json?id=${user.userid}`;
const headers={"Content-Type":"application/json"};
const { data } = await axios.get(url, {headers});
console.log(data);
if(data.status === 200) { // 백엔드 정상적인가?
if(data.result === 0) { // 사용 가능 위치
user.idcheck = '<label style="color:green">사용 가능</label>';
// v-html을 사용했으므로 ''안의 태그가 해석되어서 출력
}
else if(data.result === 1) { // 사용 불가 위치
user.idcheck = '<label style="color:red">사용 불가</label>';
}
}
else { // 정상적이지 않을 경우
user.idcheck = '<label style="color:#000000">중복 확인</label>';
}
}
else { // 내용 입력하지 않음
user.idcheck = '<label style="color:#000000">중복 확인</label>';
}
};
// 템플릿에서 사용하기 위한 리턴(변수, 함수 등..)
return {
user,
handleJoin,
uid,
upw,
upw1,
uname,
uage,
uemail,
handleIDCheck
}
}
}
</script>
<style lang="css" scoped>
.container {
width : 600px;
padding : 20px;
border : 2px solid #ffd7d7;
margin : 0px auto;
}
.lbl {
display: inline-block;
width: 100px;
padding: 5px;
}
</style>
====================================
-- 라이브러리 설치하기
CMD> npm i vuex --save
// 파일명 : stores/index.js
import { createStore } from 'vuex';
// LoginPage.vue 컴포넌트에서 로그인된 정보를 App.vue로 실시간으로 알려줘야 함
// LogoutPage.vue 컴포넌트에서 로그아웃된 정보를 App.vue로 실시간으로 알려줘야 함
// mutations에서 데이터를 바꾸고 state변수에 저장하면 getters에서 가져가는것!
const stores = createStore({
// 컴포넌트별 공유하는 변수
// 저장소의 토큰값을 가져와서 true, false 나타냄
/* :를 찍으면 {} 내용을 변수설정한다고 보기 때문에 if, for과 같은 문법이 사용 불가능 하다.
state : {
logged : false,
counter : 10
},
*/
// 새로고침하더라도 로그인 상태를 유지하고 싶다!
state() {
let tmp = false; // 기본값은 로그아웃
if(sessionStorage.getItem("TOKEN") !== null){ // 토큰 값이 있으면
tmp = true; // 로그인 상태로
}
return {
logged : tmp, // 로그인 or 아웃 상태를 기록
counter : 10 // 이건 그냥 여러개 값이 들어간다고 보여주기 위한 예시. 실습에만 이용.
}
},
// App.vue컴포넌트에서 사용 예정. 가져감!
getters :{
getLogged(state) {
return state.logged;
}
getCounter(state) {
return state.counter;
}
},
// 로그인, 로그아웃 컴포넌트에서 사용 예정. 변경됨!
mutations :{
setLogged(state, value){
state.logged = value
},
setCounter(state, val) { // counter에 새로운 값을 줌.
state.counter = val;
},
setCounterPlus(state) { // counter 값에 +1씩
state.counter++;
// state.counter = state.counter + 1; 와 같은 의미지만 너무 길어서 위의 방식으로 사용.
},
setCounterMinus(state) { // counter 값에 -1씩
state.counter--;
}
}
});
export default stores;
// 파일명 : main.js
import { createApp } from 'vue'
import App from './App.vue'
// 라우터처럼 메인에 등록!
import routes from './routes/index';
import stores from './stores/index';
const app = createApp(App);
app.use(routes);
app.use(stores);
app.mount('#app');
// 파일명 : MyPage.vue
<template>
<div>
<h3>마이페이지</h3>
// 토큰을 가지고 있을때만(로그인 상태) 나오는 페이지
{{ state }}
<hr />
<button @click="state.menu=1">회원정보수정</button>
<button @click="state.menu=2">비밀번호변경</button>
<hr />
<div v-show="state.menu === 1" v-if="state.user">
<div>
<input type="text" v-model="state.user.name" />
</div>
<div>
<input type="text" v-model="state.user.age" />
</div>
<div>
<button @click="handleUpdate()">정보수정</button>
</div>
</div>
<div v-show="state.menu === 2">
<div>
<input type="password" v-model="state.user.oldpw" placeholder="기존암호" />
</div>
<div>
<input type="password" v-model="state.user.newpw" placeholder="변경암호" />
</div>
<div>
<input type="password" v-model="state.user.newpw1" placeholder="변경암호확인" />
</div>
<div>
<button @click="handleUpdatePW()">비밀번호변경</button>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
import { reactive, onMounted } from 'vue';
export default {
setup () {
const state = reactive({
menu : 1, // 메뉴
token : sessionStorage.getItem("TOKEN"), // 토큰
user : null, // 현재 사용자 정보 보관용
// null로 하면 if문 처리 해야 오류 안남. ''로 하면 if문 처리 안해도 오류 안남.
oldpw : null, // 이건 null이고 if문 처리 안해도 오류가 안난다..! 데이터 처리 시 순서가 나중인가...?
newpw : null,
newp1 : null,
});
const handleData = async() => {
const url = `/member101/selectone.json`;
const headers = {
"Content-Type" : "application/json",
"auth" : state.token
// headers에 토큰을 심음
}
const { data } = await axios.get(url, {headers});
console.log(data);
if(data.status === 200) {
state.user = data.result;
}
};
onMounted(() => {
handleData();
});
const handleUpdate = async() => {
const url = `/member101/update.json`;
const headers = {
"Content-Type" : "application/json",
"auth" : state.token
// 이름하고 나이만 주면 어떤 사람건지 모름. 그래서 토큰을 같이 보내는것.
};
const body = {
name : state.user.name,
age : state.user.age,
};
const { data } = await axios.put(url, body, {headers});
console.log(data);
if(data.status === 200){
alert('정보수정완료');
handleData();
// 정보 수정 후 새로고침 해준 것
}
};
const handleUpdatePW = async() =>{
const url = `/member101/updatepw.json`;
const headers = {
"Content-Type" : "application/json",
"auth" : state.token
};
const body = {
pw : state.oldpw,
newpw : state.newpw,
};
const { data } = await axios.put(url, body, {headers});
console.log(data);
if(data.status === 200){
alert('비밀번호 변경 완료');
state.menu = 2;
// handleData는 회원정보 불러오는 함수인데 거기엔 비밀번호가 포함 안되있잖어...
// 그래서 굳이 비밀번호 변경하고 다시 handleData를 작동시킬 이유가 없음.
}
};
return {
state,
handleUpdate,
handleUpdatePW
};
}
}
</script>
<style lang="css" scoped>
</style>
// 파일명 : StorePage.vue
<template>
<div>
<h3>store 실습</h3>
<div>
<input type="number" v-model="state.num" />
</div>
<button @click="handleFunc1()">입력한 값으로 변경하기</button>
<button @click="handleFunc2()">기본 숫자에서 1증가 시키기</button>
<button @click="handleFunc3()">기본 숫자에서 1감소 시키기</button>
</div>
</template>
<script>
import { reactive, computed } from 'vue';
import { useStore } from 'vuex';
export default {
setup () {
const store = useStore();
const state = reactive({
num : 10,
counter : computed(() => store.getters.getCounter ),
// 바뀐 값을 입력창에서 실시간으로 보여주고싶으면 App에서 가져와서 쓴것 처러 computed 해야함! import하는것 잊지마
});
const handleFunc1 = () =>{
store.commit('setCounter', state.num);
// state.num값으로 변경!
};
const handleFunc2 = () =>{
store.commit('setCounterPlus');
// 넣어줘야 할 값이 있는게 아님!
};
const handleFunc3 = () =>{
store.commit('setCounterMinus');
};
return {
state,
handleFunc1,
handleFunc2,
handleFunc3
};
}
}
</script>
<style lang="css" scoped>
</style>
// 파일명 : App.vue의 script 부분만
<script>
import { reactive, computed } from 'vue';
import { useStore } from 'vuex';
export default {
setup () {
// 컴포넌트별 공용변수 사용하기 위해
const store = useStore();
const state = reactive({
logged : computed(() => store.getters.getLogged ),
counter : computed(() => store.getters.getCounter ),
// counter 실습을 위해 추가함... 이게 없어도 작동 한다. App.vue에서 필요한게 아니니까
})
return {state}
}
}
</script>
참고)) vue3에서 ref와 reactive 차이 ----> https://velog.io/@yeonsubaek/Vue.js-rel-reactive-사용법값-변경하기