JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/autosize.js/3.0.20/autosize.min.js"></script>
<div id="app">
<div class="container">
<div class="input-container">
<input type="text" placeholder="標題" v-model.trim="title">
<textarea
placeholder="新增記事..."
v-model.trim="content"
ref="content"
></textarea>
<select class="color" v-model="color">
<option value="" selected disabled>請選擇顏色</option>
<option value="red">紅色</option>
<option value="green">綠色</option>
<option value="blue">藍色</option>
</select>
</div>
<button class="addBtn" @click="add">新增</button>
</div>
<div class="notes">
<div
class="note"
v-for="(note, index) of notes"
:style="{ 'background-color': note.color }"
:key = note.title
>
<h3 class="title">
{{ note.title }}
</h3>
<p class="content">
{{ note.content}}
</p>
<button class="deleteBtn" @click="del(index)">✖</button>
</div>
</div>
</div>
CSS
* {
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #202124;
}
#app {
padding: 20px;
}
.container {
display: flex;
justify-content: center;
max-width: 600px;
margin: 0 auto 20px;
}
.input-container {
display: flex;
flex-direction: column;
width: 500px;
}
.addBtn {
flex-shrink: 0;
border: 1px solid #5f6368;
color: #5f6368;
border-left: none;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
cursor: pointer;
padding: 0 16px;
transition: color 0.2s;
font-size: 18px;
font-weight: bold;
}
.addBtn:hover {
color: #fff;
white-space: nowrap;
}
input, textarea, .color {
padding: 12px 16px;
border: 1px solid #5f6368;
outline: none;
box-shadow: none;
color: #fff;
border-right: none;
}
input {
font-size: 16px;
font-weight: 500;
border-bottom: none;
border-top-left-radius: 8px;
}
textarea {
font-size: 14px;
/* height: 3rem; */
border-top: none;
border-bottom: none;
resize: none;
/* overflow: hidden; */
}
.color {
border-top: none;
border-bottom-left-radius: 8px;
cursor: pointer;
}
.notes {
display: grid;
grid-template-columns: repeat(auto-fit, 240px);
grid-gap: 16px;
justify-content: center;
}
.note {
width: 240px;
border: 1px solid #5f6368;
border-radius: 8px;
padding: 12px 16px;
font-size: 18px;
color: #fff;
position: relative;
}
.title {
background-color: transparent;
word-break: break-all;
}
.content {
margin-top: 4px;
background-color: transparent;
word-break: break-all;
}
.deleteBtn {
color: rgba(255, 255, 255, .7);
background-color: transparent;
border: none;
position: absolute;
font-size: 20px;
top: 5px;
right: 5px;
cursor: pointer;
transition: color .2s
}
.deleteBtn:hover {
color: #fff;
}
JavaScript
const { createApp } = Vue
createApp({
data() {
return {
title: '',
content: '',
color: '',
notes: [
{
title: "春節行程安排",
content: "吃飽睡,睡飽吃",
color: "red",
},
{
title: "工作待辦事項",
content: "詢問各家廠商報價",
color: "green",
},
{
title: "運動健身計畫",
content: "每天早上六點去健身",
color: "blue",
},
],
};
},
methods: {
add() {
if (this.title === '' || this.content === '' || this.color === '') return;
const newNote = {
title: this.title,
content: this.content,
color: this.color,
};
this.notes.push(newNote);
this.title = '';
this.content = '';
this.color = '';
},
del(index) {
this.notes.splice(index, 1);
}
},
watch: {
notes: {
handler() {
localStorage.setItem('notesData',JSON.stringify(this.notes));
},
deep: true,
}
},
mounted() {
this.notes[0].content = '多出門、到處走走、也要多運動';
if (localStorage.getItem('notesData')) {
this.notes = JSON.parse(localStorage.getItem('notesData'))
}
autosize(this.$refs.content);
},
}).mount('#app')