vue

 

vuejs + firebase 처음 시작하기

 

 

 => Vue Vuetify 페이징 처리Vue Vuetify 페이징 처리,정렬처리, 검색처리

 

vuetify 1.5

 

1. firebaseConfig.js  설정

export default {
    apiKey: "AIzaSyClfeff2N2rwyW8uqQd_5ly312-v-3JKvnRyxLmMHg",
    authDomain: "test3213-455cc.firebaseapp.com",
    projectId: "tes3t-455332cc",
    storageBucket: "te3st-455cc2.appspot.com",
    messagingSenderId: "193241221312359154",
    appId: "1:19233241259154:web:c21d32a5d1c87e30fe501a4b",
    measurementId: "G-78RXX53213PSJT"
}

 

 

 

2. import 및 crud 파일 firebase.js 

여기서는 plugins 디렉토리 에 생성하였다.

import Vue from 'vue'
import { initializeApp } from 'firebase/app';
import firebase from "firebase/app";
import { query, orderBy, startAfter, limit, endBefore, limitToLast } from "firebase/firestore";
import { getFirestore, collection, getDocs, serverTimestamp, addDoc, doc, getDoc, updateDoc, deleteDoc,setDoc  } from 'firebase/firestore';
import firebaseConfig from '../../firebaseConfig.js';
import { head } from 'lodash'

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);




//collectionName => table 이름
//firebase 저장하기
async function fbWrite(collectionName, objData) {

    //firebase 데이터 저장 - addDoc 일경우 아이디가 자동 생성
    await addDoc(collection(getFirestore(), collectionName), objData);
    
    // 전체등록 갯수 가져오기
    const docRef = doc(db, collectionName + "_totalCount", "tot_id");
    const totNum = await getDoc(docRef);

    //전체등록 갯수 업데이트   // totNum.exists() 존재할 경우 업데이트 처리 - 카운트 증가처리  :   없으면 1 로 최초등록
    await setDoc(doc(db, collectionName + "_totalCount", "tot_id"), {
        totalCount: totNum.exists() ? totNum.data().totalCount + 1 :  1,
        upDate: serverTimestamp()
    });

}


//firebase 삭제하기
async function fbDelete(collectionName, id) {
    await deleteDoc(doc(db, collectionName, id));

    // 전체등록 갯수 가져오기
    const docRef = doc(db, collectionName + "_totalCount", "tot_id");
    const totNum = await getDoc(docRef);

    //전체 갯수 업데이트   // totNum.docs[0] 값이 없을 경우 최초 등록으로 1 , 존재할 경우 업데이트 처리 - 카운트 감소
    await setDoc(doc(db, collectionName + "_totalCount", "tot_id"), {
        totalCount: totNum.data().totalCount > 0 ? totNum.data().totalCount - 1 : 0,
        upDate: serverTimestamp()
    });
}



//firebase 수정하기
async function fbUpdate(collectionName, objData) {    
    const updateData = doc(db, collectionName, objData.id);
    await updateDoc(updateData, objData);
}



//firebase 한개의 데이터 가져오기
async function fbGetData(collectionName, id) {
    const docRef = doc(db, collectionName, id);
    return await getDoc(docRef);
}


// firebase 데이터 목록 가져오기
async function fbGetList(collectionName) {
    const querySnapshot = await getDocs(collection(db, collectionName));
    return querySnapshot;
}


// firebase query 데이터 목록 가져오기
async function fbGetQueryList(collectionName, culum, order, pageSize, documentSnapshots,  currentPage, beforPage ) {
    //1. 첫 페이지일 경우
    if (currentPage==undefined ||currentPage == 1) {
        //1.첫페이지일 경우
        const first = query(collection(db, collectionName),           
            orderBy(culum, order),        
            limit(pageSize));
        
        const documentSnapshots2 =await getDocs(first);
        return documentSnapshots2;
    }
    

    if (beforPage <= currentPage) {
        
        //2.next 다음 페이지로 이동
        const lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1];
   
        if (documentSnapshots.size == 0) {
            return;
        }

        const next = query(collection(db, collectionName),
            orderBy(culum, order),
            startAfter(lastVisible),
            limit(pageSize));
        const documentSnapshots2 = await getDocs(next);

        return documentSnapshots2;


    } else {
        //3.이전 페이지로 이동

        const prevVisible = documentSnapshots.docs;

        const before = query(collection(db, collectionName),
            orderBy(culum, order),            
            endBefore(head(prevVisible)),
            limitToLast(pageSize+1)            
        );
        const documentSnapshots2 = await getDocs(before);

        return documentSnapshots2;
    }
   
}




