我有一个奇怪的问题,我可以把它放在分数上,这样你就可以更好地理解。
请在浏览器中打开此小提琴Demo 1,如您所见,我正在使用highchart-ng https://github.com/pablojim/highcharts-ng angular指令来创建图表。这很好。
现在,请在新标签Demo 2中打开此链接,我刚刚使用了HTML5 localStorage。
我正在做的是
首先检查localStorage'图表中的图表数据,如果存在则使用它,否则
从硬编码的json变量$ scope.highchartsNG中绘制图表。
我的意思是:
if(JSON.parse(localStorage.getItem('chart'))){
console.log('FROM CACHE');
$scope.highchartsNG = JSON.parse(localStorage.getItem('chart'));
}else{
$scope.highchartsNG = {
options: {
...
...
}
为了清除localStorage,我提供了按钮
<input type='button' onclick='javascript:localStorage.clear();' value='clear localStorage' />
点击后,我正在使用localStorage.clear();
问题是当我从localstorage读取时,图表x轴和y轴标签的变化不同,但是如何?
请考虑以下步骤:
当您点击按钮&#39;清除localStorage&#39;,然后运行小提琴,您将获得正常的图表。 (这是正确的)好的,之后我将数据存储在
中localStorage.setItem(&#39; chart&#39;,JSON.stringify($ scope.highchartsNG));
现在
2.再次当你运行小提琴时,它进入if
块并从localstorage获取数据,然后图表x轴改变。为什么
答案 0 :(得分:0)
您看到不同结果的原因是JSON无法序列化功能(除其他外) 因此,当您将对象存储在localStorage中时,所有引用函数的属性(例如格式化程序)都会丢失。
<强>更新强>:
为了它的乐趣,我实现了一个简单的&#34;序列化器&#34;能够字符串化/解析简单的匿名函数(就像你的配置中使用的那样)。
您可以看到它的实际效果 here (并找到此 updated fiddle 中的代码)。
这不是一个通用的,一刀切的,生产就绪的解决方案,但它似乎适用于您的具体情况。
以下是其工作原理的快速概述:
当&#34;字符串化&#34;时,它首先遍历对象并将每个函数转换为字符串(使用其toString()
方法)。 (当天无用的提示:当没有使用内联数组表示法时,这是Angular用于识别注入的依赖项的内容。)
然后它使用JSON.stringify
来实际对字符串进行字符串化。
在解析时,它首先像往常一样解析字符串(使用JSON.parse
),然后遍历生成的对象,检测与RegExp匹配的字符串属性(旨在匹配匿名函数),最后转换那些字符串化函数到实际函数。
以下是代码:
.factory('JSONwithFn', function () {
var fnRE = /^[\s\r\n]*function[\s\r\n]*\([^\)]*\)[\s\r\n]*\{[\s\S]*\}[\s\r\n]*$/i;
function strToFn(str) {
var args = str.substring(str.indexOf('(') + 1, str.indexOf(')')).
split(',').
map(function (arg) {
return arg.trim();
});
var fnBody = str.substring(str.indexOf('{') + 1, str.lastIndexOf('}')).
trim();
args.push(fnBody);
return Function.apply(null, args);
}
function parseFns(obj) {
var retObj;
switch (Object.prototype.toString.call(obj)) {
case '[object Undefined]':
case '[object Null]':
case '[object Boolean]':
case '[object Number]':
case '[object Function]':
retObj = obj;
break;
case '[object String]':
retObj = fnRE.test(obj) ? strToFn(obj) : obj;
break;
case '[object Array]':
retObj = obj.map(function (value) {
return parseFns(value);
});
break;
case '[object Object]':
retObj = {};
Object.keys(obj).forEach(function (key) {
var value = obj[key];
retObj[key] = parseFns(value);
});
break;
default:
break;
}
return retObj;
};
function stringifyFns(obj) {
var retObj;
switch (Object.prototype.toString.call(obj)) {
case '[object Undefined]':
case '[object Null]':
case '[object Boolean]':
case '[object Number]':
case '[object String]':
retObj = obj;
break;
case '[object Function]':
retObj = obj.toString();
break;
case '[object Array]':
retObj = obj.map(function (value) {
return stringifyFns(value);
});
break;
case '[object Object]':
retObj = {};
Object.keys(obj).forEach(function (key) {
var value = obj[key];
retObj[key] = stringifyFns(value);
});
break;
default:
break;
}
return retObj;
}
return {
stringify: function (obj) {
var obj2 = stringifyFns(obj);
return JSON.stringify(obj2);
},
parse: function (str) {
var obj = JSON.parse(str);
return parseFns(obj);
}
};
});
只需将其注入您的控制器(或其他),然后使用JSNOwithFn.stringify/parse
代替JSON.stringify/parse
您的代码中无需更改任何其他内容
它会起作用:))
答案 1 :(得分:0)
就像ExpertSystem所说的那样,JSON.stringify
在序列化时会抛出你的格式化函数。
根据您要执行的操作,您可以将格式化程序功能单独存储在控制器中,并在从localstorage加载图表选项后重新分配。
控制器的顶部:
$scope.xAxisFormatter = function(){
return 'Week ' + this.value;
}
您的图表选项:
<snip...>
xAxis: {
tickInterval: 1,
allowDecimals: false,
labels: {
formatter: $scope.xAxisFormatter
}
},
<snip...>
从localstorage加载时:
$scope.highchartsNG = JSON.parse(localStorage.getItem('chart'));
$scope.highchartsNG.options.xAxis.labels.formatter = $scope.xAxisFormatter;