javascript - 如何仅在单击确定按钮后才使元素 UI 时间选择器设置值?

标签 javascript vue.js element-ui

目前,每当小时、分钟或秒更改时,Element Timepicker 都会触发 input 事件(有趣的是 - 而不是 change 事件 mentioned in the docs) .对于我的用例,我需要它允许用户选择一个值但实际上不设置模型(我正在使用 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>

最佳答案

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>

关于javascript - 如何仅在单击确定按钮后才使元素 UI 时间选择器设置值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54818183/

相关文章:

vue.js - 使用 VUE 的未知自定义元素

mysql - 用户 'username' 访问被拒绝 @'IP' 错误 - digitalocean

javascript - jQuery Selection 无法选择所有元素

javascript - 扩展 javascript 类并将它们包装在容器对象中

javascript - 如何编写正则表达式来过滤掉分隔字符串数组中单次出现 4 的字符串

javascript - 使用 ajax 在 Vue.js 中提交表单

vuejs2 - VueJs + 元素用户界面 : How to custom el-dialog title?

javascript - 元素 UI 选择不适用于对象作为值

javascript - 在页面上放置多个 raphael.js 对象