【问题标题】:What's the proper way to implement formatting on v-model in Vue.js 2.0在 Vue.js 2.0 中实现 v-model 格式化的正确方法是什么
【发布时间】:2017-04-28 00:29:06
【问题描述】:

举个简单的例子:输入货币数据的文本框。 要求是以“$1,234,567”格式显示用户输入并删除小数点。

我已经尝试过 vue 指令。由于其他控件而刷新 UI 时,不会调用指令的 update 方法。因此文本框中的值恢复为没有任何格式的值。

我还尝试了 v-on:change 事件处理程序。但我不知道如何在事件处理程序中调用全局函数。在每个 Vue 对象中创建货币转换方法并不是一个好习惯。

那么现在 Vue 2.0 中的标准格式化方式是什么?

问候

【问题讨论】:

    标签: vue.js


    【解决方案1】:

    请检查这个有效的 jsFiddle 示例:https://jsfiddle.net/mani04/bgzhw68m/

    在这个例子中,格式化的货币输入本身就是一个组件,它使用v-model,就像 Vue.js 中的任何其他表单元素一样。您可以按如下方式初始化该组件:

    <my-currency-input v-model="price"></my-currency-input>
    

    my-currency-input 是一个独立的组件,用于在输入框非活动时格式化货币值。当用户将光标放在里面时,格式被删除,以便用户可以轻松地修改值。

    这是它的工作原理:

    my-currency-input 组件有一个计算值 - displayValue,其中定义了 getset 方法。在get方法中,如果输入框没有激活,则返回格式化的货币值。

    当用户在输入框中输入内容时,displayValue 计算属性的set 方法使用$emit 发出值,从而通知父组件此更改。

    在自定义组件上使用v-model 的参考:https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events

    【讨论】:

    • @BillCriswell 谢谢!甚至我比我的其他示例更喜欢这个,因为它是一个完全独立的组件,并且父模板是干净的。
    • 我喜欢你的方法,所以我稍微扩展了一下:jsfiddle.net/crswll/xxuda425/5
    • 谢谢@BillCriswell,你的例子看起来很干净!我不知道 toLocaleString,它处理点用于数字分隔符和逗号用于十进制的情况。它比使用复制粘贴的正则表达式要好得多,我还没有解码它是如何工作的。此外,将掩码指定为单独的输入也很棒!这将允许其他类型的输入格式,如日期格式器、非美元货币类型等。感谢您花时间在这方面,我将使用您的 jsFiddle 构建我的通用可重用输入组件:)
    • 这很好,谢谢,我已将它用于我的增强输入组件。我必须添加一个稍微凌乱的杂物才能让它像我想要的货币字段一样工作,即将实际值截断或四舍五入到小数点后 2 位(而不是仅仅显示它)。我添加了一个 @change 处理程序,它在值上调用 toFixed(2)。不过,我想知道这是否可以在 unmask 方法中更巧妙地处理?我找不到办法,我不得不说。
    • 好点。我现在在 toFixed 之后使用 parseFloat,它解决了这个问题。
    【解决方案2】:

    这是一个工作示例:https://jsfiddle.net/mani04/w6oo9b6j/

    它通过在聚焦和聚焦事件期间修改输入字符串(您的货币值)来工作,如下所示:

    <input type="text" v-model="formattedCurrencyValue" @blur="focusOut" @focus="focusIn"/>
    
    1. 当你将光标放在输入框内时,它会将this.currencyValue转换为纯格式,以便用户修改。

    2. 用户输入值并点击其他地方(焦点外)后,this.currencyValue在忽略非数字字符后重新计算,显示文本按要求格式化。

    货币格式化程序(reg exp)是从这里复制粘贴的:How can I format numbers as money in JavaScript?

    如果你不想要你提到的小数点,你可以在focusOut方法中做this.currencyValue.toFixed(0)

    【讨论】:

    • 这是我见过的唯一一种理智的、不烦人的输入掩码的方法。
    • 谢谢,我想要一个更接近Vue架构的解决方案。我尝试使用计算属性(丑陋的解决方案,我必须为每个货币输入添加一个计算属性)。现在当用户输入“1111”(字符串)时,模型值为 1111(数字)。然后用户在“1111”后输入“.22”,setter 去掉小数点。但是输入文本框是 1111.22,因为模型值仍然是 1111,不会调用 getter。
    • 我已经为这个问题添加了另一个答案。由于它涉及对 jsFiddle 示例的完全重写,我决定添加一个单独的答案而不是编辑这个答案。请看看它是否符合您的要求。我使用您指定的计算属性。小数点在内部处理,而显示仅显示您在格式化货币时在toFixed() 中指定的任何精度。
    【解决方案3】:

    我实现了一个组件。根据 Mani 的回答,它应该使用 $emit。

    Vue.component('currency', {
    template: '<input type="text"' +
                ' class="form-control"' +
                ' :placeholder="placeholder""' +
                ' :title="title"' +
                ' v-model="formatted" />',
    props: ['placeholder', 'title', 'value'],
    computed: {
        formatted: {
            get: function () {
                var value = this.value;
                var formatted = currencyFilter(value, "", 0);
                return formatted;
            },
            set: function (newValue) {
                var cleanValue = newValue.replace(",", "");
                var intValue = parseInt(cleanValue, 10);
                this.value = 0;
                this.value = intValue;
            }
        }
    }
    }
    

    );

    【讨论】:

      【解决方案4】:

      使用 Vue 自定义指令 + .toLocaleString() 也是一个很好的选择。

      Vue.directive("currency", {
        bind(el, binding, vnode) {
          el.value = binding.value && Number(binding.value).toLocaleString('en-US', {style: 'currency', currency: !binding.arg ? 'USD' : binding.arg });
          el.onblur = function(e) {
            e.target.value = Number(e.target.value).toLocaleString('en-US', {style: 'currency', currency: !binding.arg ? 'USD' : binding.arg});
          };
          el.onfocus = function(e) {
            e.target.value =
              e.target.value && Number(e.target.value.replace(/[^\d.]/g, ""));
          };
          el.oninput = function(e) {
            vnode.context.$data[binding.expression] = e.target.value;
          };
        }
      });
      

      这里是示例链接:https://codepen.io/Mahmoud-Zakaria/pen/YzPvNmO

      【讨论】:

        猜你喜欢
        • 2013-10-26
        • 2019-07-01
        • 1970-01-01
        • 2020-06-07
        • 1970-01-01
        • 2011-09-17
        • 2011-11-06
        • 2018-08-12
        • 1970-01-01
        相关资源
        最近更新 更多