element-plus, store 모듈화, upload

keep_going·2023년 1월 6일
0

vue

목록 보기
12/13
  • store도 파일이 많아지면 관리가 어렵다. 모듈화 시킨다(폴더를 따로 만들어서 파일을 분리하는것!)

// 파일명: stores/index.js_수정: 원래 있던 index파일을 copy해서 index1.js로 바꿔주고 지금 실습을 위해 index.js 새로 생성.. 기존에 index파일 쓰던 컴포넌트들은 오류 날것이야...


import { createStore } from "vuex";

// 상대경로로 가져옴
import { moduleA } from './modules/moduleA';
// 절대경로로 가져옴
import { moduleB } from '@/stores/modules/moduleB';

export default createStore({
    modules : { moduleA, moduleB }
});

// props와 emit은 component 둘 사이에만 주고 받을떄
// 여러 component에서 공통으로 데이터 주고 받으려고 하면 복잡! 그래서 따로 store(vuex, 리액트에서는 redux) 만들어서 바로 가져가도록함.
// 가져온 component(element plus)를 사용하기 위해서 props, emit설명했던것 실제 쓸일 없을것이야...

// 파일명: stores/modules/moduleA.js

// 숫자로 관리
export const moduleA = {
    namespaced:true,

    state : {
        num1 : 0,
        num2 : 10,
    },

    getters : {
        getNum1(state) {
            return state.num1;
        },
        getNum2(state) {
            return state.num2;
        }
    },

    mutations : {
        setNum1(state, value) {
            state.num1 = value;
        },
        setNum1DoubleCount(state){
            state.num1 = state.num1*2;
        },
        setNum2(state, value) {
            state.num2 = value;
        }
    },

    actions : {
        // 로그인 후에 토큰을 받음, 세션 저장소 보관
      	// (context, value)로 찍으면 value값 전달 가능. 지금은 오류나기 때문에 안쓴것.
        handleData(context) {
            //벡엔드 연동 실행 후 mutation에 있는 함수 이용 -> mutation에서 state 변수값 변경
            // mutations는 백엔드 연동 안됨. 실시간으로 변경되는 것만 가능.
          	// getters는 가져가는것만 가능. readonly
          	// state가 갱신되면 getters는 자동으로 변경된 값을 가져옴
            // mutations와 actions은 둘다 컴포넌트에서 데이터를 변경하는 것. 
          	// 차이점은 actions은 백엔드에 연동되는 시간이 필요. mutations은 못기다림.
            context.commit("setNum1", 13);
        }
    }
}

// 파일명: stroes/modules/moduleB.js

// 로그인 관련 정보
export const moduleB = {
    namespaced:true,

    state : {
        logged : false,
        userid : '',
        username : '',
    },

    getters : {
        getLogged(state) {
            return state.logged;
        },
        getUserid(state) {
            return state.userid;
        }
    },

    mutations : {
        setLogged(state, value) {
            state.logged = value;
        },
        setUserid(state, value) {
            state.userid = value;
        }
    },

    actions : {
        handleData(context) {
            context.commit("setUserid", "벡엔드에서 받은 아이디값");
        }
    }
}

// 파일명: VuexPage.vue

<template>
    <div>
        <h3>Vuex실습</h3>
        {{ state }}
        <button @click="handleA()">모듈A의 num1을 77로 변경</button>
        <button @click="handleB()">모듈A의 num2을 888로 변경</button>
        <button @click="handleC()">모듈B의 logged을 true로 변경</button>
		<hr />
        // v-model은 양방향, 입력한게 바로 state변수에 적용됨. 
        // v-text => {{  }}, v-html 2개는 단방향, 내용을 가져와서 표시하는것만 가능
        <input type="text" v-model="state.name" />
    </div>
</template>

