파일명 src/component/Join.vue
<template>
<div class="style1">
<h3>src/component/Join.vue</h3>
{{state}}
<hr/>
<el-form :inline="true" >
<el-form-item label-width="120px" label="User Id" >
<el-input ref="userid" v-model="state.uid"></el-input>
</el-form-item>
</el-form>
<el-form :inline="true" >
<el-form-item label-width="120px" label="User Password" >
<el-input ref="userpw" type="password" v-model="state.upw"></el-input>
</el-form-item>
</el-form>
<el-form :inline="true" >
<el-form-item label-width="120px" label="Password check" >
<el-input ref="userpw1" type="password" v-model="state.upw1"></el-input>
</el-form-item>
</el-form>
<el-form :inline="true" >
<el-form-item label-width="120px" label="User Email" >
<el-input ref="useremail" v-model="state.uemail"></el-input>
</el-form-item>
<el-form-item label="@">
<el-select ref="useremail1" v-model="state.uemail1" placeholder="도메인 선택">
<el-option label="gmail.com" value="gmail.com"></el-option>
<el-option label="naver.com" value="naver.com"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-form :inline="true" >
<el-form-item label-width="120px" label=" " >
<el-button style="width:100px" @click="handleJoin" type="primary">회원가입</el-button>
<el-button style="width:100px" type="primary">취소</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { reactive, ref } from 'vue';
import axios from "axios";
export default {
setup () {
// High레벨 변수 생성 : 오브젝트만 변화 감지
const state = reactive({
uid : '',
upw : '',
upw1 : '',
uemail : '',
uemail1 : '',
})
// Low레벨 변수 생성 : 오브젝트가 아님
const userid = ref(null); // 위에서 연결하면 bbb값은 의미가 없어짐
const userpw = ref(null); // ref 안쪽에 모든 데이터가
const userpw1 = ref(null);
const useremail = ref(null);
const useremail1 = ref(null);
// function handleJoin( ){ }
const handleJoin = async() =>{
if(state.uid === ''){
alert('아이디를 입력 하세요');
userid.value.focus();
return false; // 이 위치에서 메소드 종료
}
if(state.upw === ''){
alert('비밀번호를 입력하세요');
userpw.value.focus();
return false;
}
if(state.upw1 !== state.upw){
alert('비밀번호가 일치하지 않습니다');
userpw1.value.focus();
return false;
}
if(state.uemail === ''){
alert('이메일을 입력하세요');
useremail.value.focus();
return false;
}
if(state.uemail1 === ''){
alert('도메인을 선택하세요');
useremail1.value.focus();
return false;
}
// 유효성 검증완료되는 시점에 백엔드 연동
const url = "http://ihongss.com/json/exam13.json";
const headers = {"Content-Type": "application/json"};
const response = await axios.get(url,{headers});
console.log(response.data);
alert('회원가입 완료');
};
return {userid, userpw, userpw1, useremail, useremail1, state, handleJoin}
}
}
</script>
<!-- scss,less => css -->
<!-- npm install -D sass-loader@^10 sass -->
<style lang="scss" scoped>
.style1{
border : 1px solid #cccccc;
padding : 20px;
}
</style>
=====================================================
파일명 src/components/Chart.vue
https://github.com/J-T-McC/vue3-chartjs
CMD> npm install chart.js @j-t-mcc/vue3-chartjs
npm install chart.js
npm install @j-t-mcc/vue3-chartjs
<template>
<div>
<h3>src/components/Chart.vue</h3>
<div style="width:500px; height:300px">
<vue3-chart-js :id = "state.id" :type = "state.type"
ref = "chartRef" :data = "state.data">
</vue3-chart-js>
<button @click="updateChart">Update Chart</button>
<button type="submit" @click="exportChart">Export Chart as PNG</button>
</div>
</div>
</template>
<script>
import { ref } from 'vue';
import Vue3ChartJs from '@j-t-mcc/vue3-chartjs'
export default {
components:{
Vue3ChartJs
},
setup () {
// object(R) -> reactive(RW) -> ref(RW Deep)
//const state = reactive({}); v-model 변화감지 Read Write
const state ={ // Read
id:'doughnut',
type : 'doughnut',
data :{
labels : ['VueJs', 'EmberJs', 'ReactJs', 'AngularJs'],
datasets : [
{ backgroundColor: [ '#41B883', '#E46651', '#00D8FF', '#DD1B16'],
data : [340,220,460,320]
}
],
}
}
// 빈것 만들기
const chartRef = ref(null);
// function updateChart() { }
const updateChart = () => {
// 변경 데이터 설정
state.data.labels = ['Cats', 'Dogs', 'Hamsters', 'Dragons']
state.data.datasets = [
{
backgroundColor: ['#333333', '#E46651', '#00D8FF', '#DD1B16'],
data: [100, 20, 80, 20]
}
]
// 컴포넌트에 변화되었음을 알려줌
chartRef.value.update(250);
}
const exportChart = () => {
let a = document.createElement('a')
a.href = chartRef.value.chartJSState.chart.toBase64Image()
a.download = 'image-export.png'
a.click()
a = null
}
// 리턴함
return {state, updateChart, chartRef, exportChart}
}
}
</script>
<style lang="scss" scoped>
</style>
=====================================================
파일명 src/components/Chart1.vue
<template>
<div>
<h3>src/components/Chart1.vue</h3>
<div style="max-width: 600px">
<vue3-chart-js ref="chartRef" :id="state.id" :type="state.type" :data="state.data">
</vue3-chart-js>
</div>
<button @click="updateChart">Update Chart</button>
<button type="submit" @click="exportChart">Export Chart as PNG</button>
</div>
</template>
<script>
import { ref } from 'vue'
import Vue3ChartJs from "@j-t-mcc/vue3-chartjs";
export default {
components: { Vue3ChartJs },
setup () {
const chartRef = ref(null)
const state ={
id : "rader",
type : "bar",
data: {
labels: [ "일", "월", "화", "수", "목", "금", "토" ],
datasets: [
{
label: "독서량",
data: [ 20, 78, 8, 40, 95, 43, 19],
borderColor: "rgb(255, 99, 132)",
backgroundColor: "rgba(255, 99, 132, 0.5)"
},
{
label: "수면시간",
data: [ 99, 43, 8, 20, 43, 41, 5],
borderColor: "rgb(54, 162, 235)",
backgroundColor: "rgba(54, 162, 235, 0.5)"
},
{
label: "여가시간",
data: [ 75, 50, 74, 72, 70, 63, 20],
borderColor: "rgb(75, 192, 192)",
backgroundColor: "rgba(75, 192, 192, 0.5)"
},
],
},
}
const updateChart = () => {
state.data.labels = [ "월", "화", "수", "목", "금", "토", "일" ]
state.data.datasets = [
{
label: "독서량",
data: [ 10, 28, 38, 40, 55, 73, 89],
borderColor: "rgb(255, 99, 132)",
backgroundColor: "rgba(255, 99, 132, 0.5)"
},
{
label: "수면시간",
data: [ 10, 24, 38, 40, 53, 81, 95],
borderColor: "rgb(54, 162, 235)",
backgroundColor: "rgba(54, 162, 235, 0.5)"
},
{
label: "여가시간",
data: [ 25, 30, 44, 52, 60, 93, 100],
borderColor: "rgb(75, 192, 192)",
backgroundColor: "rgba(75, 192, 192, 0.5)"
},
]
chartRef.value.update(250);
}
const exportChart = () => {
let a = document.createElement('a')
a.href = chartRef.value.chartJSState.chart.toBase64Image()
a.download = 'image-export.png'
a.click()
a = null
}
return {state, updateChart, chartRef, exportChart }
}
}
</script>
<style lang="scss" scoped>
</style>
=====================================================
파일명 src/component/BoardWrite.vue
npm install --save @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic
<template>
<div>
<h3>src/component/BoardWrite.vue</h3>
{{state}}<br />
제목 : <input type="text" v-model="state.title"/><br />
내용 :
<div style="width:600px">
<ckeditor :editor="editor.editor" :config="editor.editorConfig" v-model="state.content"></ckeditor>
</div>
작성자 : <input type="text" v-model="state.writer" /><br />
이미지 : <img :src="state.imgurl" style="width:50px;height:50px"/>
<input type="file" @change="handleImage"/><br />
<button @click="handleWrite">글쓰기</button>
</div>
</template>
<script>
import { reactive } from 'vue'
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
export default {
setup () {
//object
const editor ={
editor : ClassicEditor,
editorData : <p>테스트</p>,
editorConfig : {}
}
const state = reactive({
title : '',
content : '',
writer : '',
imgdata : '',
imgurl : require('../assets/default.jpg'),
});
const handleImage = (e) =>{
console.log(e);
if(e.target.files[0]){// 첨부
state.imgdata = e.target.files[0];
// 크롬 내부에 임시로 이미지를 표시하기 위한 URL생성
state.imgurl = URL.createObjectURL(e.target.files[0]);
}
else{// 취소
state.imfdata = '';
state.imgurl = require('../assets/default.jpg');
}
};
const handleWrite = async() =>{
if(state.title === ''){
alert('제목을 입력하세요.');
return false;
}
if(state.content === ''){
alert('내용을 입력하세요.');
return false;
}
if(state.writer === ''){
alert('작성자를 입력하세요.');
return false;
}
if(state.imgdata === ''){
alert('사진을 입력하세요.');
return false;
}
alert('작성이 완료 되었습니다.');
}
return {state, handleImage, handleWrite, editor}
}
}
</script>
<style lang="css">
.ck-editor__editable {
min-height: 500px;
}
</style>
=====================================================
파일명 src/component/main.vue
import { createApp } from 'vue'
import App from './App.vue'
// router 설정
import routes from './routes/index.js';
// stores 설정
import stores from './stores/index.js';
// element-plus 설정
import ElemtntPlus from 'element-plus';
import 'element-plus/theme-chalk/index.css'
//CKEditor
import CKEditor from '@ckeditor/ckeditor5-vue';
// 1. 객체 생성
const app = createApp(App);
// 2. 여기에 필요한 라이브러리 설정하기
app.use(routes);
app.use(stores);
app.use(ElemtntPlus);
app.use(CKEditor);
// 3. 마운트
app.mount('#app');
=====================================================
파일명 src/component/Board.vue
<template>
<div>
<h3>src/component/Board.vue</h3>
<table border="1">
<thead>
<tr>
<th>no</th>
<th>title</th>
<th>writer</th>
<th>hit</th>
</tr>
</thead>
<tbody>
<tr v-for="tmp in state.items.result" :key="tmp">
<td @click="handleBoardContent(tmp.no)">{{tmp.no}}</td>
<td>{{tmp.title}}</td>
<td>{{tmp.writer}}</td>
<td>{{tmp.hit}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { onMounted, reactive } from 'vue';
import { useRouter } from 'vue-router';
export default {
setup () {
const router = useRouter();
const state = reactive({
items : {},
});
// 생명주기 onMounted()
onMounted(() => {
// 백엔드로 데이터를 받음
state.items.result = [
{ no:1, title:'가1', writer :'b', hit:14},
{ no:2, title:'가2', writer :'c', hit:24},
{ no:3, title:'가3', writer :'d', hit:34},
];
console.log(state.items.result);
});
// function handleBoardContent(no) { }
const handleBoardContent = (no) =>{
console.log(no);
// 127.0.0.1:3000/boardcontent?no=2
router.push({name:"BoardContent", query:{no:no}});
}
return {state, handleBoardContent}
},
}
</script>
<style lang="scss" scoped>
</style>
=====================================================
파일명 src/components/boardcontent
<template>
<div>
<h3>src/components/boardcontent</h3>
{{state}}
</div>
</template>
<script>
import { reactive } from 'vue';
import { useRoute } from 'vue-router';// query 받기
export default {
setup () {
const route = useRoute();
const state = reactive({
no : route.query.no
})
return {state}
}
}
</script>
<style lang="scss" scoped>
</style>
=====================================================
파일명 src/component/Home.vue
<template>
<div>
<h3>src/component/Home.vue</h3>
<vueper-slides autoplay>
<vueper-slide v-for="tmp in state.slides" :key="tmp" :title="state.title" :image="tmp.image"></vueper-slide>
</vueper-slides>
</div>
</template>
<script>
import { VueperSlides, VueperSlide } from 'vueperslides';
import 'vueperslides/dist/vueperslides.css';
export default {
components:{
VueperSlides, VueperSlide
},
setup () {
const state = {
slides : [
{ title : 'a', image : 'https://picsum.photos/500/300?image=1'},
{ title : 'b', image : 'https://picsum.photos/500/300?image=2'},
{ title : 'c', image : 'https://picsum.photos/500/300?image=3'},
{ title : 'd', image : 'https://picsum.photos/500/300?image=4'},
{ title : 'e', image : 'https://picsum.photos/500/300?image=5'},
]
}
return { state }
}
}
</script>
<style lang="scss" scoped>
</style>
=====================================================
파일명 src/component/BoardTest.vue
<template>
<div>
<h3>src/component/BoardTest.vue</h3>
{{state}}
<QuillEditor theme="snow" toolbar="full" v-model:content="state.content" style="height:500px"/>
</div>
</template>
<script>
// 참고 : https://vueup.github.io/vue-quill/
// CMD> npm install @vueup/vue-quill@beta --save
import { reactive } from 'vue';
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css';
export default {
components: {
QuillEditor
},
setup () {
const state = reactive({
content : ''
});
return {state}
}
}
</script>
<style lang="scss" scoped>
</style>