vue

 

 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue3</title>
    <script src="https://unpkg.com/vue@next"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <style>
        .board_container{
            margin: 20px;
        }
        .v-move{
            transition: transform 1s;
        }
       textarea:active, textarea:focus, input:active, input:focus, .btn:active, .btn:focus { outline: none !important; 
            box-shadow: none !important;        
        } 

    </style>
</head>
<body>









    <div id="app">


        <div class="board_container">
            <div class="row">
              <div class="col-md-10  offset-md-1 text-center">
                <h2>게시판 만들기</h2>
      

                <p>json 파일 읽기</p>
                <input type="file" @change="loadData">
                <button @click="saveBoardList">게시판 저장</button>
        </div>
    </div>
    </div>

        <my-board-list  
            v-if="listOk"
            :object="boardObject" 
            @board-read="boardRead"
            @board-write="boardWrite"
            @board-delete="boardDelete"
        ></my-board-list>

        <my-board-read 
            v-if="readOk"
            :object="boardInfo"
            @board-list="boardList" 
        ></my-board-read>


       <my-board-write
        v-if="writeOk"
        @board-list="boardList"
        @board-save="boardSave"
       ></my-board-write>


    </div>



<script>
    const MyBoardList={
        props:['object'],
        template:`        
        <div class="board_container">
            <div class="row">   
                <div class="col-md-10 offset-md-1">
                    <table id="list" class="table table-striped text-center ">
                        <thead>
                        <tr>
                            <th>글번호</th>
                            <th>제목</th>
                            <th>조회수</th>
                            <th></th>
                        </tr>
                        </thead>
                        <tbody>
                            <tr v-if="object.length==0">
                                <td colspan="4"> 등록된 글이 없습니다.</td>
                            </tr>
                            <tr v-else v-for="(item , index) in object" :key="item.no" >
                                <td>{{item.no}}</td>
                                <td @click="boardRead(item)">{{item.title}}</td>
                                <td>{{item.view}}</td>
                                <td>
                                    <button @click="boardDelete(item.no)" class="btn btn-danger">삭제</button>
                                </td>
                            </tr>
                        </tbody>
                        <tfoot>
                            <tr>
                                <td colspan="4" style="text-align: right;">
                                    <button @click="boardWrite" class="btn btn-success">글쓰기</button>
                                </td> 
                            </tr>
                        </tfoot>
                        </table>
                </div>     
            </div>
        </div>       
        `
        ,
       methods :{
            boardRead(item){
               this.$emit('board-read', item);
            },

            boardWrite(){
                this.$emit('board-write');
            },

            boardDelete(no){
                this.$emit('board-delete', no);
            }
       }

    };



    const MyBoardRead={

        props:['object'],
        template:`
        <div class="board_container">
        <div class="row">   
            <div class="col-md-10 offset-md-1">
                <table id="list" class="table">                
                    <tbody>
                    <tr class="border">
                        <th class="border">글제목</th>
                        <td class="text-left">{{object.title}}</td>
                    </tr>
                    <tr>
                        <td colspan="2">
                            {{object.content}}
                        </td>
                    </tr>  
                </tbody>
                <tfoot>
                    <tr>
                        <td colspan="2" style="text-align: right;border-bottom: none;">
                            <button  @click="boardList"   class="btn btn-success">목록</button>
                        </td>
                    </tr>
                </tfoot>              
                </table>            
            </div>         
        </div>
    </div>
            
        `
        ,
        methods:{
            boardList(){
                this.$emit('board-list');
            }
        }
    }



    const MyBoardWrite={
        data(){
            return{
                title:"",
                content:""
            }
        },
        template:`
            
<div class="board_container">
    <div class="row">   
       <div class="col-md-10 offset-md-1">
           <table id="list" class="table">                
               <tbody>
               <tr class="border">
                   <th class="border">글제목</th>
                   <td class="text-left">
                       <input v-model="title" class="form-control">
                   </td>
               </tr>
               <tr>
                   <td colspan="2">
                       <textarea v-model="content" cols="10" style="width: 100%;"
                        rows="10" class="form-control"
                       ></textarea>                      
                   </td>
               </tr>  
           </tbody>
            <tfoot>
                <tr>
                    <td colspan="2" style="text-align: right;border-bottom: none;">
                       <button @click="boardList" class="btn btn-success">목록</button>&nbsp;
                       <button @click="boardSave" class="btn btn-primary">저장</button>
                    </td>
                </tr>
            </tfoot>              
           </table>            
        </div>         
   </div>
</div>

        `,
     
        methods:{
            boardList(){
                this.$emit('board-list');
            },

            boardSave(){
                this.$emit('board-save', this.title, this.content);
            }

        }
    }



    const app = {
        data() {
            return {

                boardObject:[
                    // {"no":1, "title" :"첫번째글","content":"첫번째 글 내용", "view":1},
                    // {"no":2, "title" :"두번째글","content":"두번째 글 내용", "view":0},
                    // {"no":3, "title" :"세번째글","content":"세번째 글 내용", "view":3}
                ],
                boardInfo:{},
                listOk:true,
                readOk:false,
                writeOk:false
            }
        },
        components: {
            'my-board-list':MyBoardList,
            'my-board-read':MyBoardRead,
            'my-board-write':MyBoardWrite
        },
            
        methods: {
            loadData(e){
                const file =e.target.files[0];
                if(file){
                    const reader =new FileReader();
                    let parentThis=this;
                    reader.onload=function(e){
                        const json=JSON.parse(e.target.result);
                        parentThis.boardObject=json;
                    };  
                    reader.readAsText(file);             
                }

            },

            saveBoardList(){
             
                let data = this.boardObject;

                if(data.length == 0) {
                    alert('저장할 게시판 내용이 없습니다.')
                    return;
                }
                const filename = 'board.json';

                if(typeof data === "object"){
                    data = JSON.stringify(data, undefined, 4);
                }

                const blob = new Blob([data], {type: 'text/json'}),
                    e    = document.createEvent('MouseEvents'),
                    a    = document.createElement('a');

                a.download = filename;
                a.href = window.URL.createObjectURL(blob);
                a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':');
                e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                a.dispatchEvent(e);

            }
            ,
            boardRead(boardInfo){

                for(let i=0; i<this.boardObject.length; i++){
                    if(this.boardObject[i].no==boardInfo.no){

                        let updateData={
                            "no":this.boardObject[i].no,
                            "title":this.boardObject[i].title,
                            "content":this.boardObject[i].content,
                            "view":this.boardObject[i].view+1,
                        }
                        this.boardObject.splice(i, 1,updateData);
                        break;
                    }
                }  

                this.boardInfo=boardInfo;
                this.listOk=false;
                this.readOk=true;
            }
            ,
            boardList(){
                this.listOk=true;
                this.writeOk=false;
                this.readOk=false;
            },

            boardWrite(){
                this.listOk=false;
                this.writeOk=true;
            },

            boardSave(title, content){
                let lastNo=0;
                if(this.boardObject.length!=0){
                    //마지막 번호 가져오기
                    lastNo=this.boardObject[this.boardObject.length-1].no                
                }
                
                const data={
                    "no":lastNo+1,
                    "title":title,
                    "content":content,
                    "view":0
                }
                this.boardObject.push(data);
                this.boardList();
            },

            boardDelete(no){            
                for(let i=0; i<this.boardObject.length; i++){
                    if(this.boardObject[i].no==no){
                        this.boardObject.splice(i, 1);
                        break;
                    }
                }                
            }
        },
    }

    Vue.createApp(app).mount('#app');  
    
</script>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>

 

 

about author

PHRASE

Level 60  라이트

Like master, like man. (그 상전에 그 종

댓글 ( 4)

댓글 남기기

작성