javascript - 如何仅在单击确定按钮后才使元素 UI 时间选择器设置值?
问题描述
目前,每次更改小时、分钟或秒时,元素时间选择器都会触发input
事件(有趣的是,不是文档中提到change
的事件)。对于我的用例,我需要它来允许用户选择一个值但不实际设置模型(我使用的是 v-model 但本质上是触发一个使用的事件),直到用户单击按钮。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>
解决方案
当您单击时它会发出一个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>
推荐阅读
- amazon-web-services - AWS SAM 部署失败
- python - MATLAB 找不到 Python 脚本编写的文件
- python - 列表中的项目和列表中的项目
- python-3.x - 为什么 GridLayout 位于屏幕的左下方?
- javascript - Vue.js 中的参数验证
- ansible - Ansible jinja2 停止删除转义的双引号
- jquery - 未选中的复选框不返回任何数据
- javascript - 模糊或聚焦无法正常工作 js
- python - 如果数组在列表中,如何根据索引号打印数组值?
- html - 有没有办法在 HTML 中的特定字母上直接写小文本?