我正在vue.js中编写一个(非常)简单的datepicker控件,使用moment.js格式化和更改日期。

我遇到的问题是,即使当我单击任一按钮时修改了组件中的日期实例,显示也不会更新。

我尝试将其更改为简单的整数而不是日期实例,并且按预期工作(DOM已正确更新)

这是我为此的源代码:

App.js

Vue.component("datePicker", {
    props: ["value"],
    data: function() {
        return { selectedDate: moment(this.value) };
    },
    template: "<div><button v-on:click='decrement'>&lt;</button>{{formattedSelectedDate}}<button v-on:click='increment'>&gt;</button></div>",
    methods: {
        increment: function () {
            this.selectedDate.add(1, "days");
            this.$emit('input', this.selectedDate);
        },
        decrement: function () {
            this.selectedDate.subtract(1, "days");
            this.$emit('input', this.selectedDate);
        }
    },
    computed: {
        formattedSelectedDate: function() {
            return this.selectedDate.format("YYYY-MM-DD");
        }
    }
});

var PointTracker = new Vue({
    el: "#PointTracker",
    data: {
        selectedDate: moment(),
        todoItems: {}
    }
});

Index.html
<html>
    <head>
        <meta charset="utf-8">
        <title>Point Tracker</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>

        <div id="PointTracker">
            <date-picker v-model="selectedDate">
        </div>

        <script src="node_modules/moment/moment.js"></script>
        <script src="node_modules/vue/dist/vue.js"></script>
        <script src="node_modules/vue-resource/dist/vue-resource.js"></script>
        <script src="app.js"></script>
    </body>
</html>

最佳答案

您必须更改selectedDate的引用,因为它是从moment函数返回的,它们始终是相同的引用,因此不会为这些触发vue观察者。

您必须进行以下更改才能更改引用:

methods: {
    increment: function () {
        this.selectedDate = moment(this.selectedDate).add(1, "days")
    },
    decrement: function () {
        this.selectedDate = moment(this.selectedDate).subtract(1, "days")
    }
},

工作提琴:http://jsfiddle.net/mimani/pLcfyrvy/1/

以下是add/subtract库中moment的实现:
function addSubtract (duration, input, value, direction) {
    var other = createDuration(input, value);

    duration._milliseconds += direction * other._milliseconds;
    duration._days         += direction * other._days;
    duration._months       += direction * other._months;

    return duration._bubble();
}

// supports only 2.0-style add(1, 's') or add(duration)
export function add (input, value) {
    return addSubtract(this, input, value, 1);
}

// supports only 2.0-style subtract(1, 's') or subtract(duration)
export function subtract (input, value) {
    return addSubtract(this, input, value, -1);
}

它返回相同的对象,因此对日期对象的引用相同。

为什么发生

之所以会发生这种情况,是因为moment.js是isn't immutable ,这意味着在更改属性之后,在带有矩值的对象it returns the same object上调用添加/减去函数。

vue的caveats上有一些reactivity,由于Object.observe现在已过时,因此无法跟踪javascript对象是否在内部进行了更改,除非您克隆该对象并创建您需要的新对象。

还有其他的workarounds,包括使用frozen-moment库。

10-05 20:43
查看更多