【问题标题】:Vue js apply filter on v-model in an input fieldVue js在输入字段中对v-model应用过滤器
【发布时间】:2016-07-28 23:48:09
【问题描述】:

希望有人可以帮助我!我已经制定了一个指令,将 Jasny Bootstrap 插件更具体地包装为输入掩码,一切顺利!

现在我制作了一个自定义过滤器,支持时刻来格式化日期字段!

我从后端应用程序收到的日期格式是 YYY-MM-DD,我必须在视图上显示为 DD/MM/YYYY...我已经尝试过 v-model="date | myDate",但它不能正常工作!

JS

Vue.directive('input-mask', {
  params: ['mask'],

  bind: function() {
    $(this.el).inputmask({
      mask: this.params.mask
    });

  },
});

Vue.filter('my-date', function(value, formatString) {

  if (value != undefined)
    return '';

  if (formatString != undefined)
    return moment(value).format(formatString);

  return moment(value).format('DD/MM/YYYY');

});

var vm = new Vue({
  el: 'body',
  data: {
    date: '2015-06-26',
  }
});

HTML

<label>Date</label>
<input type="text" class="form-control" v-input-mask mask="99/99/9999" v-model="date">
<p>{{ date | myDate 'dd/mm/yyyy' }}</p>

如果有人感兴趣,有JSBin

提前致谢!

编辑:更好地解释我的期望 =)

当页面首次加载时,输入接收值 2015-06-26,我想将该值显示为 DD/MM/YYYY 所以 26/06/2015!只有在我开始输入内容后才能正常工作!

【问题讨论】:

  • “它不能正常工作”描述性不够。请解释如何它不能正常工作。你期待什么,它做了什么?
  • 对不起@MattJohnson!只是在底部添加了一个更好的解释!请看你是否明白!
  • 请注意,d/m/y 和 m/d/y 是不明确的,最好使用像 10-Apr-2016 这样的月份名称。
  • @RobG 在世界的某些地方(例如意大利),d/m/y 是司空见惯的,而其他一切只会让用户感到困惑。
  • @MarcoBolis——完全同意,m/d/y 只被少数人使用。但它在计算(尤其是网络)中无处不在,因此使用月份名称来消除歧义很有帮助。

标签: javascript jquery date momentjs vue.js


【解决方案1】:

我了解您要执行的操作,但是,由于使用 v-model 时的两种方式绑定,最好在从服务器接收到日期时格式化日期,然后将其与前端应用程序中所需的格式 ('DD/MM/YYYY')。

将数据发送回后端时,只需将其格式化回所需的服务器格式 ('YYYY-MM-DD')。

在您的 Vue 应用程序中,工作流程是这样的:

 new Vue({
    el: 'body',
    data: {
      date: null,
    },
    methods: {
        getDataFromServer: function() {
                // Ajax call to get data from server

                // Let's pretend the received date data was saved in a variable (serverDate)
                // We will hardcode it for this ex.
                var serverDate = '2015-06-26';

                // Format it and save to vue data property
                this.date = this.frontEndDateFormat(serverDate);
        },
        saveDataToServer: function() {
            // Format data first before sending it back to server
            var serverDate = this.backEndDateFormat(this.date);

            // Ajax call sending formatted data (serverDate)
        },
        frontEndDateFormat: function(date) {
            return moment(date, 'YYYY-MM-DD').format('DD/MM/YYYY');
        },
        backEndDateFormat: function(date) {
            return moment(date, 'DD/MM/YYYY').format('YYYY-MM-DD');
        }
    }
  });

这对我很有效,希望对你有帮助。

这是一个小提琴:

https://jsfiddle.net/crabbly/xoLwkog9/

语法更新:

    ...
    methods: {
        getDataFromServer() {
                // Ajax call to get data from server

                // Let's pretend the received date data was saved in a variable (serverDate)
                // We will hardcode it for this ex.
                const serverDate = '2015-06-26'

                // Format it and save to vue data property
                this.date = this.frontEndDateFormat(serverDate)
        },
        saveDataToServer() {
            // Format data first before sending it back to server
            const serverDate = this.backEndDateFormat(this.date)

            // Ajax call sending formatted data (serverDate)
        },
        frontEndDateFormat(date) {
            return moment(date, 'YYYY-MM-DD').format('DD/MM/YYYY')
        },
        backEndDateFormat(date) {
            return moment(date, 'DD/MM/YYYY').format('YYYY-MM-DD')
        }
    }
  })

【讨论】:

  • OP 想要“DD/MM/YYYY”,而不是“MM/DD/YYYY”(尽管由于两者都模棱两可,使用月份名称或缩写会更清楚)。
  • @RobG 谢谢,刚刚编辑。在这里打错字。只要是明确的,Moment 就会接受他想要的格式。
  • 不确定Vue在2016年的状态。但是我们可以使用computed属性来实现,代码会简单得多。
  • @RosdiKasim 计算属性自 v1.1 起在 Vue 中可用。但是,我不建议在这种情况下使用它们。不需要为每个日期保留两个响应式格式版本,至少出于上述目的。相反,我建议将这些日期格式化程序移动到实用程序 es6 模块中,使它们可在其他组件中重用。它也会清理上面的组件。
【解决方案2】:

当我想将输入值大写时遇到了类似的问题。

这就是我最终做的:

// create a directive to transform the model value
Vue.directive('uppercase', {
  twoWay: true, // this transformation applies back to the vm
  bind: function () {
    this.handler = function () {
      this.set(this.el.value.toUpperCase());
    }.bind(this);
    this.el.addEventListener('input', this.handler);
  },
  unbind: function () {
    this.el.removeEventListener('input', this.handler);
  }
});

