JavaScript 系列七:第7課 ── 認識 Template Refs
by applelily
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript 系列七:第7課 ── 認識 Template Refs</title>
<link rel="stylesheet" href="./07_js_vue_Template-Refs.css">
</head>
<body>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">
<div class="input_content">
<div class="input_group">
<div class="label">標題</div>
<input class="input_area" type="text" placeholder="標題" v-model="newNote.title">
</div>
<div class="input_group">
<div class="label">記事</div>
<!-- 在 textarea 元素上设置 ref 来引用它 -->
<textarea
ref="autoResizeTextArea"
class="input_area"
v-model="newNote.content"
cols="50"
rows="3"
placeholder="新增記事">
</textarea>
</div>
<div class="input_group">
<div class="label">顏色</div>
<select class="input_area" v-model="newNote.color">
<option value="red">紅色</option>
<option value="green">綠色</option>
<option value="blue">藍色</option>
</select>
</div>
<div class="input_group">
<button class="create_btn" @click="addNote">新增</button>
</div>
</div>
<div class="wrap">
<div v-for="(note, index) in notes" :key="index" class="note" :class="note.color">
<h3 class="title">
{{ note.title }}
<button class="delete_btn" @click="deleteNote(index)">X</button>
</h3>
<p class="content">
{{ note.content }}
</p>
</div>
</div>
</div>
<script...
CSS
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
.input_content {
width: 760px;
border-radius: 5px;
border: 1px solid #ccc;
padding: 10px;
margin-left: 10px;
}
.input_group {
position: relative;
margin-bottom: 20px; /* Adds space between input groups */
display: flex; /* 將容器設置為 Flexbox 以便對齊子元素 */
}
.label {
position: absolute;
left: 10px;
top: -10px;
font-size: 16px;
font-weight: bold;
color: #277eb0;
background-color: #fff;
}
.input_area {
font-size: 20px;
line-height: 150%;
box-sizing: border-box;
padding: 10px;
border: 1px solid #ccc;
}
.create_btn {
margin-left: auto; /* 將按鈕推到右側 */
padding: 8px 16px;
font-size: 20px;
border-radius: 20px;
border: 1px solid #ccc;
width: 100px;
letter-spacing: 5px;
}
.create_btn:hover {
cursor: pointer;
}
.create_btn:active {
background-color: #e24d4d;
color: #f5cdcd;
}
.wrap {
display: flex;
flex-wrap: wrap; /* 允許項目換行 */
align-content: flex-start; /* 對齊方式,這裡是從上到下 */
}
.delete_btn {
background: none; /* 去掉背景 */
border: none; /* 去掉邊框 */
color: red; /* X 的顏色 */
font-weight: bold; /* 字體加粗 */
cursor: pointer; /* 鼠標懸停時顯示為手型 */
position: absolute; /* 絕對定位 */
top: -6px; /* 距離上邊界的距離 */
right: -4px; /* 距離右邊界的距離 */
}
.note {
width: 240px;
height: 100px;
border: 1px solid #ccc;
border-radius: 5px;
margin: 10px;
padding: 15px;
position: relative; /* 新增這一行 */
}
.red {
background-color: #f7d5d9;
}
.green {
background-color: #D0EDDA;
}
.blue {
background-color: #C9E4FD;
}
JavaScript
const { createApp } = Vue;
const app = createApp({
data() {
return {
notes: [
{
title: "春節行程安排",
content: "吃飽睡,睡飽吃",
color: "red",
},
{
title: "工作待辦事項",
content: "詢問各家廠商報價",
color: "green",
},
{
title: "運動健身計畫",
content: "每天早上六點去健身",
color: "blue",
},
],
newNote: {
title: '',
content: '',
color: 'red' // 預設顏色
}
};
},
methods: {
addNote() {
if (this.newNote.title && this.newNote.content) {
this.notes.push({ ...this.newNote }); // 將新筆記添加到 notes 陣列中, 這是淺拷貝
this.newNote = { title: '', content: '', color: 'red' }; // 清空表單
} else {
alert("請填寫標題和內容"); // 確保標題和內容不為空
}
},
deleteNote(index) {
this.notes.splice(index, 1); // 刪除指定索引的筆記
}
},
watch: {
// 監聽 notes 陣列的變化
notes: {
handler(newNotes) {
// 每次 notes 更新後,將 notes 存儲到 Local Storage
localStorage.setItem('notes', JSON.stringify(newNotes));
},
deep: true // 監聽嵌套物件的變化
}
},
mounted() {
// 應用啟動時從 Local Storage 加載筆記
const savedNotes = localStorage.getItem('notes');
if (savedNotes) {
this.notes = JSON.parse(savedNotes); // 如果有筆記資料,則加載它們
}
// 使用 ref 引用 textarea 并应用 autosize
autosize(this.$refs.autoResizeTextArea);
}
});
// 將 Vue 應用實例掛載到 #app
app.mount('#app');