簡體   English   中英

為什么 vue.js 不使用 moment.js 使用 datepicker 更新 dom

[英]Why does vue.js not update the dom with datepicker using moment.js

我正在 vue.js 中編寫一個(非常)簡單的 datepicker 控件,使用 moment.js 來格式化和改變日期。

我遇到的問題是,即使在我單擊任一按鈕時修改了組件中的日期實例,顯示也不會更新。

我嘗試將其更改為簡單的整數而不是日期實例,並且按預期工作(DOM 已正確更新)

這是我為此提供的源代碼:

應用程序.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: {}
    }
});

索引.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/


以下是從庫中加/減的實現:

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 不是immutable的,這意味着當您在 moment 對象上調用 add/subtract 函數時,它返回相同的 object ,並在更改屬性后。

關於 vue 的反應性有一些警告,並且由於Object.observe現在已過時,它無法跟蹤 javascript 對象是否在內部發生了更改,除非您克隆該對象並創建一個您需要的新對象。

還有其他解決方法,包括使用凍結時刻庫。

問題是對 selectedDate 的引用永遠不會改變。 即使您在其上調用方法,它也是同一個對象。
這里的一種方法是以不同的格式存儲日期。 作為日期對象、數字等。然后,當您對其進行更改時,您可以生成該數據的新實例。

這是一個例子:

 var datePicker = Vue.component("datePicker", { data: function() { return { selectedDate: moment().toDate() } }, template: `<div> <button v-on:click='decrement'>&lt;</button> {{formattedSelectedDate}} <button v-on:click='increment'>&gt;</button> {{selectedDate}} </div>`, methods: { increment: function () { var currentDate = moment(this.selectedDate); currentDate.add(1, "days"); this.selectedDate = currentDate.toDate(); }, decrement: function () { var currentDate = moment(this.selectedDate); currentDate.subtract(1, "Days"); this.selectedDate = currentDate.toDate(); } }, computed: { formattedSelectedDate: function() { return moment(this.selectedDate).format("YYYY-MM-DD"); } } }); var PointTracker = new Vue({ el: "#PointTracker", data: { date: 0 }, components: { datePicker } });
 <div id="PointTracker"> <date-picker /> </div> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.js"></script>

這是因為 moment 和 vue 都依賴於定義對象的 getter 和 setter,這會導致在你的情況下一個覆蓋另一個。 (因此更改參考有效,因為vm.selectedDate.set被覆蓋,而vm.set未被覆蓋)

從時刻的文檔

Moment.js 使用重載的 getter 和 setter。

來自 vue 的文檔

Vue 會遞歸地將其屬性轉換為 getter/setter 以使其“反應”。 對象必須是普通的:瀏覽器 API 對象和原型屬性等原生對象將被忽略。 經驗法則是數據應該只是數據 - 不建議觀察具有自己狀態行為的對象。

快速驗證:我在創建的小提琴 saurabh 中添加了console.log(this.selectedDate.get) ,記錄的函數是stringGet中的moment.js ,然后我在我的項目中檢查了vm.fooget ,它是proxyGetter這是一個reactiveGetter的包裝器,都在vue.runtime.common.js中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM