当前,每次更改小时,分钟或秒时,元素时间选择器都会触发input
事件(并且有趣的是-不是mentioned in the docs的change
事件)。对于我的用例,我需要它来允许用户选择一个值,但实际上并未设置模型(我正在使用v-model,但本质上是触发input
使用的v-model
事件),直到用户单击ok
按钮。
我在想内部处理状态的包装器组件是实现此目的的一种方法。 (下面的示例实现)
是否有一种更干净的方法(理想情况下,是内置于Element中并且不涉及如下所示的hack)?
编辑:似乎我对更改没有被触发是错误的-如下面@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>
答案 0 :(得分:0)
emits a change
event when you click 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>