Skip to content

Instantly share code, notes, and snippets.

@3t14
Last active August 6, 2020 03:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 3t14/a1d766d8214ddf9853fc2b9d24b06cc1 to your computer and use it in GitHub Desktop.
Save 3t14/a1d766d8214ddf9853fc2b9d24b06cc1 to your computer and use it in GitHub Desktop.
クラウド簡易メモアプリ(ユーザー認証なし)完成版
<template>
<div id="app">
<navigation :memos="memos" @onNew="newMemo" @onOpen="openMemo"/>
<edit-memo :memo="currentMemo"
@onSave="saveMemo" @onDelete="deleteMemo"
/>
</div>
</template>
<script>
// import HelloWorld from './components/HelloWorld.vue'
import EditMemo from './components/EditMemo.vue'
import Navigation from './components/Navigation.vue'
export default {
name: 'app',
components: {
// HelloWorld
EditMemo,
Navigation
},
data() {
let currentMemo = {id: -1, title: 'Untitled', content:''};
let user = this.$auth.currentUser;
return {
memos: [],
maxMemoId: 0,
currentMemo,
user
}
},
methods: {
saveMemo() {
// ローカル関数定義(後に上書き時、更新時の処理で利用可能にするため)
let saveMemo2Cloud = (memo) => {
let memosRef = this.$db.collection('data/memoData/memos');
memosRef.where('id', '==', memo.id).get().then((querySnapshot) => {
if (querySnapshot.empty) {
memosRef.add(memo); // 対象のメモが存在しない時、追加
} else {
querySnapshot.docs[0].ref.set(memo); // 対象のメモが存在する時、上書き
}
});
}
if (this.currentMemo.id == -1) { // maxMemoIdを更新して追加
this.$db.doc('data/memoData').get().then((doc) => {
// maxMemoIdの値がnullならば0、存在する場合は値を1追加
let maxMemoId = (doc.data() == null || doc.data().maxMemoId == null)
? 0: doc.data().maxMemoId + 1;
if (maxMemoId == 0) {
// 初めてのアクセスの場合、ドキュメントを作成
doc.ref.set({maxMemoId: 0}).then(() => {
this.currentMemo.id = maxMemoId;
this.memos.push(this.currentMemo);
saveMemo2Cloud(this.currentMemo);
});
} else {
doc.ref.update('maxMemoId', maxMemoId).then(() => {
this.currentMemo.id = maxMemoId;
this.memos.push(this.currentMemo);
saveMemo2Cloud(this.currentMemo);
});
}
});
} else saveMemo2Cloud(this.currentMemo); // 上書き保存
},
newMemo() {
this.currentMemo = { id: -1, title: 'Untitled', content: ''};
},
openMemo(id) {
this.memos.forEach((memo) => {
if (memo.id == id) {
this.currentMemo = memo;
}
});
},
deleteMemo() {
let deleteIndex = -1;
// 削除する対象のインデックスを取得
for ( let i in this.memos ){
if (this.currentMemo.id == this.memos[i].id) {
deleteIndex = i;
}
}
if (deleteIndex != -1) {
if (confirm("本当に削除しますか?")) {
this.memos.splice(deleteIndex, 1);
this.$db.collection('data/memoData/memos')
.where('id', '==', this.currentMemo.id).get().then((querySnapshot => {
if (!querySnapshot.empty) {
querySnapshot.docs[0].ref.delete().then(() => {
this.newMemo(); // 新規メモを作成
});
}
}));
}
}
}
},
mounted() {
// Firestoreから非同期でmemosとmaxMemoIdの取得
this.$db.collection('data/memoData/memos').get().then((querySnapshot) => {
this.memos = [];
querySnapshot.forEach((doc) => {
this.memos.push(doc.data());
});
this.$db.collection('data/memoData/').get().then((doc) => {
this.maxMemoId = doc.data().maxMemoId;
});
});
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<div id="editMemo">
<ul>
<li>
<label>タイトル</label>
</li>
<li>
<input id="editMemoTitle" type="text" v-model="memo.title"/>
</li>
<li>
<label>メモ</label>
</li>
<li>
<textarea id="editMemoContent" v-model="memo.content">
</textarea>
</li>
<li >
<div class="buttons">
<button class="button" @click="$emit('onSave', memo)">保存する</button>
<button class="button" @click="$emit('onDelete', memo)">削除する</button>
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
name:"EditMemo",
props: {
memo: Object
}
}
</script>
<style>
#editMemo ul {
list-style-type: none;
display: flex;
flex-direction: column;
align-items: center;
padding: 1em;
}
#editMemo ul li {
display: inline-flex;
width: 100%;
margin: 0em;
padding: 0em;
}
#editMemoTitle {
flex: 1;
}
#editMemoContent {
flex: 1;
height: 20em;
resize: none;
}
#editMemo .buttons {
display: flex;
justify-content: space-evenly;
align-items: center;
flex: 1;
}
#editMemo .button {
margin: 1em;
width: 8em;
}
</style>
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// Firebaseの初期化
import firebase from 'firebase'
import 'firebase/firestore'
// 以下の引数は自身の環境のものを代入してください。
firebase.initializeApp({
apiKey: 'APIキー',
authDomain: '認証ドメイン',
projectId: 'プロジェクトID'
});
const db = firebase.firestore();
// どこからでもすぐにFirebaseにアクセスできるように$dbに格納
// Vueインスタンスの中ではthis.$dbで参照可能に
Vue.prototype.$db = db;
new Vue({
render: h => h(App),
}).$mount('#app')
<template>
<div id="nav">
<ul>
<li>📝簡易メモ帳</li>
<li><button @click="$emit('onNew')">新規作成</button></li>
<li>
<select v-model="selectedId">
<option v-for="memo in memos" :key="memo.id" :value="memo.id">
{{memo.title}}
</option>
</select>
<button @click="$emit('onOpen', selectedId)">を開く</button>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Navigation',
props: {
memos: Array,
},
data() {
return {
selectedId: -1
}
}
}
</script>
<style>
#nav {
width: 100%;
}
#nav ul {
list-style-type: none;
border-bottom:lightgray 1px solid;
padding: 1em;
display: flex;
justify-content: space-evenly;
width: 100%;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment