TimePicker 時間選択 - Vant 4
TimePicker 時間ピッカー ⏰
紹介
分・秒まで正確にコントロール!TimePicker は強力な時間選択コンポーネントで、時・分・秒の柔軟な選択に対応します。アラーム設定、予約時間、所要時間の記録など、滑らかで直感的な体験を提供します。✨
⏰ 時の魔法使い - すべての瞬間を正確に捉える!TimePicker は親切な時間管理人のように、望む時刻へ簡単に到達できます。通常はポップアップと組み合わせて、優雅な選択体験を提供します。
取り込み
以下の方法でコンポーネントをグローバル登録します。詳細はコンポーネント登録を参照してください。
import { createApp } from 'vue';
import { TimePicker } from 'vant';
const app = createApp();
app.use(TimePicker);コード例
🎯 基本的な使い方 - 時間選択の第一歩
時計の針を回すように、滑らかな操作で目標の時刻へすばやく移動できます。
<template>
<van-time-picker
v-model="currentTime"
title="時間を選択"
@confirm="onConfirm"
@cancel="onCancel"
/>
</template>import { ref } from 'vue';
import { showToast } from 'vant';
export default {
setup() {
const currentTime = ref(['12', '00']);
const onConfirm = ({ selectedValues }) => {
showToast(`選択した時間:${selectedValues.join(':')}`);
};
const onCancel = () => {
showToast('選択をキャンセル');
};
return {
currentTime,
onConfirm,
onCancel
};
},
};🎨 オプションタイプ - 自由な時間構成
時間は積み木のように自由に組み合わせ可能です。columns-type で hour(時)・minute(分)・second(秒)を任意順で構成できます。
比如:
['hour']を渡して時のみ選択['minute']を渡して分のみ選択['minute', 'second']で分と秒を選択['hour', 'minute', 'second']で時・分・秒を選択
<!-- 時・分を選択 - 日常的な設定に適する -->
<van-time-picker
v-model="currentTime"
title="時間を選択"
:columns-type="['hour', 'minute']"
@confirm="onTimeConfirm"
/>
<!-- 時・分・秒を選択 - 秒単位で精密制御 -->
<van-time-picker
v-model="preciseTime"
title="精密な時間"
:columns-type="['hour', 'minute', 'second']"
@confirm="onPreciseTimeConfirm"
/>
<!-- 分・秒を選択 - カウントダウンやタイマーに適する -->
<van-time-picker
v-model="durationTime"
title="所要時間を設定"
:columns-type="['minute', 'second']"
@confirm="onDurationConfirm"
/>import { ref } from 'vue';
export default {
setup() {
const currentTime = ref(['12', '00']);
const preciseTime = ref(['12', '00', '00']);
const durationTime = ref(['05', '30']);
const onTimeConfirm = ({ selectedValues }) => {
console.log('選択した時間:', selectedValues.join(':'));
};
const onPreciseTimeConfirm = ({ selectedValues }) => {
console.log('精密な時間:', selectedValues.join(':'));
};
const onDurationConfirm = ({ selectedValues }) => {
console.log('所要時間の設定:', `${selectedValues[0]}分${selectedValues[1]}秒`);
};
return {
currentTime,
preciseTime,
durationTime,
onTimeConfirm,
onPreciseTimeConfirm,
onDurationConfirm
};
}
};🚧 時間範囲 - 境界の設定
min-hour や max-hour などの属性で、時・分・秒の選択範囲を制限し、より正確で秩序ある選択を実現します。
以下の例では、時は 10 ~ 20、分は 30 ~ 40 の範囲で選択できます。
<template>
<!-- 時と分の範囲を制限 -->
<van-time-picker
v-model="currentTime"
title="時間を選択"
:min-hour="10"
:max-hour="20"
:min-minute="30"
:max-minute="40"
@confirm="onConfirm"
/>
<!-- ランチ時間ピッカー (11:30-14:00) -->
<van-time-picker
v-model="lunchTime"
title="ランチ時間を選択"
:min-hour="11"
:max-hour="14"
:min-minute="30"
@confirm="onLunchTimeConfirm"
/>
</template>import { ref } from 'vue';
import { showToast } from 'vant';
export default {
setup() {
const currentTime = ref(['12', '35']);
const lunchTime = ref(['12', '30']);
const onConfirm = ({ selectedValues }) => {
showToast(`選択した時間:${selectedValues.join(':')}`);
};
const onLunchTimeConfirm = ({ selectedValues }) => {
showToast(`ランチ時間:${selectedValues.join(':')}`);
};
return {
currentTime,
lunchTime,
onConfirm,
onLunchTimeConfirm
};
},
};
### 🌍 全体の時間範囲 - 全体制御
`min-time` と `max-time` を使って全体の時間範囲を制限します。`10:00:00` のようなフォーマットを使用します。
- `min-time` を設定すると、`min-hour`、`min-minute`、`min-second` は無効になります。
- `max-time` を設定すると、`max-hour`、`max-minute`、`max-second` は無効になります。
以下の例では、`09:40:10` から `20:20:50` の任意時間を選択できます。
```htmlimport { ref } from'vue'; exportdefault { setup() { const currentTime = ref(['12', '00', '00']); return { currentTime }; }, };✨ フォーマットオプション - 時間テキストの装飾
formatter 関数で表示テキストを美しく整形できます。各時間単位をわかりやすく装飾します。
<template>
<!-- 中国語の時間フォーマット -->
<van-time-picker
v-model="chineseTime"
title="時間を選択"
:formatter="chineseFormatter"
@confirm="onChineseTimeConfirm"
/>
<!-- 12時間制フォーマット -->
<van-time-picker
v-model="ampmTime"
title="時間を選択"
:formatter="ampmFormatter"
@confirm="onAmpmTimeConfirm"
/>
</template>import { ref } from 'vue';
import { showToast } from 'vant';
export default {
setup() {
const chineseTime = ref(['12', '00']);
const ampmTime = ref(['12', '00']);
// 中国語フォーマッタ
const chineseFormatter = (type, option) => {
if (type === 'hour') {
option.text += '时';
}
if (type === 'minute') {
option.text += '分';
}
if (type === 'second') {
option.text += '秒';
}
return option;
};
// 12小时制格式化器
const ampmFormatter = (type, option) => {
if (type === 'hour') {
const hour = parseInt(option.value);
if (hour === 0) {
option.text = '12 AM';
} else if (hour < 12) {
option.text = `${hour} AM`;
} else if (hour === 12) {
option.text = '12 PM';
} else {
option.text = `${hour - 12} PM`;
}
}
if (type === 'minute') {
option.text += ' min';
}
return option;
};
const onChineseTimeConfirm = ({ selectedValues }) => {
showToast(`中国語時間:${selectedValues[0]}時${selectedValues[1]}分`);
};
const onAmpmTimeConfirm = ({ selectedValues }) => {
showToast(`12時間制:${selectedValues.join(':')}`);
};
return {
chineseTime,
ampmTime,
chineseFormatter,
ampmFormatter,
onChineseTimeConfirm,
onAmpmTimeConfirm
};
},
};🔍 フィルタリングオプション - 時間の精密選別
filter 関数でオプション配列を精密にフィルタリングできます。不要な時間を除外し、任意の時間間隔を実現します。
<template>
<!-- 5 分間隔の選択器 -->
<van-time-picker
v-model="intervalTime"
title="時間を選択(5 分間隔)"
:filter="intervalFilter"
@confirm="onIntervalTimeConfirm"
/>
<!-- 勤務時間フィルタ -->
<van-time-picker
v-model="workTime"
title="勤務時間を選択"
:filter="workTimeFilter"
@confirm="onWorkTimeConfirm"
/>
</template>import { ref } from 'vue';
import { showToast } from 'vant';
export default {
setup() {
const intervalTime = ref(['12', '00']);
const workTime = ref(['09', '00']);
// 5 分間隔フィルタ
const intervalFilter = (type, options) => {
if (type === 'minute') {
return options.filter((option) => Number(option.value) % 5 === 0);
}
return options;
};
// 勤務時間フィルタ
const workTimeFilter = (type, options) => {
if (type === 'hour') {
// 勤務時間 9:00-18:00 のみ表示
return options.filter((option) => {
const hour = Number(option.value);
return hour >= 9 && hour <= 18;
});
}
if (type === 'minute') {
// 00分と30分のみ表示
return options.filter((option) => {
const minute = Number(option.value);
return minute === 0 || minute === 30;
});
}
return options;
};
const onIntervalTimeConfirm = ({ selectedValues }) => {
showToast(`間隔時間:${selectedValues.join(':')}`);
};
const onWorkTimeConfirm = ({ selectedValues }) => {
showToast(`勤務時間:${selectedValues.join(':')}`);
};
return {
intervalTime,
workTime,
intervalFilter,
workTimeFilter,
onIntervalTimeConfirm,
onWorkTimeConfirm
};
},
};🚀 上級用法 - 時間フィルタの極意
filter の第 3 引数で現在の選択状態を取得できます。非制御モードでも柔軟で賢いフィルタリングが可能です。
exportdefault { setup() { constfilter = (type, options, values) => { const hour = +values[0]; if (type === 'hour') { return options.filter( (option) =>Number(option.value) >= 8 && Number(option.value) <= 18, ); } if (type === 'minute') { options = options.filter((option) =>Number(option.value) % 10 === 0); if (hour === 8) { return options.filter((option) =>Number(option.value) >= 40); } if (hour === 18) { return options.filter((option) =>Number(option.value) <= 20); } } return options; }; return { filter, }; }, };API
Props
| パラメータ | 説明 | 型 | デフォルト |
|---|---|---|---|
| v-model | 🎯 現在選択されている時間(配列形式) | string[] | - |
| columns-type | ⚙️ 選択項目の種類(hour・minute・second の配列) | string[] | ['hour', 'minute'] |
| min-hour | 🌅 選択可能な最小の時 | number | string | 0 |
| max-hour | 🌇 選択可能な最大の時 | number | string | 23 |
| min-minute | ⏰ 選択可能な最小の分 | number | string | 0 |
| max-minute | ⏰ 選択可能な最大の分 | number | string | 59 |
| min-second | ⏱️ 選択可能な最小の秒 | number | string | 0 |
| max-second | ⏱️ 選択可能な最大の秒 | number | string | 59 |
min-time v4.5.0 | 🚫 選択可能な最小時刻(例 07:40:00)。使用時は min-hour min-minute min-second は無効 | string | - |
max-time v4.5.0 | 🚫 選択可能な最大時刻(例 10:20:00)。使用時は max-hour max-minute max-second は無効 | string | - |
| title | 📝 ヘッダーのタイトル | string | '' |
| confirm-button-text | ✅ 確認ボタンの文言 | string | 确认 |
| cancel-button-text | ❌ キャンセルボタンの文言 | string | 取消 |
| show-toolbar | 🔧 ヘッダー(ツールバー)を表示 | boolean | true |
| loading | ⏳ ローディング状態を表示(非同期データ時) | boolean | false |
| readonly | 🔒 読み取り専用(選択不可) | boolean | false |
| filter | 🔍 オプションのフィルタ関数 | (type: string, options: PickerOption[], values: string[]) => PickerOption[] | - |
| formatter | 🎨 オプションのフォーマット関数 | (type: string, option: PickerOption) => PickerOption | - |
| option-height | 📏 オプション高さ(px vw vh rem をサポート、デフォルト px) | number | string | 44 |
| visible-option-num | 👁️ 表示されるオプション数 | number | string | 6 |
| swipe-duration | 🏃 慣性スクロール時間(ms) | number | string | 1000 |
Events
| イベント名 | 説明 | コールバック引数 |
|---|---|---|
| confirm | ✅ 完了ボタンで発火。時間を確定 | { selectedValues, selectedOptions, selectedIndexes } |
| cancel | ❌ キャンセルボタンで発火。選択を取り消し | { selectedValues, selectedOptions, selectedIndexes } |
| change | 🔄 オプション変更時に発火。操作をリアルタイムに反映 | { selectedValues, selectedOptions, selectedIndexes, columnIndex } |
Slots
| 名前 | 説明 | 引数 |
|---|---|---|
| toolbar | 🔧 ヘッダー全体のカスタマイズ | - |
| title | 📝 タイトルのカスタマイズ | - |
| confirm | ✅ 確認ボタンのカスタマイズ | - |
| cancel | ❌ キャンセルボタンのカスタマイズ | - |
| option | 🎨 オプション表示のカスタマイズ | option: PickerOption, index: number |
| columns-top | ⬆️ オプション上部のカスタマイズ | - |
| columns-bottom | ⬇️ オプション下部のカスタマイズ | - |
メソッド
ref で Picker インスタンスを取得してメソッドを呼び出せます。詳細はコンポーネントインスタンスメソッドを参照してください。
| メソッド名 | 説明 | 引数 | 戻り値 |
|---|---|---|---|
| confirm | ✅ 慣性スクロールを停止し confirm を発火 | - | - |
| getSelectedTime | 🎯 現在選択中の時間を取得 | - | string[] |
型定義 📝
TypeScript の型定義を提供します:
import type { TimePickerProps, TimePickerColumnType } from 'vant';TimePickerInstance はコンポーネントインスタンスの型です:
import { ref } from 'vue';
import type { TimePickerInstance } from 'vant';
const timePickerRef = ref<TimePickerInstance>();
// プログラムで確認
timePickerRef.value?.confirm();
// 現在選択中の時間を取得
const selectedTime = timePickerRef.value?.getSelectedTime();よくある質問
デスクトップで操作できない?
デスクトップ適応 を参照してください。
🎯 ベストプラクティス
時間ピッカーとポップアップの組み合わせ
<template>
<van-cell title="時間を選択" :value="timeText" @click="showPicker = true" />
<van-popup v-model:show="showPicker" position="bottom">
<van-time-picker
v-model="currentTime"
title="時間を選択"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const showPicker = ref(false);
const currentTime = ref(['12', '00']);
const timeText = computed(() => {
return currentTime.value.join(':');
});
const onConfirm = ({ selectedValues }) => {
currentTime.value = selectedValues;
showPicker.value = false;
};
return {
showPicker,
currentTime,
timeText,
onConfirm
};
}
};
</script>レスポンシブな時間範囲設定
// 現在時刻に基づき選択可能範囲を動的設定
const getCurrentTimeRange = () => {
const now = new Date();
const currentHour = now.getHours();
const currentMinute = now.getMinutes();
return {
minHour: currentHour,
minMinute: currentHour === now.getHours() ? currentMinute : 0,
maxHour: 23,
maxMinute: 59
};
};スマートなデフォルト値設定
// 妥当なデフォルト時間を設定
const getDefaultTime = () => {
const now = new Date();
const hour = now.getHours().toString().padStart(2, '0');
const minute = Math.ceil(now.getMinutes() / 15) * 15; // 15 分に切り上げ
return [hour, minute.toString().padStart(2, '0')];
};💡 使い方のコツ
多言語の時間フォーマット
const createTimeFormatter = (locale = 'zh-CN') => {
const formatMap = {
'zh-CN': { hour: '时', minute: '分', second: '秒' },
'en-US': { hour: 'h', minute: 'm', second: 's' },
'ja-JP': { hour: '時', minute: '分', second: '秒' }
};
return (type, option) => {
const suffix = formatMap[locale][type] || '';
option.text += suffix;
return option;
};
};上級フィルタ機能
// 工作时间过滤器
const workTimeFilter = (type, options, values) => {
if (type === 'hour') {
return options.filter(option => {
const hour = Number(option.value);
return hour >= 9 && hour <= 18; // 只显示工作时间
});
}
if (type === 'minute') {
return options.filter(option => {
const minute = Number(option.value);
return minute % 15 === 0; // 只显示15分钟间隔
});
}
return options;
};列タイプの動的切り替え
<template>
<van-radio-group v-model="timeMode" direction="horizontal">
<van-radio name="hour">時のみ</van-radio>
<van-radio name="minute">時・分</van-radio>
<van-radio name="second">秒まで</van-radio>
</van-radio-group>
<van-time-picker
v-model="currentTime"
:columns-type="columnsType"
/>
</template>
<script>
const timeMode = ref('minute');
const columnsType = computed(() => {
const modeMap = {
hour: ['hour'],
minute: ['hour', 'minute'],
second: ['hour', 'minute', 'second']
};
return modeMap[timeMode.value];
});
</script>🔧 よくある問題の解決
時間フォーマットの互換性
// 異なる時間フォーマットに対応
const formatTimeValue = (timeArray) => {
return timeArray.map(time => {
// 2 桁に整形
return time.toString().padStart(2, '0');
});
};
// 時間文字列の解析
const parseTimeString = (timeString) => {
const parts = timeString.split(':');
return parts.map(part => part.padStart(2, '0'));
};性能优化
// debounce で頻繁な change を最適化
import { debounce } from 'lodash-es';
const debouncedChange = debounce((selectedValues) => {
console.log('時間選択の変化:', selectedValues);
// 関連ロジックを実行
}, 300);データ検証とエラー処理
// 時間の妥当性検証
const validateTime = (timeArray) => {
const [hour, minute, second] = timeArray.map(Number);
if (hour < 0 || hour > 23) return false;
if (minute < 0 || minute > 59) return false;
if (second !== undefined && (second < 0 || second > 59)) return false;
return true;
};
// エラー処理
const handleTimeError = (error) => {
console.error('時間ピッカーエラー:', error);
// デフォルト時間にリセット
currentTime.value = ['12', '00'];
};🎨 デザインのヒント
テーマ化時間ピッカー
/* ダークテーマ */
.van-time-picker--dark {
--van-picker-background: #1a1a1a;
--van-picker-option-text-color: #ffffff;
--van-picker-option-selected-text-color: #1989fa;
}
/* グラデーション背景 */
.van-time-picker--gradient {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
/* 角丸スタイル */
.van-time-picker--rounded {
border-radius: 20px;
overflow: hidden;
}アニメーション強化
/* オプション切り替えアニメーション */
.van-picker-column__item {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.van-picker-column__item--selected {
transform: scale(1.1);
font-weight: bold;
color: #1989fa;
}
/* ポップアップアニメーション */
.time-picker-enter-active,
.time-picker-leave-active {
transition: all 0.3s ease;
}
.time-picker-enter-from,
.time-picker-leave-to {
opacity: 0;
transform: translateY(100%);
}クリエイティブなインタラクション
// バイブレーションフィードバック
const handleTimeChange = () => {
if ('vibrate' in navigator) {
navigator.vibrate(50); // 軽い振動のフィードバック
}
};
// サウンドフィードバック
const playTickSound = () => {
const audio = new Audio('/sounds/tick.mp3');
audio.volume = 0.3;
audio.play().catch(() => {
// 音声再生失敗を黙って処理
});
};🚀 上級機能の拡張
スマート時間推薦システム
// ユーザー履歴選択に基づく推薦
class TimeRecommendationSystem {
constructor() {
this.history = JSON.parse(localStorage.getItem('timeHistory') || '[]');
}
// ユーザー選択を記録
recordSelection(timeArray) {
this.history.push({
time: timeArray,
timestamp: Date.now()
});
// 最近 50 件のみ保持
if (this.history.length > 50) {
this.history = this.history.slice(-50);
}
localStorage.setItem('timeHistory', JSON.stringify(this.history));
}
// 推奨時間を取得
getRecommendations() {
const timeFrequency = {};
this.history.forEach(record => {
const timeKey = record.time.join(':');
timeFrequency[timeKey] = (timeFrequency[timeKey] || 0) + 1;
});
return Object.entries(timeFrequency)
.sort(([,a], [,b]) => b - a)
.slice(0, 3)
.map(([time]) => time.split(':'));
}
}多タイムゾーン時間ピッカー
// 複数タイムゾーン対応
const createTimezoneTimePicker = (timezone = 'Asia/Shanghai') => {
const getTimezoneTime = () => {
const now = new Date();
const utc = now.getTime() + (now.getTimezoneOffset() * 60000);
const targetTime = new Date(utc + (getTimezoneOffset(timezone) * 60000));
return [
targetTime.getHours().toString().padStart(2, '0'),
targetTime.getMinutes().toString().padStart(2, '0')
];
};
const getTimezoneOffset = (tz) => {
// タイムゾーンのオフセットマップ
const timezones = {
'Asia/Shanghai': 8,
'America/New_York': -5,
'Europe/London': 0,
'Asia/Tokyo': 9
};
return (timezones[tz] || 0) * 3600000;
};
return {
getTimezoneTime,
formatTimezone: (time) => {
return `${time.join(':')} (${timezone})`;
}
};
};📚 参考資料
技術ドキュメント
- Picker ピッカー基礎 - 低レベル実装の理解
- DatePicker 日付選択 - 日付選択の最良の相棒
- Calendar カレンダー - より豊かな日時選択
デザインガイド
ユーザー体験
関連ドキュメント 📚
🎯 コアコンポーネント
- Picker ピッカー - 時間ピッカーの基礎コンポーネント
- DatePicker 日付選択 - 強力な組み合わせ
- Calendar カレンダー - 豊かな日時選択体験
🔧 補助コンポーネント
- Popup ポップアップ - 時間ピッカーの理想的な器
- Cell セル - 時間選択のトリガー
- Field 入力欄 - 簡易な時間入力の代替
⚡ 上級機能
- Form フォーム - バリデーションと時間選択の組み合わせ
- ConfigProvider グローバル設定 - テーマと言語の統一設定