Skip to content

ContactEdit 联系人编辑 - Vant 4

✏️ ContactEdit 連絡先編集

📝 紹介

ContactEdit はあなた専用の連絡先管理アシスタントのようなものです!✨ 完全な連絡先編集機能を提供するだけでなく、新しい連絡先の追加や情報の編集をスムーズに行える親切なデジタル管家のようです。インターフェースデザインはシンプルかつ優雅で、あらゆる操作が丁寧に設計されており、連絡先管理を芸術のようなスムーズな体験として提供します!🎨

📦 導入

以下の方法でグローバルにコンポーネントを登録します。詳細な登録方法についてはコンポーネント登録を参照してください。

js
import { createApp } from'vue'; import { ContactEdit } from'vant'; const app = createApp(); app.use(ContactEdit);

🎯 コードのデモ

🔧 基本用法 - 連絡先情報の完璧な編集体験

ContactEdit は機能豊富な連絡先編集インターフェースを提供します!📱 新しい友達の情報を追加する場合でも、古い友達の連絡先を更新する場合でも、優雅なインターフェースで簡単に行えます。すべての入力フィールドは丁寧に設計されており、情報の入力が効率的かつ快適になります。

html
<template>
  <ContactEdit
    v-model:contact-info="editingContact"
    :is-edit="true"
    @save="onSave"
    @delete="onDelete"
  />
</template>
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連絡先を編集しているかどうかbooleanfalse
is-saving保存ボタンのローディングアニメーションを表示するかどうかbooleanfalse
is-deleting削除ボタンのローディングアニメーションを表示するかどうかbooleanfalse
tel-validator電話番号形式の検証関数(tel: string) => boolean-
show-set-defaultデフォルト連絡先バーを表示するかどうかbooleanfalse
set-default-labelデフォルト連絡先バーのテキストstring-

Events

イベント名説明コールバックパラメータ
save保存ボタンをクリックしたときにトリガーcontent:フォームの内容
delete削除ボタンをクリックしたときにトリガーcontent:フォームの内容
change-defaultデフォルト連絡先かどうかを切り替えたときにトリガーchecked:デフォルトかどうか

ContactEditInfo データ構造

キー名説明
name連絡先の名前string
tel連絡先の電話番号string
isDefaultデフォルトかどうかboolean | undefined

型定義

コンポーネントは以下の型定義をエクスポートします:

ts
importtype { ContactEditInfo, ContactEditProps } from'vant';

🎨 テーマカスタマイズ

スタイル変数

コンポーネントは以下の CSS 変数を提供し、カスタムスタイルに使用できます。使用方法については ConfigProvider コンポーネント を参照してください。

名前デフォルト値説明
--van-contact-edit-paddingvar(--van-padding-md)-
--van-contact-edit-fields-radiusvar(--van-radius-md)-
--van-contact-edit-buttons-paddingvar(--van-padding-xl) 0-
--van-contact-edit-button-margin-bottomvar(--van-padding-sm)-
--van-contact-edit-button-font-sizevar(--van-font-size-lg)-
--van-contact-edit-field-label-width4.1em-

🎯 ベストプラクティス

📝 フォーム検証戦略

  1. リアルタイム検証 - ユーザーの入力時に即座にフィードバックを提供する
  2. フレンドリーな通知 - 明確で理解しやすいエラーメッセージを使用する
  3. 重複送信防止 - ユーザーが保存ボタンを複数回クリックするのを防ぐ
  4. データ永続化 - 下書きを自動的に保存し、データの喪失を防ぐ

🔍 高度なフォーム検証

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>

❓ よくある問題の解決策

🔧 フォーム検証が機能しない?

問題:カスタム検証関数が呼び出されていない 解決策

  1. tel-validator 属性が正しくバインドされていることを確認する
  2. 検証関数はブール値を返す必要がある
  3. 関数が正しいスコープ内にあるかどうかを確認する

📱 モバイルキーボードの重なり問題

問題:ソフトキーボードが表示されたときに入力フィールドが隠れる 解決策

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)))
    }
  }
}

🎨 デザインのインスピレーション

🌈 テーマスタイルのカスタマイズ

  1. ビジネススタイル - プロフェッショナルでシンプル

    css
    --van-contact-edit-padding: 24px;
    --van-contact-edit-fields-radius: 8px;
    --van-contact-edit-button-font-size: 16px;
  2. ファッションスタイル - モダンで活発

    css
    --van-contact-edit-padding: 20px;
    --van-contact-edit-fields-radius: 16px;
    --van-contact-edit-button-font-size: 18px;
  3. ミニマリストスタイル - 清潔で優雅

    css
    --van-contact-edit-padding: 32px;
    --van-contact-edit-fields-radius: 4px;
    --van-contact-edit-button-font-size: 14px;

🎯 インタラクション体験の最適化

  • スマート入力 - 入力内容に基づいて自動的にフォーマットする
  • クイック操作 - キーボードショートカットをサポート
  • ジェスチャーサポート - スワイプで編集モードを切り替え
  • 音声入力 - 音声認識機能を統合

📚 関連文書

🔗 関連リンク

Vant に基づく企業向けモバイルソリューション