然后我可以在带有v-model 的输入字段上使用此指令。

<input type="text" v-model="someData" v-uppercase="someData">

现在,每当我在此字段中输入或更改 someData 时,该值都会转换为大写。

这基本上做了我希望v-model="someData | uppercase" 会做的事情。但当然,你不能那样做。

总而言之:制作一个转换数据的指令,而不是过滤器

【讨论】:

  • 指令在页面加载或用户输入文本时起作用。当 UI 因其他控件的变化而被刷新时,不会调用指令上的 update 方法。文本框中的值将恢复为未格式化的值。
  • @flyfrog 我认为这里更好的选择是computed 属性
  • @flyfrog 你可以使用 inserted 选项来调用指令 onload。 vuejs.org/v2/guide/custom-directive.html#Hook-Functions
【解决方案3】:

转到 main.js 并添加以下代码:

import moment from 'moment'
Vue.filter('myDate', function (value) {
    if (value) {
        return moment(String(value)).format('dd/mm/yyyy')
    }
});

在您的 HTML 中执行以下操作:

<label>Date</label>
<v-text-field :value="date | myDate" @input="value=>date=value"></v-text-field>
<p>{{ date | myDate 'dd/mm/yyyy' }}</p>

所以我们使用上面的 v-bind 来绑定值和 @input 事件处理程序以具有 v-model 功能。

【讨论】:

  • 我不知道为什么这不是选择的答案。这以他想要的方式完美地解决了 OP 问题。我不确定它是否会起作用,但事实证明它就是这么简单。谢谢。
  • 谢谢,这有助于保持关注点分离。玩过视图模型,但这是一个比 VM 更好的解决方案。
【解决方案4】:

这就是我使用 watch 回调为 v-model 实现 vue 过滤器的方式,这不会在加载时更新值。

Vue.filter('uppercase', function (value) {
    return value.toUpperCase();
});

html:

<input type="text" v-model="someData">

还有手表回调:

watch:{
   someData(val) {
       this.someData = this.$options.filters.uppercase(val);
    },
}

【讨论】:

  • 非常有用!为避免在 watch 函数中递归调用,首先获取过滤后的值,将其与当前值进行比较,只有在不同时才设置if (this.someData != filteredVal) this.someData = filteredVal
【解决方案5】:

当您最初获得值时,调整它以适应输入。我让它在 ready 函数中工作,但你也可以在你的 DB 调用之后这样做:

ready: function(){    
  var year = this.date.substr(0, 4);
  var monDay = this.date.substr(5,5);
  var result = monDay + "-" + year;
  this.date = result.replace(/-/g,"/");
}

在备份到数据库的过程中,您可能也需要做类似的事情。

【讨论】:

    【解决方案6】:

    模板

    <input type="text" v-model="date" @change="onDateChange">
    

    组件

      methods: {
        onDateChange(event) {
          this.myDate = event.target.value
        }
        getFormatedDate(date) {
         return '2020/08/19'
        }
      },
      computed: {
        date() {
          return this.getFormatedDate(this.myDate)
        }
      }
    

    【讨论】:

      【解决方案7】:

      我想提供一个替代方案,来自 Vue 指令的钩子更新

      export default {
        data() {
          return {
            someData: '',
          }
        },
        directives: {
          lowercase: {
            update(el) {
              el.value = el.value.toLowerCase()
            },
          },
          uppercase: {
            update(el) {
              el.value = el.value.toUpperCase()
            },
          },
          capitalize: {
            update(el) {
              const lowerCase = el.value.toLowerCase()
              el.value = lowerCase.charAt(0).toUpperCase() + lowerCase.slice(1)
            },
          },
        },
      }
      

      Vue.directive('lowercase', {
        update(el) {
          el.value = el.value.toLowerCase()
        }
      })
      Vue.directive('uppercase', {
        update(el) {
          el.value = el.value.toUpperCase()
        }
      })
      Vue.directive('capitalize', {
        update(el) {
          const lowerCase = el.value.toLowerCase()
          el.value = lowerCase.charAt(0).toUpperCase() + lowerCase.slice(1)
        }
      })
      
      <input type="text" v-model="someData" v-capitalize />
      

      【讨论】:

        【解决方案8】:

        在文本字段上使用绑定值 示例:

        <v-text-field :value="string | stringFormat"></v-text-field>
        

        【讨论】:

          【解决方案9】:

          我发现我可以使用普通组件 v-bind:value / v-on:input dance 过滤输入,而无需使用 datawatch 子句,如果我在发出过滤值后调用 $forceUpdate()

          Vue 组件:

          {
            props: ['value'],
            methods: {
              mEmit: function(EVT) {
                const VAL      = EVT.target.value;
                var   FILTERED = myFilterFunction(VAL);
                this.$emit('input', FILTERED);
                this.$forceUpdate();
              }
            }
          }
          

          组件 HTML(数据在输入时被过滤):

            <input type="text" v-bind:value="value" v-on:input="mEmit($event)" />
          

          使用组件:

          <my-component v-model="myDataVar"></my-component>
          

          【讨论】:

            猜你喜欢
            • 2019-04-30
            • 2019-10-07
            • 2019-01-15
            • 1970-01-01
            • 1970-01-01
            • 2020-05-05
            • 2020-12-30
            • 2019-12-16
            • 1970-01-01
            相关资源
            最近更新 更多