在可写的计算可观察量中包装localStorage无法破坏缓存

时间:2014-09-19 22:34:19

标签: knockout.js computed-observable

我是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。

2 个答案:

答案 0 :(得分: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'),
    ...
});

答案 1 :(得分:0)

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

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

的任何外部修改