//전역변수로 사용 설정
Vue.prototype.$firebase = firebase

Vue.prototype.$fbWrite = fbWrite
Vue.prototype.$fbUpdate = fbUpdate
Vue.prototype.$fbGetList = fbGetList
Vue.prototype.$fbGetQueryList = fbGetQueryList

Vue.prototype.$fbDelete = fbDelete
Vue.prototype.$fbGetData = fbGetData

Vue.prototype.$db = db
Vue.prototype.$getFirestore = getFirestore
Vue.prototype.$collection = collection
Vue.prototype.$getDocs = getDocs
Vue.prototype.$serverTimestamp = serverTimestamp
Vue.prototype.$addDoc = addDoc
Vue.prototype.$doc = doc
Vue.prototype.$getDoc = getDoc
Vue.prototype.$updateDoc = updateDoc
Vue.prototype.$deleteDoc = deleteDoc
 

 

 

3. 뷰 파일 (ex notes.vue)

<template>
  <v-container fluid grid-list-md class="mt-15">
    <v-layout>
        <v-card  style="padding:10px">
            전체:<span v-text="totalCount"></span> 개  
        </v-card>        
    </v-layout>

 
      <v-layout> 
        <v-flex xs5>
            <v-text-field v-model="title" label="title"></v-text-field>   
        </v-flex>   
        <v-flex xs5>
            <v-text-field v-model="content" label="content"></v-text-field>   
        </v-flex>  
        <v-flex xs2>
             <v-btn color="success"  @click="fbWrite" >등록하기</v-btn>
        </v-flex>   
    </v-layout>   



      <v-data-iterator
        :items="items"
        content-tag="v-layout"
        row
        wrap
      hide-default-footer
      >
      <template v-slot:item="props">
        <v-flex xs12 sm6 md4 lg3 >
          <v-card>
            <v-card-title><h4>{{props.item.title}}</h4></v-card-title>
            <v-card-title><h6>{{props.item.id}}</h6></v-card-title>
            <v-divider></v-divider>
            <v-card-text>
                {{props.item.content}}
            </v-card-text> 
  
            <v-card-actions>
                    <v-spacer></v-spacer>
                    <!-- <v-btn @click="fbUpdate(props.item)">수정하기</v-btn> -->
                    <v-btn icon @click="openDialog(props.item)"><v-icon>mdi-pencil</v-icon></v-btn>
                    <v-btn icon @click="fbDelete(props.item)"><v-icon>mdi-delete</v-icon></v-btn>

            </v-card-actions>   


          </v-card>
        </v-flex>
      </template>
    </v-data-iterator>



      <v-layout mt-5>
            <v-flex xs12 sm4 md4>              
                <v-select
                  v-model="pageSize"
                  :items="pageSizes"
                  label="페이지 당 항목"
                  @change="handlePageSizeChange"
                ></v-select>
            </v-flex>

            <!-- <v-flex xs12 sm8 md8 >
                <v-pagination
                 v-model="currentPage"
                 :length="totalPage"
                  total-visible="0"
                  next-icon="mdi-menu-right"
                  prev-icon="mdi-menu-left"
                  circle
                ></v-pagination>                 
            </v-flex> -->
            <!-- @input="getList" -->
            
            <div>
              <v-btn small color="primary" @click="prevBtn"  :disabled="prevBtnDisable" >prev</v-btn>
            </div>
            <div>
              <v-btn small color="primary" @click="nextBtn" :disabled="nextBtnDisable" >next</v-btn>
            </div>
     </v-layout>

   


     <v-dialog max-width="500" v-model="dialog">
      <v-card>
        <v-form>
          <v-card-text>
            <v-text-field v-model="detail.id" readonly></v-text-field>
            <v-text-field v-model="detail.title"></v-text-field>
            <v-text-field v-model="detail.content"></v-text-field>
          </v-card-text>
          <v-card-actions>
            <v-spacer/>
            <v-btn @click="fbUpdate()">수정하기</v-btn>
          </v-card-actions>
        </v-form>
      </v-card>
    </v-dialog>
    
  </v-container>
</template>

