4

我是 KnockoutJS 的新手,很想知道这是否可能。我正在尝试将本地存储对象包装在可写计算中,以便我可以利用 KnockoutJS 的自动绑定优势。但是,“读取”操作不引用任何可观察对象 - 因此初始值永远不会更新:

<select data-bind="foreach: logLevelsArray, value: currentLogLevel">
    <option data-bind="attr: { value: $index() }, text: $data"></option>
</select>

_.extend(DevUtilitiesViewModel.prototype, {
    ...
    logLevelsArray: ['error', 'warning', 'info', 'debug'],
    currentLogLevel: ko.computed({
        read: function() {
            return localStorage.getItem("logger-level");
        },
        write: function( newValue ) {
            localStorage.setItem("logger-level", newValue);
        }
    })
    ...
});

DevUtilitiesViewModel.currentLogLevel(); // 2 (default)
DevUtilitiesViewModel.currentLogLevel(4);
localStorage.getItem("logger-level"); // 4 - write was successful
DevUtilitiesViewModel.currentLogLevel(); // 2 - still the original value

我了解这是预期的行为,并且我了解原因。我也明白我可以制作currentLogLevel一个简单的 observable 并订阅它并以这种方式更新本地存储。但是我必须跟踪订阅并手动处理它,编写更多代码等等。我只是想看看是否有办法做我想做的事情:为本地存储提供一个可观察的 getter/setter。

4

2 回答 2

6

您需要提出一个方案,以便在本地存储发生任何更改时通知您,以便您可以依赖它们。

装饰localStorage.setItem()函数(以及可选的localStorage.removeItem()函数)以通知任何更改。还要收听storage来自其他打开选项卡的更改的事件。

有了这个,我们需要注册一个对你的 observable 的依赖。看起来唯一的方法是使用 observable 作为通知源并调用它。您可以将此逻辑包装在localStorageObservable.

(function () {
    var localStorageObserver = ko.observable();

    function notifier(fn) {
        return function () {
            fn.apply(this, arguments);
            localStorageObserver.notifySubscribers(arguments[0]);
        };
    }
    localStorage.setItem = notifier(localStorage.setItem);
    localStorage.removeItem = notifier(localStorage.removeItem);
    window.addEventListener('storage', function (event) {
        localStorageObserver.notifySubscribers(event.key);
    }, false);
    // not sure how to capture changes in the form:
    //     localStorage.property = value;

    ko.localStorageObservable = function (key) {
        var target = ko.dependentObservable({
            read: function () {
                localStorageObserver(); // register on any changes
                return localStorage.getItem(key);
            },
            write: function (value) {
                localStorage.setItem(key, value);
            }
        });
        target.key = key;
        return target;
    };
}());

有了这个,您现在可以与本地存储同步。

_.extend(DevUtilitiesViewModel.prototype, {
    ...
    logLevelsArray: ['error', 'warning', 'info', 'debug'],
    currentLogLevel: ko.localStorageObservable('logger-level'),
    ...
});
于 2014-09-20T16:23:28.230 回答
1

如果您只想检测何时使用可写可计算的write方法,则可以使用 aobservable来轻松处理通知:

currentLogLevel: ko.computed({
    owner: ko.observable(localStorage.getItem("logger-level")),
    read: function() { return this() },
    write: function( newValue ) {
        localStorage.setItem("logger-level", newValue);
        this( newValue );
    }
})

请记住,虽然这不会检测到任何外部修改localStorage

于 2015-11-05T16:03:42.063 回答