我在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'><</button>{{formattedSelectedDate}}<button v-on:click='increment'>></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>
答案 0 :(得分:8)
您必须更改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库。
答案 1 :(得分:0)
这是因为moment和vue都依赖于定义对象的getter和setter,这导致在你的情况下一个覆盖另一个。 (因此更改引用的工作原理是因为vm.selectedDate.set
被覆盖而vm.set
不被覆盖)
从时刻doc开始:
Moment.js使用重载的getter和setter。
来自vue的doc:
Vue将递归地将其属性转换为getter / setter以使其“被动”。该对象必须是明确的:忽略浏览器API对象和原型属性等本机对象。根据经验,数据应该只是数据 - 不建议观察具有自身状态行为的对象。
快速验证:我将console.log(this.selectedDate.get)
添加到创建的小提琴saurabh中,stringGet
中记录的函数为moment.js
,然后我检查了vm.foo
的{{1}}在我的项目中,它是get
proxyGetter
的{{1}}的包装器,reactiveGetter
。