今日目標
按下分享經驗後跳出表單,填寫完後按分享經驗按鈕就可以囉
在 src/components 中新增 NewPostModal.vue
<template>
<div v-if="visible" class="modal-overlay" @click.self="close">
<div class="modal-content share-modal">
<div class="modal-header">
<h3 class="modal-title">✍ 分享你的推甄經驗</h3>
<button class="close-btn" @click="close">×</button>
</div>
<div class="modal-body">
<form @submit.prevent="submitExperience" class="share-form">
<div class="form-section">
<h4 class="section-title">📚 基本資訊</h4>
<div class="form-grid">
<div class="form-group">
<label class="form-label">學校</label>
<input
v-model="formData.pSchool"
type="text"
class="form-input"
placeholder="例:台灣大學"
required
/>
</div>
<div class="form-group">
<label class="form-label">系所</label>
<input
v-model="formData.pDep"
type="text"
class="form-input"
placeholder="例:資訊管理學系"
required
/>
</div>
<div class="form-group">
<label class="form-label">推甄年度</label>
<input
v-model="formData.pYear"
type="text"
class="form-input"
placeholder="例:114"
required
/>
</div>
<div class="form-group">
<label class="form-label">成績排名</label>
<input
v-model="formData.pScore"
type="text"
class="form-input"
placeholder="例:5% 或 系排第3"
/>
</div>
<div class="form-group">
<label class="form-label">GPA (選填)</label>
<input
v-model="formData.pGPA"
type="text"
class="form-input"
placeholder="例:4.0/4.0"
/>
</div>
</div>
</div>
<div class="form-section">
<h4 class="section-title">🌟 經歷與背景</h4>
<div class="form-group">
<label class="form-label">詳細經歷</label>
<textarea
v-model="formData.pExp"
class="form-textarea"
rows="6"
placeholder="請分享你的經歷,例如: - 專題研究 - 實習經驗 - 競賽得獎 - 證照考取 - 社團活動 - 其他特殊經歷"
required
></textarea>
</div>
</div>
<div class="form-section">
<h4 class="section-title">🎯 推甄結果</h4>
<div class="form-group">
<label class="form-label">申請結果</label>
<textarea
v-model="formData.pResult1"
class="form-textarea"
rows="6"
placeholder="請分享你的申請結果,例如: 台大資管 一階落榜 政大資管 正取 成大資管 備取5 中央資管 正取"
required
></textarea>
</div>
</div>
<div class="form-section">
<h4 class="section-title">🔗 來源連結 (選填)</h4>
<div class="form-group">
<label class="form-label">原文連結</label>
<input
v-model="formData.pURL"
type="url"
class="form-input"
placeholder="例:https://www.dcard.tw/f/graduate_school/p/..."
/>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" @click="close">
取消
</button>
<button type="submit" class="btn btn-primary" :disabled="isSubmitting">
{{ isSubmitting ? '分享中...' : '✨ 分享經驗' }}
</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const props = defineProps({
visible: { type: Boolean, default: false }
})
const emit = defineEmits(['close', 'submit'])
const isSubmitting = ref(false)
const formData = reactive({
pSchool: '',
pDep: '',
pYear: '',
pScore: '',
pGPA: '',
pExp: '',
pResult1: '',
pURL: ''
})
function close() {
emit('close')
resetForm()
}
function resetForm() {
Object.keys(formData).forEach(key => {
formData[key] = ''
})
}
async function submitExperience() {
if (isSubmitting.value) return
isSubmitting.value = true
try {
const newExperience = {
pId: `p_${Date.now()}`,
pDate: new Date().toLocaleDateString('zh-TW', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).replace(/\//g, '/'),
pDcardId: null,
pURL: formData.pURL || null,
pYear: formData.pYear,
pContent: `背景:
學校/系所:${formData.pSchool} ${formData.pDep}
${formData.pScore ? `成績排名:${formData.pScore}` : ''}
${formData.pGPA ? `GPA:${formData.pGPA}` : ''}
經歷:
${formData.pExp}
結果:
${formData.pResult1}`,
pSchool: formData.pSchool,
pDep: formData.pDep,
p_sd_sId: "user_submitted",
p_sd_dId: "user_submitted",
pScore: formData.pScore || null,
pGPA: formData.pGPA || null,
pExp: formData.pExp,
pResult1: formData.pResult1
}
emit('submit', newExperience)
alert('感謝你的分享!你的經驗已成功加入資料庫 ✨')
close()
} catch (error) {
console.error('提交失敗:', error)
alert('提交失敗,請稍後再試')
} finally {
isSubmitting.value = false
}
}
</script>
<script setup>
import NewPostModal from './components/NewPostModal.vue'
...
const showShareModal = ref(false)
const allPosts = ref([...posts])
function openShareModal() {
showShareModal.value = true
}
function handleNewExperience(newExperience) {
allPosts.value.unshift(newExperience)
showShareModal.value = false
keyword.value = ''
currentPage.value = 1
}
...
</script>
<template>
<Header @share="openShareModal" />
<main>
...
<NewPostModal :visible="showShareModal" @close="showShareModal=false" @submit="handleNewExperience" />
</main>
</template>
<template>
<header class="header">
<div class="header-content">
<h1 class="logo">
✦ 推甄經驗分享 ✦
</h1>
<button class="add-btn" @click="handleShare">
✍ 分享經驗
</button>
</div>
</header>
</template>
<script setup>
const emit = defineEmits(['share'])
function handleShare() {
emit('share')
}
</script>
但是目前還沒接到資料的 API,所以資料只會暫時新增上去
ref
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 讀寫要用 .value
count.value++
<template>
<button @click="count++"> {{ count }} </button> <!-- 在模板可直接用 -->
</template>
reactive
import { reactive } from 'vue'
const form = reactive({
school: '',
dep: '',
year: ''
})
form.school = '台大' // 直接改屬性
<template>
<input v-model="form.school" placeholder="學校"/>
<p>輸入的學校是:{{ form.school }}</p>
</template>
小結
- 實作新增資料功能
- ref 與 reaactive 差異