ContactEdit 聯絡人編輯 - Vant 4
✏️ ContactEdit 聯絡人編輯
📝 介紹
ContactEdit 就像是你的專屬聯絡人管理助手!✨ 它不僅提供了完整的聯絡人編輯功能,更像是一個貼心的數位管家,讓新增和編輯聯絡人資訊變得如絲般順滑。介面設計簡潔而不失優雅,每一個操作都經過精心雕琢,讓你在管理聯絡人時享受到如藝術般的流暢體驗!🎨
📦 引入
通過以下方式來全域註冊元件,更多註冊方式請參考元件註冊。
js
import { createApp } from'vue';
import { ContactEdit } from'vant';
const app = createApp();
app.use(ContactEdit);🎯 程式碼演示
🔧 基礎用法 - 聯絡人資訊的完美編輯體驗
ContactEdit 為你打造了一個功能齊全的聯絡人編輯介面!📱 無論是添加新朋友的資訊,還是更新老朋友的聯絡方式,都能讓你在優雅的介面中輕鬆完成。每一個輸入框都經過精心設計,讓資訊錄入變得既高效又愉悅。
html
js
import { ref } from'vue';
import { showToast } from'vant';
export default {
setup() {
const editingContact = ref({ tel: '', name: '', });
const onSave = (contactInfo) => showToast('儲存');
const onDelete = (contactInfo) => showToast('刪除');
return { onSave, onDelete, editingContact, }; }, };📖 API
Props
| 參數 | 說明 | 類型 | 預設值 |
|---|---|---|---|
| contact-info | 聯絡人資訊 | ContactEditInfo | {} |
| is-edit | 是否為編輯聯絡人 | boolean | false |
| is-saving | 是否顯示儲存按鈕載入動畫 | boolean | false |
| is-deleting | 是否顯示刪除按鈕載入動畫 | boolean | false |
| tel-validator | 手機號格式校驗函數 | (tel: string) => boolean | - |
| show-set-default | 是否顯示預設聯絡人欄 | boolean | false |
| set-default-label | 預設聯絡人欄文案 | string | - |
Events
| 事件名 | 說明 | 回調參數 |
|---|---|---|
| save | 點擊儲存按鈕時觸發 | content:表單內容 |
| delete | 點擊刪除按鈕時觸發 | content:表單內容 |
| change-default | 切換是否為預設聯絡人時觸發 | checked:是否預設 |
ContactEditInfo 資料結構
| 鍵名 | 說明 | 類型 |
|---|---|---|
| name | 聯絡人姓名 | string |
| tel | 聯絡人手機號 | string |
| isDefault | 是否預設 | *boolean |
類型定義
元件匯出以下類型定義:
ts
import type { ContactEditInfo, ContactEditProps } from'vant';🎨 主題定製
樣式變數
元件提供了下列 CSS 變數,可用於自訂樣式,使用方法請參考 ConfigProvider 元件。
| 名稱 | 預設值 | 描述 |
|---|---|---|
| --van-contact-edit-padding | var(--van-padding-md) | - |
| --van-contact-edit-fields-radius | var(--van-radius-md) | - |
| --van-contact-edit-buttons-padding | var(--van-padding-xl) 0 | - |
| --van-contact-edit-button-margin-bottom | var(--van-padding-sm) | - |
| --van-contact-edit-button-font-size | var(--van-font-size-lg) | - |
| --van-contact-edit-field-label-width | 4.1em | - |
🎯 最佳實踐
📝 表單驗證策略
- 即時驗證 - 在使用者輸入時提供即時回饋
- 友好提示 - 使用清晰易懂的錯誤資訊
- 防重複提交 - 避免使用者多次點擊儲存按鈕
- 資料持久化 - 自動儲存草稿,防止資料遺失
🔍 進階表單驗證
vue
<template>
<ContactEdit
:contact-info="contactInfo"
:is-edit="isEditMode"
:is-saving="isSaving"
:tel-validator="validatePhone"
@save="handleSave"
@delete="handleDelete"
/>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { showToast, showDialog } from 'vant'
const contactInfo = reactive({
name: '',
tel: '',
isDefault: false
})
const isSaving = ref(false)
const isEditMode = ref(false)
// 手機號驗證
const validatePhone = (tel) => {
const phoneRegex = /^1[3-9]\d{9}$/
return phoneRegex.test(tel)
}
// 姓名驗證
const validateName = (name) => {
if (!name.trim()) {
showToast('請輸入聯絡人姓名')
return false
}
if (name.length > 20) {
showToast('姓名長度不能超過20個字元')
return false
}
return true
}
// 儲存聯絡人
const handleSave = async (formData) => {
// 表單驗證
if (!validateName(formData.name)) return
if (!validatePhone(formData.tel)) {
showToast('請輸入正確的手機號碼')
return
}
isSaving.value = true
try {
await saveContactAPI(formData)
showToast('儲存成功')
// 返回上一頁或重新整理清單
router.back()
} catch (error) {
showToast('儲存失敗,請重試')
} finally {
isSaving.value = false
}
}
// 刪除聯絡人
const handleDelete = async (formData) => {
const result = await showDialog({
title: '確認刪除',
message: '刪除後無法復原,確定要刪除這個聯絡人嗎?',
confirmButtonText: '刪除',
confirmButtonColor: '#ee0a24'
})
if (result === 'confirm') {
try {
await deleteContactAPI(formData.id)
showToast('刪除成功')
router.back()
} catch (error) {
showToast('刪除失敗,請重試')
}
}
}
</script>💾 資料持久化方案
javascript
// 自動儲存草稿
const draftKey = 'contact-edit-draft'
// 儲存草稿到本機儲存
const saveDraft = (formData) => {
localStorage.setItem(draftKey, JSON.stringify(formData))
}
// 復原草稿資料
const restoreDraft = () => {
const draft = localStorage.getItem(draftKey)
if (draft) {
return JSON.parse(draft)
}
return null
}
// 清除草稿
const clearDraft = () => {
localStorage.removeItem(draftKey)
}
// 監聽表單變化,自動儲存草稿
watch(contactInfo, (newValue) => {
if (newValue.name || newValue.tel) {
saveDraft(newValue)
}
}, { deep: true })
// 頁面載入時復原草稿
onMounted(() => {
const draft = restoreDraft()
if (draft && !isEditMode.value) {
Object.assign(contactInfo, draft)
showToast('已復原上次編輯的內容')
}
})💡 使用技巧
🎨 自訂表單佈局
vue
<template>
<div class="custom-contact-edit">
<ContactEdit
:contact-info="contactInfo"
:show-set-default="showDefaultOption"
:set-default-label="defaultLabel"
@save="handleSave"
class="enhanced-form"
>
<!-- 可以透過插槽自訂額外欄位 -->
<template #extra-fields>
<Field
v-model="contactInfo.email"
label="信箱"
placeholder="請輸入信箱地址"
type="email"
/>
<Field
v-model="contactInfo.company"
label="公司"
placeholder="請輸入公司名稱"
/>
</template>
</ContactEdit>
</div>
</template>
<style>
.enhanced-form {
--van-contact-edit-padding: 20px;
--van-contact-edit-fields-radius: 12px;
}
.custom-contact-edit {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
</style>📱 行動端最佳化
vue
<template>
<div class="mobile-contact-edit">
<!-- 頂部導覽列 -->
<NavBar
:title="isEditMode ? '編輯聯絡人' : '新增聯絡人'"
left-arrow
@click-left="handleBack"
>
<template #right>
<Button
type="primary"
size="small"
:loading="isSaving"
@click="quickSave"
>
儲存
</Button>
</template>
</NavBar>
<!-- 聯絡人頭像 -->
<div class="avatar-section">
<Uploader
v-model="avatarList"
:max-count="1"
:preview-size="80"
upload-text="上傳頭像"
/>
</div>
<!-- 表單內容 -->
<ContactEdit
:contact-info="contactInfo"
:is-saving="isSaving"
@save="handleSave"
@delete="handleDelete"
/>
</div>
</template>
<script setup>
// 處理返回操作
const handleBack = () => {
if (hasUnsavedChanges.value) {
showDialog({
title: '確認離開',
message: '目前有未儲存的變更,確定要離開嗎?',
confirmButtonText: '離開',
cancelButtonText: '繼續編輯'
}).then(() => {
router.back()
}).catch(() => {
// 使用者選擇繼續編輯
})
} else {
router.back()
}
}
// 快速儲存
const quickSave = () => {
// 觸發表單儲存
handleSave(contactInfo)
}
</script>🔄 批次操作支援
vue
<template>
<div class="batch-contact-edit">
<div class="batch-header">
<Checkbox v-model="selectAll" @change="handleSelectAll">
全選 ({{ selectedContacts.length }}/{{ contacts.length }})
</Checkbox>
<div class="batch-actions" v-if="selectedContacts.length > 0">
<Button size="small" @click="batchDelete">
批次刪除
</Button>
<Button size="small" type="primary" @click="batchExport">
批次匯出
</Button>
</div>
</div>
<div class="contact-list">
<div
v-for="contact in contacts"
:key="contact.id"
class="contact-item"
>
<Checkbox
:model-value="selectedContacts.includes(contact.id)"
@update:model-value="toggleSelect(contact.id)"
/>
<ContactEdit
:contact-info="contact"
is-edit
@save="updateContact"
@delete="deleteContact"
/>
</div>
</div>
</div>
</template>
<script setup>
const contacts = ref([])
const selectedContacts = ref([])
const selectAll = ref(false)
// 切換選擇狀態
const toggleSelect = (contactId) => {
const index = selectedContacts.value.indexOf(contactId)
if (index > -1) {
selectedContacts.value.splice(index, 1)
} else {
selectedContacts.value.push(contactId)
}
}
// 全選/取消全選
const handleSelectAll = (checked) => {
if (checked) {
selectedContacts.value = contacts.value.map(c => c.id)
} else {
selectedContacts.value = []
}
}
// 批次刪除
const batchDelete = async () => {
const result = await showDialog({
title: '批次刪除',
message: `確定要刪除選中的 ${selectedContacts.value.length} 個聯絡人嗎?`
})
if (result === 'confirm') {
try {
await batchDeleteAPI(selectedContacts.value)
showToast('刪除成功')
// 重新整理清單
loadContacts()
selectedContacts.value = []
} catch (error) {
showToast('刪除失敗')
}
}
}
</script>❓ 常見問題解決
🔧 表單驗證不生效?
問題:自訂驗證函數沒有被呼叫 解決方案:
- 確保
tel-validator屬性正確綁定 - 驗證函數必須回傳布林值
- 檢查函數是否在正確的作用域內
📱 行動端鍵盤遮擋問題
問題:軟鍵盤彈起時遮擋輸入框 解決方案:
css
/* 新增視窗適配 */
.van-contact-edit {
padding-bottom: env(keyboard-inset-height, 0);
}
/* 或使用 JavaScript 動態調整 */
const adjustForKeyboard = () => {
const viewport = window.visualViewport
if (viewport) {
document.documentElement.style.setProperty(
'--keyboard-height',
`${window.innerHeight - viewport.height}px`
)
}
}💾 資料儲存失敗處理
問題:網路異常導致儲存失敗 解決方案:
javascript
const saveWithRetry = async (data, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
await saveContactAPI(data)
return true
} catch (error) {
if (i === maxRetries - 1) {
// 最後一次重試失敗,儲存到本機
saveDraft(data)
showToast('網路異常,已儲存為草稿')
return false
}
// 等待一段時間後重試
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
}
}
}🎨 設計靈感
🌈 主題風格定製
商務風格 - 專業簡潔
css--van-contact-edit-padding: 24px; --van-contact-edit-fields-radius: 8px; --van-contact-edit-button-font-size: 16px;時尚風格 - 現代活潑
css--van-contact-edit-padding: 20px; --van-contact-edit-fields-radius: 16px; --van-contact-edit-button-font-size: 18px;極簡風格 - 純淨優雅
css--van-contact-edit-padding: 32px; --van-contact-edit-fields-radius: 4px; --van-contact-edit-button-font-size: 14px;
🎯 互動體驗最佳化
- 智慧輸入 - 根據輸入內容自動格式化
- 快捷操作 - 支援鍵盤快捷鍵
- 手勢支援 - 滑動切換編輯模式
- 語音輸入 - 整合語音辨識功能