Vue.js カスタムディレクティブ
カスタムディレクティブ
Vue.jsのカスタムディレクティブを作成して、フォーカス管理やバリデーション機能を実装します。
タスク
v-focusディレクティブ
要素に自動フォーカスを設定するディレクティブを作成する
v-highlightディレクティブ
条件に応じて要素をハイライトするディレクティブを作成する
v-validateディレクティブ
入力値のバリデーションを行うディレクティブを作成する
ヒント
v-focus、v-highlight、v-validateなどのカスタムディレクティブを作成して、DOM要素の動作をカスタマイズしましょう。
参考コード
// カスタムディレクティブの定義 const app = Vue.createApp({}) // v-focusディレクティブ - 要素に自動フォーカス app.directive('focus', { mounted(el) { el.focus() }, updated(el) { if (el.dataset.shouldFocus === 'true') { el.focus() } } }) // v-highlightディレクティブ - 条件に応じてハイライト app.directive('highlight', { mounted(el, binding) { if (binding.value) { el.classList.add('highlight') } }, updated(el, binding) { if (binding.value) { el.classList.add('highlight') } else { el.classList.remove('highlight') } } }) // v-validateディレクティブ - 入力値のバリデーション app.directive('validate', { mounted(el, binding) { el.addEventListener('input', () => { validateField(el, binding.value) }) el.addEventListener('blur', () => { validateField(el, binding.value) }) }, updated(el, binding) { validateField(el, binding.value) } }) // バリデーション関数 function validateField(el, rules) { const value = el.value let isValid = true let errorMessage = '' // 必須チェック if (rules.required && !value.trim()) { isValid = false errorMessage = 'この項目は必須です' } // 最小文字数チェック if (rules.minLength && value.length < rules.minLength) { isValid = false errorMessage = `最低${rules.minLength}文字入力してください` } // 最大文字数チェック if (rules.maxLength && value.length > rules.maxLength) { isValid = false errorMessage = `最大${rules.maxLength}文字まで入力できます` } // 正規表現チェック if (rules.pattern && !rules.pattern.test(value)) { isValid = false errorMessage = rules.message || '入力形式が正しくありません' } // 結果を適用 if (isValid) { el.classList.remove('error') el.classList.add('success') el.title = '' } else { el.classList.remove('success') el.classList.add('error') el.title = errorMessage } return isValid } // フォームコンテナコンポーネント const FormContainer = { template: ` <div class="form-container"> <div class="form-group"> <label>名前 (必須)</label> <input v-model="form.name" v-focus v-validate="{ required: true, minLength: 2, maxLength: 20 }" placeholder="名前を入力してください" > </div> <div class="form-group"> <label>メールアドレス (必須)</label> <input v-model="form.email" v-validate="{ required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '有効なメールアドレスを入力してください' }" placeholder="example@email.com" > </div> <div class="form-group"> <label>電話番号</label> <input v-model="form.phone" v-validate="{ pattern: /^[0-9-]{10,}$/, message: '有効な電話番号を入力してください' }" placeholder="090-1234-5678" > </div> <div class="form-group"> <label>メッセージ</label> <textarea v-model="form.message" v-highlight="form.message.length > 100" v-validate="{ maxLength: 500 }" rows="4" placeholder="メッセージを入力してください(最大500文字)" ></textarea> </div> <div class="button-group"> <button @click="submitForm">送信</button> <button @click="resetForm" class="secondary">リセット</button> <button @click="focusFirstField" class="secondary">最初のフィールドにフォーカス</button> </div> <div class="directive-info"> <h4>使用しているカスタムディレクティブ</h4> <ul> <li><strong>v-focus</strong>: 要素に自動フォーカスを設定</li> <li><strong>v-highlight</strong>: 条件に応じて要素をハイライト(メッセージが100文字を超えると黄色背景)</li> <li><strong>v-validate</strong>: 入力値のバリデーション(必須、文字数、正規表現チェック)</li> </ul> </div> </div> `, data() { return { form: { name: '', email: '', phone: '', message: '' } } }, methods: { submitForm() { // フォーム送信処理 console.log('フォーム送信:', this.form) alert('フォームが送信されました!') }, resetForm() { this.form = { name: '', email: '', phone: '', message: '' } }, focusFirstField() { // 最初のフィールドにフォーカス const firstInput = document.querySelector('input') if (firstInput) { firstInput.focus() } } } } // コンポーネントを登録 app.component('form-container', FormContainer) // マウント app.mount('#app')