如何在单击确定按钮后才能生成元素UI时间选择器设置值?

问题描述 投票:2回答:1

目前,Element Timepicker每次更改小时,分钟或秒时触发input事件(有趣的是 - 不是change事件,如mentioned in the docs)。对于我的用例,我需要它允许用户选择一个值但不实际设置模型(我使用的是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>
javascript vue.js element-ui
1个回答
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/[email protected]/lib/theme-chalk/index.css" rel="stylesheet" />
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/[email protected]/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>
© www.soinside.com 2019 - 2024. All rights reserved.