<script>
  export default {
    data: () => ({
      //collectionName- 테이블 이름
      collectionName:"messages",

      // rowsPerPageItems: [4, 8, 12],
      // pagination: {
      //   rowsPerPage: 4
      // },
      items: [],
      title:'',
      content:'',
      messages:[],
    
      detail: {
        id:'',
        title: '',
        content: ''
      },

      dialog: false,
      prevBtnDisable:true,
      nextBtnDisable:false,

      documentSnapshots:null,
      documentSnapshotsFirst:null,

      totalCountId:null,
      totalCount:0,      
      currentPage:1,
      totalPage:6,

      pageSize: 3,
      pageSizes: [3, 6, 9],

    })
    ,
    mounted(){
       this.getList();
    },
 
  watch: {
      // currentPage 변경될 때 마다 이 기능이 실행
      currentPage: function (curPage, beforPage) {

          this.getList(beforPage);
          if(this.currentPage<=1){
              this.prevBtnDisable=true;
          }else{
             this.prevBtnDisable=false;
          }
      },

    },
  
    methods:{
        //firebase 데이터 넣기
        async fbWrite(){ 
           const objData= {              
              title: this.title,
              content: this.content,
              regDate:this.$serverTimestamp()
            }
          
            await this.$fbWrite(this.collectionName ,objData);             
            this.getList();
        },

       //firebase 데이터 수정하기
       async fbUpdate(){           
            const objData= {
              id :this.detail.id,
              title: this.detail.title,
              content: this.detail.content,
              upDate:this.$serverTimestamp()
            }

            await this.$fbUpdate(this.collectionName, objData );            
            this.getList();
            this.dialog = false;
       },

        prevBtn(){
          this.currentPage=this.currentPage-1;
        },
        nextBtn(){
          this.currentPage=this.currentPage+1;
        },

        // firebase 데이터 목록 가져오기
        async getList(beforPage){   
            this.title="";
            this.content=""; 
            this.items=[];
            
            await this.totalCountData(); 
            this.pageDataSetting(this.totalCount, this.pageSize);

            
          // const querySnapshot = await this.$fbGetList("messages");
            const documentSnapshots = await  this.$fbGetQueryList(this.collectionName, "regDate", "desc", this.pageSize , this.documentSnapshots, this.currentPage,beforPage );  
            this.documentSnapshots=documentSnapshots;
            if(this.currentPage==1){
              this.documentSnapshotsFirst=documentSnapshots;
            }

             documentSnapshots.forEach((doc) => {
             this.items.push({
                id: doc.id, 
                title: doc.data().title,
                content: doc.data().content
            });


        });

      },

        //한개 데이터 가져오기
        async getData(id){  //eslint-disable-line
          return await this.$fbGetData(this.collectionName, id);          
        },


        // 전체 갯수 가져오기
        async totalCountData(){
            const totNum = await this.$fbGetList(this.collectionName+"_totalCount");  
            totNum.forEach((doc) => {
                this.totalCountId=doc.id,
                this.totalCount=doc.data().totalCount
            })                             
        },


      //삭제
       async fbDelete(item){
            if(confirm("정말 삭제 하시겠습니까?")){
              await this.$fbDelete(this.collectionName, item.id);  
              this.getList();
            }                     
       },

      //dialog 오픈 글상세보기
      async openDialog (item) {
          this.dialog = true
          // console.log(item);
          this.detail.id=item.id;
          this.detail.title=item.title;
          this.detail.content=item.content;
          // console.log("openDialog : " +item.id);
          // const getData=await this.getData(item.id);
          // this.detail.id=item.id;
          // this.detail.title=getData.data().title;
          // this.detail.content=getData.data().content;
      }

      , 
       //전체 페에지 갯수 구하기
       pageDataSetting(total, limit) {
          this.totalPage = Math.ceil(total / limit);
          console.log("현재/전체 :" +this.currentPage + "/ " +this.totalPage);
          if(this.currentPage==this.totalPage){
            this.nextBtnDisable=true;
          }else{
            this.nextBtnDisable=false;
          }
          
       }
    ,

     handlePageSizeChange(size) {
          this.pageSize = size;
          this.currentPage = 1;
          this.getList();
      },


    }
  }
</script>

 

 

소스 :  https://github.com/braverokmc79/vf

 

 


 

 

 

 

about author

PHRASE

Level 60  라이트

군자는 행동은 지나칠 만큼 공손한 태도를 취하고 상사(喪事)가 있을 때에는 허례를 버리며, 애도하는 마음에 치중하고 모든 비용은 지나칠 만큼 검소하게 한다. 이 세 가지는 지나칠 정도로 해도 아직 미치지 못하는 것이다. -역경

댓글 ( 4)

댓글 남기기

작성












vue 목록    more