<script>
import { reactive } from '@vue/reactivity';
import { useStore } from 'vuex'
import { computed, watch } from '@vue/runtime-core';
export default {
    setup () {
        const store = useStore();

        // App.vue => store.getter를 수동으로 처리 가능.
        store.subscribe((mutations, state) => {
            console.log(mutations, state);
        });

        const state = reactive({
          	name  : '',
            name1 : '', 
            // '' 대신 computed(() => state.name.toLowerCase()), 쓰면 watch쓰는것과 같은 효과. 입력한 값을 실시간으로 변경. 
            // computed때문에 자동화 된것. 데이터가 변경되면 감지해서 실시간으로 오도록 한것. 그래서 오는걸 따로 처리 안해도 변경된 값이 바로 온것!
          
          	// n1, n2 표현만 다르게 한것. {}이걸 쓰면 함수처럼 보여서 return해야한다.
            n1 : computed(() => { return store.getters["moduleA/getNum1"] }),
            n2 : computed(() => store.getters["moduleA/getNum2"]),
            logged : computed(() => store.getters["moduleB/getLogged"]),
        });
      	// 이 페이지에서만 쓸꺼면 state만 쓰면 되지... 여기서 호출하는경우는 없다!!! 
        // 원래는 vux페이지에서 로그인, 로그아웃 같은 다른 페이지 호출하려고 쓰는것.
        // 지금은 실습이니까 페이지 새로 만들기 귀찮아서 이 페이지에 만들어서 쓰는것이야 헷갈리지마슈
      
      	// 실시간으로 변수를 감지
        watch(() => state.name, () => {
            state.name1 = state.name.toLowerCase();
        },{
            immediate : true,
            deep : true,
        });
      
        const handleA = () => {
            store.commit("moduleA/setNum1", 77);
            // actions 호출방법 => store.dispatch("moduleA/handleData", "전달하는내용")
        };

        const handleB = () => {
            store.commit("moduleA/setNum2", 888);
        };

        const handleC = () => {

        };

        return { 
            state, 
            handleA, 
            handleB, 
            handleC 
        };
    }
}
</script>

<style lang="scss" scoped>

</style>

// 파일명: BoardInsertPage.vue_수정: 이미지 업로드에 element plus 적용

<template>
  <el-dialog v-model="state.dialogVisible">
    <img style="width:100%" :src="state.dialogImageUrl" alt="Preview Image" />
  </el-dialog>

<el-upload action="#" 
	list-type="picture-card" 
	:auto-upload="false" 
	:on-remove="handelRemove"
	:on-preview="handlePreview"
	v-model:file-list="state.filelist"
>
  <el-icon><Plus /></el-icon>
</el-upload>
<!--  emit이 아니라 props로 되어 있음.. -->
</template>

<script>
import { Plus } from '@element-plus/icons-vue'     

export default {
    components : {
        Plus, // plus쓰고 싶으면 import 시키고 여기에 추가해야 한다!
    },
  
  	setup () {
        const state = reactive({
            filelist : [], // 첨부파일 목록
            dialogVisible : false, // + 미리보기 다이얼로그
            dialogImageUrl : '', // 미리보기 이미지 url
        });
      
      	 const handleInsert = async() => {
            // 사진 여러개 추가했을때 동시에 넣을수 있나 싶어서 반복물 돌렸으나..
            // 그건 백엔드를 수정해야하는거고 이렇게 하면 똑같은 게시글이지만 사진만 다른 게시글이 여러개로 나뉘어서 올라감
            for(let tmp of state.filelist) {
                const url = `/board101/insertimage.json`;
                const headers = {"Content-Type":"multipart/form-data"};
                const body = new FormData();
                body.append("title", state.title);
                body.append("content", state.editorData);
                body.append("writer", state.writer);
                // 파일명, 크기, 내용, 종류
                // body.append("image", state.file);
                body.append("image", tmp.raw); 

                const { data } = await axios.post(url, body, {headers});
                console.log(data);
                console.log(state.filelist);
                if(data.status === 200) {
                    store.commit('setDefaultActive', '/boardselect1');
                	router.push({path:'/boardselect'});
                }
            }
         };
      
         const handelRemove = (e) => {
            console.log(`삭제 =>`, e);
         }
            // {e}로 확인하면 object로 나와서 내용 확인하려면 e로.. 파일의 정보가 나옴
         const handlePreview = (e) => {
            state.dialogImageUrl = e.url;
            state.dialogVisible = true;
            console.log(`미리보기 =>`, e);
         }

         return {
            state,
            // handleImage,
            handleInsert,
            handelRemove,
            handlePreview,
         }
    }
}
</script>
profile
keep going

1개의 댓글

comment-user-thumbnail
2023년 1월 9일

빌드하고나면... public에서 index위치에 ...
14라인에서 app.vue... 결국 이게 들어가는것...!통으로 빌드 시키면 js파일 두개css 파일 2개 정도로 되는데...
그때 만들어진 index와 아이콘,,, 웹은 이걸 ㅏㄱ져가서 쓰는것... vue파일으 ㄹ보는게 아니다.
src에서 해결안되는 라이브러리 있으면 최종적으로 index.html에 가서 스크립트를 짜도 되긴함.. 빌드할떄 안들어가서...!
아이콘은 index에 7라인 ㅣ떄문에 나온것. 그래서 크롬에서 탭창에서 뜨는 아이콘이 뜬거야...!

답글 달기