Как сделать значение выбора времени пользовательского интерфейса элемента только после нажатия кнопки ОК?
В настоящее время элемент Timepicker запускает input
событие (и, что интересно, - не change
событие, как указано в документации) каждый раз, когда меняются часы, минуты или секунды. Для моего случая использования мне нужно, чтобы пользователь мог выбрать значение, но на самом деле не установить модель (я использую v-модель, но, по сути, запускаю input
событие, которое v-model
использует), пока пользователь не нажмет ok
кнопка.
Я думаю, что компонент-обертка, который управляет государством внутри, является одним из способов сделать это. (Пример реализации ниже)
Есть ли более чистый способ (в идеале, встроенный в Element, без использования хаков, как показано ниже), чтобы сделать это?
РЕДАКТИРОВАТЬ: Похоже, что я был неправ по поводу того, что изменение не было запущено - как объясняется в ответе @Roy J ниже, оно срабатывает, когда нажимается кнопка, но также важно, когда пользователь просто щелкает из таймера, когда он находится в фокусе, который это не то поведение, которое требуется - модель должна обновляться только при нажатии кнопки ОК.
<template>
<el-time-picker
v-bind="_passthrough"
:value="_displayValue"
@blur="handleBlur"
@focus="handleFocus"
@input="handleInput"
>
</el-time-picker>
</template>
<script>
import { TimePicker } from "element-ui";
/**
* A list of props accepted by the element time picker component
* @private
*/
const _elTimePickerProps = [
"isRange",
"readonly",
"disabled",
"editable",
"clearable",
"size",
"placeholder",
"startPlaceholder",
"endPlaceholder",
"arrowControl",
"align",
"popperClass",
"pickerOptions",
"rangeSeparator",
"defaultValue",
"valueFormat",
"name",
"unlinkPanels",
"prefixIcon",
"clearIcon",
"value"
];
/**
* A wrapper on the element time picker to trigger the 'input' event only when the 'ok' button is clicked - lazily.
* The actual element timepicker fires the input event every time an internal control is changed which is
* undesirable in some cases.
*/
export default {
name: "LazyTimePicker",
props: [..._elTimePickerProps], // Accept the same props as element time picker
components: {
ElTimePicker: TimePicker
},
data() {
return {
/**
* Shadow to the value prop - used to update the value while the user is selecting without affecting the
* globally bound value
*/
currentValue: "",
/**
* Tracks if the element currently has focus
*/
hasFocus: false
};
},
methods: {
handleInput(value) {
// Update the internal value every time the value is updated
this.currentValue = value;
},
handleConfirm() {
// Confirm button was clicked
// Emit input event with the current value - plays nicely with v-model
this.$emit("input", this.currentValue);
// Remove the event listener on the confirm button
this.$confirmButton.removeEventListener("click", this.handleConfirm);
// Set the instance ref to the confirm button to undefined
this.$confirmButton = undefined;
},
handleFocus() {
// The time picker has gained focus, the dialogue will be open on the next tick
// May be called multiple time (for example when switching between hours, minutes and seconds,
// each switch triggers a focus event
// Update focus state
this.hasFocus = true;
// Check if the one time setup is complete (indicated by the availability of the button ref on the
// instance)
if (this.$confirmButton) {
// One time setup is complete, return early
return;
}
// Initialise the instance's currentValue to the value received via props
this.currentValue = this.value;
// Wait until the time picker dialogue is open on the next tick as the confirm button will be on
// the DOM only then
this.$nextTick(() => {
// Get a ref to the confirm button
const $confirmButton = document.querySelector(
".el-time-range-picker button.el-time-panel__btn.confirm"
);
// If the ref is available
if ($confirmButton) {
// Register click handler on the `ok` button
$confirmButton.addEventListener("click", this.handleConfirm);
// Keep a ref to the button for future use - also doubles as an indicator that the one time
// setup that is done every time this component is opened is complete
this.$confirmButton = $confirmButton;
}
});
},
handleBlur() {
// The time picker has lost focus, the dialogue will be closed on the next tick
this.hasFocus = false;
this.$nextTick(() => {
// Clean up the confirm button and it's event listener in case the user clicked out or pressed
// cancel without pressing okay
if (this.$confirmButton) {
// Remove the event listener on the confirm button
//Removing the listener here will prevent the input event from being emitted - does the listener get cleaned up?
//this.$confirmButton.removeEventListener('click', this.handleConfirm);
// Set the instance ref to the confirm button to undefined
this.$confirmButton = undefined;
}
});
}
},
computed: {
/**
* Collect all props related to the actual element time picker to be `v-bind`ed to it in one shot
* @returns {Object} Element time picker props
* @private
*/
_passthrough() {
const self = this;
return _elTimePickerProps.reduce(
(acc, key) => ({ ...acc, [key]: self[key] }),
{}
);
},
/**
* The value to be displayed. When the element is not in focus (the dialogue is closed) the value in
* the inputs should reflect the value bound to the time picker. When the element is in focus, the dialogue
* will be open and the user will be in the process ofmaking their new selection. At this time, the inputs
* should not show the value as it is currently being selected
* @returns {string}
* @private
*/
_displayValue() {
return this.hasFocus && this.currentValue
? this.currentValue
: this.value;
}
}
};
</script>
1 ответ
Испускает change
событие при нажатии ok
, Таким образом, вы можете положить change
обработчик, чтобы установить значение. Во фрагменте ниже value
обновления по вашему выбору, но value2
только обновления, когда вы нажимаете ok
,
Что интересно, v-model.lazy
не изменяет поведение, чтобы задержать изменение значения после ok
, Кажется, не имеет значения вообще.
new Vue({
el: '#app',
data() {
return {
value1: '',
value2: '',
};
},
methods: {
changed(nv) {
this.value2 = nv;
}
}
});
<link href="//unpkg.com/element-ui@2.0.4/lib/theme-chalk/index.css" rel="stylesheet" />
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui@2.0.4/lib/index.js"></script>
<div id="app">
<div class="block">
<el-time-picker v-model.lazy="value1" @change="changed" type="date" format="HH:mm:ss A">
</el-time-picker>
{{value1}}
</div>
{{value2}}
</div>