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

Rya*_*ale 4 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
Run Code Online (Sandbox Code Playgroud)

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

Jef*_*ado 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;
    };
}());
Run Code Online (Sandbox Code Playgroud)

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

_.extend(DevUtilitiesViewModel.prototype, {
    ...
    logLevelsArray: ['error', 'warning', 'info', 'debug'],
    currentLogLevel: ko.localStorageObservable('logger-level'),
    ...
});
Run Code Online (Sandbox Code Playgroud)