실시간 멀티 접속 테스트
파이이베이스 db와 연결하기 위해
파이어베이스 sdk와 뷰파이어 플러그인 패키지 설치
npm install firebase vuefire@next
@next 의미는 v2.0이상 의미함
Vue-CLI 사용하는 워크박스 :
index.html, *css, *js, *txt를 자동으로 캐시함
- 플러그인 모드 :
GenerateSW (자동으로 생성되는 서비스 워커에 워크박스 옵션 지정)
InjectManifest (서비스 워커에 자신의 코드를 직접 넣어 최종 서비스 워커 파일 생성)
-캐시 :
프리 캐시 (실행하기 전에 미리 지정)
런타임 캐시 (프로그램 실행할때 원하는 부분만 지정)
--캐시전략
(Network-First, Cache-First, Stale-while-revalidate, Network-Only, Cache-Only)
// generateSW 모드
module.exports = {
pwa: {// 생략가능
workboxPluginMode: 'GenerateSW',
workboxOptions: {
// 프리캐시 옵션 지정
runtimeCaching: [{
// 런타임 캐시 옵션 지정
}]
}
}
}
// injectManifest 모드
module.exports = {
pwa: {// 생략가능 불가능 반드시 지정
workboxPluginMode: 'InjectManifest',
workboxOptions: {
// 서비스 워커 파일을 꼭지정
swSrc: 'src/serviceworker.js',
}
}
}
module.exports = {
pwa: {
workboxOptions: {
include: [/^index\.html$/, /\.css$/, /\.js$/, /^manifest\.json$/, /\.png$/],
exclude:[]
}
}
}
include: 프리캐시에서 사용할 파일을 지정
exclude: 프리캐시에서 제거할 파일을 지정
제거할것이 없어도 반드시 명시해야한다.
규칙은 테스트 모드로
<template>
<v-app>
<!-- 전체 영역을 카드ui로 변경하여 색상의 일관성을 유지 -->
<v-card>
<v-app-bar dark color="lime">
<v-app-bar-nav-icon></v-app-bar-nav-icon>
<v-toolbar-title>To-Do 리스트</v-toolbar-title>
</v-app-bar>
<v-content>
<v-container>
<v-row my-5>
<v-col cols="8" offset="1">
<!-- 실행되자마자 입력 포커스를 가지도록 autofocus 설정 -->
<v-text-field label="할 일" autofocus v-model="sTodoTitle">
</v-text-field>
</v-col>
<v-col cols="2" my-2>
<v-btn
fab
max-height="50px"
max-width="50px"
color="pink"
dark
@click="fnSubmitTodo()"
>
<v-icon>add</v-icon>
</v-btn>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-list two-line v-for="item in oTodos" :key="item.key">
<!-- item.b_edit 값을 통해 읽기 모드인 경우만 표시 -->
<v-card flat color="grey lighten-3" v-if="!item.b_edit">
<!-- 항목을 하나씩 가져와서 title 단위로 표시 -->
<v-list-item class="py-2">
<v-list-item-action>
<!-- 체크박스 표시하고 선택되면 변경 상태를 DB에 저장 -->
<v-checkbox
v-model="item.b_completed"
@change="fnCheckboxChange(item)"
></v-checkbox>
</v-list-item-action>
<!-- 제목 표시 체크선택시 취소선 표시 -->
<v-list-item-content>
<v-list-item-title :class="{'style_completed': item.b_completed}">
{{ item.todo_title }}
</v-list-item-title>
<!-- 두번째 줄에 아이콘 배치 -->
<v-list-item-subtitle class="mt-2">
<!-- 수정 아이콘 표시하고 클릭하면 수정모드로 변경함 -->
<v-icon class="pointer" @click="fnSetEditTodo(item['.key'])">create</v-icon>
<!-- 삭제 아이콘 표시하고 클릭하면 해당 item 삭제 -->
<v-icon class="pointer" @click="fnRemoveTodo(item['.key'])">delete</v-icon>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-card>
<!-- item.b_edit값을 통해 수정모드인 경우 어둡게 표시 -->
<v-card v-else dark>
<v-list-item class="py-2">
<v-list-item-action>
<v-checkbox v-model="item.b_completed"></v-checkbox>
</v-list-item-action>
<!-- v-list-item안에서 텍스트입력과 버튼 사용을 위해
v-card 엘리먼트 사용 -->
<v-card-text>
<!-- 포커스를 입력창으로 바로 옮기고 삭제 아이콘도 추가함 -->
<v-text-field autofocus clearable v-model="item.todo_title"></v-text-field>
</v-card-text>
<v-card-actions>
<!-- 수정모드에서 '저장' 아이콘 클릭하면 해당 item 저장 -->
<v-icon class="pointer" @click="fnSaveEdit(item)">save</v-icon>
<!-- 수정모드에서 '취소' 아이콘 클릭하면 취소하고 읽기모드로
돌아감 -->
<v-icon class="pointer" @click="fnCancelEdit(item['.key'])">cancel</v-icon>
</v-card-actions>
</v-list-item>
</v-card>
</v-list>
</v-col>
</v-row>
</v-container>
</v-content>
</v-card>
</v-app>
</template>
<script>
// 파이어베이스 DB 가져옴
import {
oTodosinDB
} from '@/datasources/firebase'
export default {
name: 'App',
data: () => ({
oTodos: [], // 할일 데이터 목록 저장 변수
sTodoTitle: '' // 할 일 제목 저장 문자열 변수
}),
// 파이어베이스를 쉽게 사용하도록 oTodos 변수로 변경
firebase: {
oTodos: oTodosinDB
},
methods: {
// 할 일 제목, 완료, 수정모드 상태값을 DB에 저장
fnSubmitTodo() {
oTodosinDB.push({
todo_title: this.sTodoTitle,
b_completed: false,
b_edit: false
})
this.sTodoTitle = ''
},
// 전달된 할 일을 DB에서 제거
fnRemoveTodo(pKey) {
oTodosinDB.child(pKey).remove()
},
// 전달된 할 일의 b_edit를 수정모드로 변경
fnSetEditTodo(pKey) {
oTodosinDB.child(pKey).update({
b_edit: true
})
},
// 전달된 할 일의 b_edit를 읽기모드로 변경
fnCancelEdit(pKey) {
oTodosinDB.child(pKey).update({
b_edit: false
})
},
// 전달된 할 일의 수정값을 DB에 저장
fnSaveEdit(pItem) {
const sKey = pItem['.key']
oTodosinDB.child(sKey).set({
todo_title: pItem.todo_title,
b_completed: pItem.b_completed,
b_edit: false
})
},
// 첵크박스 선택되면 DB에 b_completed 변경값 저장
fnCheckboxChange(pItem) {
const sKey = pItem['.key']
oTodosinDB.child(sKey).update({
b_completed: pItem.b_completed
})
}
}
};
</script>
<style>
.pointer {
/* 마우스포인터를 손모양으로 변경 */
cursor: pointer;
}
.style_completed {
/* 할 일의 제목을 취소선으로 변경 */
text-decoration: line-through;
}
</style>
<v-list-item-title :class="{'style_completed': item.b_completed}">
클래스 바인딩 : 현재 엘리먼트에 적용된 클래스가 선택자를 사용될지를
바인딩으로 결정하는 방법
item['.key']: 파이어베이스 고유키
class="pointer": 마우스가 근처에가면 손가락 모양으로 변경
@: src 폴더를 의미함
set(): 하위노드들에게도 업데이트 영향을 주게됨
module.exports = {
pwa: {
workboxOptions: {
runtimeCaching: [{
urlPattern: /\.png$/,
handler: 'cacheFirst',
options: {
cacheName: 'png-cache',
expiration: {
maxEntries: 10, // 총 파일 10개까지 캐시
maxAgeSeconds: 60 * 60 * 24 * 365, // 1년 캐시
}
}
},
{
urlPattern: /\.json$/,
handler: 'staleWhileRevalidate',
options: {
cacheName: 'json-cache',
cacheableResponse: {
statuses: [200]
}
},
}
],
}
},
devServer: {
disableHostCheck: true
}
}
handler: 5가지 캐시 전략 중 하나선택
urlPattern: 정규식 사요해서 캐시하려는 파일 또는 url 경로 지정
Options
-cahceName: 개발자 도구에 표시할 캐시 제목(중복 주의)
-expiration: 캐시제약 지정(maxEntries: 캐시할 개수, maxAgeSeconds: 캐시가 유지될 총 시간)
-cacheableResponse: HTTP 응답 코드를 통해 캐시 여부 결정
export default {
aPictures: [{
'id': 1,
'url': 'https://farm1.staticflickr.com/654/22663129542_e3df218c90_b.jpg',
'title': '청춘플랫폼_우수부스투표',
'info': '졸업작품 전시회에 출품한 작품 중에서 방문자들이 직접 우수 전시 부스를 투표로 선정하는 모습입니다.'
},
{
'id': 2,
'url': 'https://farm1.staticflickr.com/739/22663128752_7b347e01a9_b.jpg',
'title': '전시장모습',
'info': '전시가 열렸던 예술의 전당 전시실 안의 모습입니다. '
},
{
'id': 3,
'url': 'https://farm1.staticflickr.com/674/22055529403_aeeb5fc371_b.jpg',
'title': 'pc실습실',
'info': '윈도우OS 환경에서 다양한 멀티미디어디자인 S/W를 실습하는 공간입니다.'
},
{
'id': 4,
'url': 'https://farm1.staticflickr.com/706/22650669476_d8bf33c153_b.jpg',
'title': '졸업작품전시회 주제',
'info': '청춘 플랫폼이라는 주제로 젊은 열정이 펼쳐지는 무대가 마련되었습니다.'
},
{
'id': 5,
'url': 'https://farm1.staticflickr.com/677/22055530223_91e3f73227_b.jpg',
'title': '명함디자인',
'info': '자신의 미래 모습을 담은 명함을 직접 디자인하고 인쇄 제작하여 전시한 모습입니다.'
},
{
'id': 6,
'url': 'https://farm1.staticflickr.com/777/22650669326_e180cd84ca_b.jpg',
'title': '전시_방명록',
'info': '전시장을 방문한 관객들의 다양한 소감을 방명록의 기록으로 남겨졌습니다.'
},
{
'id': 7,
'url': 'https://farm1.staticflickr.com/759/22687855771_92dc8b3245_b.jpg',
'title': '매킨토시 실습실',
'info': '맥OS 환경에서 멀티미디어디자인 관련 S/W를 사용하여 작업하기 위한 맥 실습실입니다.'
},
{
'id': 8,
'url': 'https://farm6.staticflickr.com/5646/22053918354_ee031eae46_b.jpg',
'title': '캘리그래피_디자인',
'info': '학생들이 직접 디자인한 아날로그 정서의 캘리그래피 작품입니다.'
},
{
'id': 9,
'url': 'https://farm1.staticflickr.com/762/22687856291_963df9b90a_b.jpg',
'title': '실습실복도',
'info': '전공존에 따라 색상이 그룹으로 연결된 실습실 복도 모습입니다.'
},
{
'id': 10,
'url': 'https://farm1.staticflickr.com/766/22055529593_c162dc3143_b.jpg',
'title': '인터뷰_촬영',
'info': '졸업작품을 준비한 학생들의 과정을 인터뷰의 기록으로 남기는 모습입니다. '
},
{
'id': 11,
'url': 'https://farm6.staticflickr.com/5775/22053918014_f0e0873b7c_b.jpg',
'title': '전시_메모',
'info': '관객들이 전시를 보면서 느낀 점을 간단한 메모의 글로 남긴 흔적입니다.'
},
{
'id': 12,
'url': 'https://farm6.staticflickr.com/5672/22055530083_8f633d57f3_b.jpg',
'title': '종이컵_캘리그래피',
'info': '종이컵을 캔버스 삼아 학생들의 자유로운 생각을 캘리그래피의 작품으로 제작한 종이컵 아트워크입니다.'
}
]
}
외부에서 로컬 주소로 모바일로 접속하는 방법