5

将 JSON 数据格式输出至页面上

 3 years ago
source link: https://anran758.github.io/blog/2019/08/24/js-%E5%B0%86JSON%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F%E8%BE%93%E5%87%BA%E8%87%B3%E9%A1%B5%E9%9D%A2%E4%B8%8A/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

将 JSON 数据格式输出至页面上

发表于 2019-08-24 更新于 2020-11-01 分类于 JavaScript 阅读次数: 714 Disqus: 0 Comments 本文字数: 4.3k 阅读时长 ≈ 5 分钟

JSON 是一种轻量级的数据交换格式,它有键值对集合(js 中的对象)和数组两种结构。JSON是一个通用的格式,在前后端语言中都能跟该 JSON 打交道。

有时候我们需要将 JSON 格式输入至页面展示的需求,其中还需要保持一定的索引,那么该如何实现呢?

我们将对象转为 JSON 字符串时会经常使用 JSON.stringify 这个 API,其实该方法就内置有格式化的参数:

var userInfo = {name: 'anran758',github: 'https://github.com/anran758'};
var info = JSON.stringify(userInfo, null, 2);

console.log(info);
// "{↵ "name": "anran758",↵ "github": "https://github.com/anran758"↵}"

在上面的代码中,我们第一个参数(value)传入了一个需要序列化的对象。第二个参数是replacer,用以对属性转换和处理,由于我们不需要额外的处理,因此传入一个null;第三个参数则是空格索引的个数,封顶是100或不传则没有空格。

在控制台打印出信息后,我们可以看的出来格式化的数据是带换行符,并且有缩进的格式。接下来我们就要考虑如何输出到页面中。

只要学过HTML的朋友都知道,我们直接将数据输入至HTML中,空格缩进会被浏览器给忽略掉的。因此不能输入到 <div> 中。这时候又想到,JSON格式实际上也算是代码的一种,那能不能输入至雷士代码块的标签中呢?答案是可以的。

HTML 中有两个标签可以展示源代码: <pre><code> 。它们之间不同之处在于:

  • <pre> 表示预定义格式文本,按照原文件中的编排,以等宽字体的形式展现出来,文本中的空白符(比如空格和换行符)都会显示出来
  • <code> 则是呈现一段计算机代码,它以浏览器的默认等宽字体显示,但并不一定会完整呈现原来的格式

这些标签知识实际上算是比较冷门的知识,或许远古的面试题会考这种知识点,平时很少会遇到。但是如果你经常使用markdown的话,那么这些标签在markdown中有不同的别名:

比如 markdown 语法中的 ``,实际上等同于 <code> 标签。实际作用是短代码块标签

而 markdown 语法中的长代码块就等同于 `<pre>` 标签,不同的博客或者网站的应用中还可以对 `<pre>` 加类名,用以展示不同的语言的语法高亮。

通过三者之间的对比可以看出,只有 <pre> 才是符合我们需求的。

确定好展示的方式后,就可以考虑进一步扩展格式化的功能。比如对象中还有属性是 JSON 字符串的话,咱也进一步的解析,直至最底层。想实现这种功能需要编写一个递归函数,考虑如下代码:

const isPlainObject = (v) => Object.prototype.toString.call(v) === "[object Object]"
const isString = (v) => Object.prototype.toString.call(v) === "[object String]"

/**
* 格式 JSON 字符串为对象
*
* @author anran758
* @param { any }
*/
function formatJsonStrAsObj(sample) {
let temp = sample;

if (isString(temp)) {
// 因为有解析失败的可能,使用 try catch 做相应处理
try {
temp = JSON.parse(temp);
} catch (ex) {
// parse error,return this sample
return sample;
}
}

if (isPlainObject(temp)) {
temp = { ...temp };

Object.keys(temp).forEach(key => {
const item = temp[key];

// 字符串或者对象进行递归确认
if (isString(item) || isPlainObject(item)) {
temp[key] = formatJsonStrAsObj(item);
}
});
}

return temp;
}

/**
* 将 JSON 字符串转换为带缩进的字符串
*
* @param {*} sample JSON 字符串
* @param {number} [indnt=2] 缩进数
* @returns
*/
function formatJSONIndnt(sample, indnt = 2) {
const newSample = formatJsonStrAsObj(sample);

if (isString(newSample)) return newSample;

try {
return JSON.stringify(newSample, null, indnt);
} catch (ex) {
return newSample.toString();
}
}

const info = JSON.stringify({
name: 'anran758',
avatar: 'https://xxx',
detail: JSON.stringify({
desc: 'some description',
level: 2,
})
})
const data = formatJSONIndnt(info);
console.log(data);

// 可以直接将 data 输出至 dom 中

上文讲了如何将数据输出至页面,以及扩展格式化功能的示例。接下来讲解输入方面的应用。

当用户从别的地方复制数据想粘贴至输入框时,可以在输入框上设置监控事件,触发事件后尝试帮用户格式化数据,示例代码如下:

<div class="container">
<pre class="preview pre"></pre>
<textarea class="textarea"></textarea>
</div>
const info = JSON.stringify({
name: 'anran758',
avatar: 'https://xxx',
detail: JSON.stringify({
desc: 'some description',
level: 2,
})
})
const data = formatJSONIndnt(info);

const textarea = document.querySelector('.textarea');
const preview = document.querySelector('.pre');

preview.innerHTML = data;
textarea.addEventListener('paste', (e) => {
// 阻止默认事件
e.preventDefault();
const value = (e.clipboardData || window.clipboardData).getData('text');

// 这里使用了上面定义的函数,进行格式化数据
e.target.value = formatJSONIndnt(value, 2);
})
body {
display: flex;
margin: 0;
justify-content: center;
align-items: center;
padding: 0 10px;
box-sizing: border-box;
min-height: 100vh;
}

.container {
display: flex;
width: 100%;
}

.preview {
flex: 1;
margin-bottom: 20px;
padding: 20px;
background: #f5fcff;
border: 1px solid #d3eeff;
border-radius: 3px;
margin: 0;
}

.textarea {
flex: 1;
margin-left: 20px;
padding: 10px;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
monospace;
}

.preview + .preview {
margin-left: 10px;
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK