自定义格式化程序¶
自定义格式化程序允许网站控制 Web 控制台 和 调试器 中变量的显示方式。
此功能对于处理复杂对象结构的 Web 应用程序、为原生变量定义对象的 JavaScript 框架或像 ClojureScript 这样编译成 JavaScript 的框架特别有用。
自定义格式化通过显示其变量更直观和信息丰富的表示形式来增强调试过程。
启用自定义格式化¶
要启用自定义格式化,请切换到 设置 面板,并在“高级设置”下选中名为“启用自定义格式化程序”的选项。此设置将在您下次打开 DevTools 时生效。
API¶
启用自定义格式化程序后,网站可以自定义 Web 控制台和调试器中某些变量的显示方式。这是通过使用名为 devtoolsFormatters
的全局数组定义自定义格式化程序来实现的。此数组中的每个条目都表示一个特定的格式化程序,它可能处理特定类型的变量。如果未为变量定义格式化程序,则使用其默认格式进行显示。
自定义格式化程序结构¶
每个格式化程序至少必须包含一个 header
函数。此函数必须返回一个 JsonML 数组或 null
。如果返回 null
,则将调用 devtoolsFormatters
中下一个条目的 header
函数。如果所有 header
函数都返回 null
,则将使用 DevTools 的默认渲染方式显示对象。
除了 header
函数外,格式化程序还可以包含 body
函数。 hasBody
函数指示 body
是否存在。如果 hasBody
返回 true
,则可以展开对象以显示更多详细信息。然后, body
函数返回实际主体。与 header
函数一样,它可以返回 JsonML 对象或 null
。
所有三个函数都将对象作为第一个参数,并将可选的配置对象作为第二个参数,这允许传递其他信息。
以下是这些函数的详细说明
header(object, config)
返回 JsonML 数组或
null
。如果返回null
,则使用默认格式显示对象。config
参数是可选的。可以使用特殊的object
模板传递此参数(请参阅 生成子元素)。hasBody(object, config)
返回一个布尔值,指示对象是否可以展开以显示更多详细信息。
config
参数是可选的。可以使用特殊的object
模板传递此参数(请参阅 生成子元素)。body(object, config)
返回 JsonML 数组或
null
。如果返回null
,则使用默认格式显示对象。config
参数是可选的。可以使用特殊的object
模板传递此参数(请参阅 生成子元素)。
HTML 模板格式¶
每个 HTML 模板都以基于 JsonML 标准的格式进行编码。每个元素都以以下格式表示为列表
[tagName, {"style": "name: value; ..."}, child1, …]
允许使用以下 HTML 标签
<span>
、<div>
、<ol>
、<ul>
、<li>
、<table>
、<tr>
和 <td>
。
可选的 style
属性可以包含 CSS 声明字符串。可以应用的 CSS 属性为
align*
background*
(background-image
仅允许data:
URL)border*
box*
clear
color
cursor
display
float
font*
justify*
line*
margin*
padding*
position
(仅接受static
和relative
值)text*
transition*
outline*
vertical-align
white-space
word*
writing*
width
min-width
max-width
height
min-height
max-height
子元素可以是另一个元素、字符串或对象引用。
生成子元素¶
可以通过定义特殊的 object
模板来创建子元素。此模板的格式为
["object", {"object": objectToInspect, "config": configObject}]
示例¶
简单示例¶
让我们来看一个简单的示例来说明自定义格式化程序的概念
window.devtoolsFormatters = [
{
header: variable => {
if (variable.hasOwnProperty('foo')) {
return [
'span', {
'style': `
font-family: "Comic Sans MS", fantasy;
font-size: 3rem;
color: green;
`
},
'foo'
];
}
return null;
}
}
];
在上面的示例中,为变量定义了一个自定义格式化程序。格式化程序的 header 属性是一个函数,用于确定变量的显示方式。在这种情况下,如果变量具有名为 foo 的属性,它将呈现为具有特定样式的 <span> 元素。它将像这样记录到 Web 控制台
完整示例¶
对于更复杂的示例,让我们考虑显示 Date 对象
<!DOCTYPE html>
<html>
<head>
<title>Custom formatter for dates</title>
</head>
<body>
<script>
window.devtoolsFormatters = [
{
header: obj => {
if (obj instanceof Date) {
return ['div', {'style': 'font-weight: bold;'},
`Date: ${obj.toLocaleDateString()} ${obj.toLocaleTimeString()}`
];
}
return null;
},
hasBody: obj => obj instanceof Date,
body: obj => {
if (obj instanceof Date) {
return ['div', {},
['div', {}, `Year: ${obj.getFullYear()}`],
['div', {}, `Month: ${obj.getMonth() + 1}`],
['div', {}, `Day: ${obj.getDate()}`],
['div', {}, `Hour: ${obj.getHours()}`],
['div', {}, `Minutes: ${obj.getMinutes()}`],
['div', {}, `Seconds: ${obj.getSeconds()}`]
];
}
return null;
}
}
];
</script>
</body>
</html>
使用此自定义格式化程序,记录到控制台的 Date
对象将以格式化的方式显示日期和时间,以及其各个组件的单独细分。在控制台中,对象将像这样记录
带有对象引用的示例¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Menu custom formatter</title>
<script>
const menu = [
{
url: '/',
text: 'Home',
},
{
url: '/nested',
text: 'Nested',
subitems: [
{
url: '/nested/1',
text: 'Nested 1'
},
{
url: '/nested/2',
text: 'Nested 2',
subitems: [
{
url: '/nested/2/1',
text: 'Nested 2.1'
},
{
url: '/nested/2/2',
text: 'Nested 2.2'
}
]
},
{
url: '/nested/3',
text: 'Nested 3'
}
]
},
{
url: '/about',
text: 'About'
},
{
url: '/contact',
text: 'Contact'
}
];
window.devtoolsFormatters = [
{
header: (obj, config) => {
if (obj instanceof Array && obj.every(item => item.hasOwnProperty('url') && item.hasOwnProperty('text'))) {
return ['div', {'style': 'font-weight: bold;'}, `Menu: ${obj.length} entries`];
}
return null;
},
hasBody: obj => obj instanceof Array && obj.every(item => item.hasOwnProperty('url') && item.hasOwnProperty('text')),
body: (obj, config) => {
const levelColors = ['red', 'blue', 'green'];
if (config === undefined) {
config = { level: 0 };
} else {
config.level++;
}
return ['div', {'style': `margin-left: 15px; color: ${levelColors[config.level % levelColors.length]}`}, ...obj.map(item => {
const subitem = ['div', ['div', `${item.text}: ${item.url}`]];
if (item.hasOwnProperty('subitems')) {
subitem.push(['object', {'object': item.subitems, config: {level: config.level}}]);
}
return subitem;
})];
}
}
];
console.log(menu);
</script>
</head>
<body>
</body>
</html>
此示例显示了一个带有嵌套子项的菜单对象。自定义格式化程序是递归的,因此它也将显示所有子项。此示例的输出如下所示
调试自定义格式化程序¶
如果自定义格式化程序包含错误,则会将错误消息记录到控制台,解释该问题。只要可能,错误消息还将包含指向代码中错误确切位置的源链接。
更多提示¶
分析要格式化的变量的结构和行为,了解区分它们的键属性或类层次结构。
在测试对象类型时,如果对象是特定类的实例,请使用
instanceof
。如果对象是普通对象,请使用hasOwnProperty
检查特定属性。使用不同类型的变量测试您的格式化程序,以确保它们按预期工作并准确地处理各种情况。
通过 生成子元素 嵌套格式化程序,以更易读的方式显示复杂对象。
使用
config
参数将其他信息传递给格式化程序,例如当前递归级别。如果您有多个格式化程序,请记住在每个格式化程序中检查对象的类型,并在对象不是预期类型时返回
null
。否则,格式化程序将应用于所有对象,这可能会导致意外行为。明智地选择您的格式。对于大型对象,最好仅显示对象的摘要,并在需要时允许用户展开它。
每个记录的对象都将调用格式化程序挂钩,这可能会影响性能。因此,您应该以小型且快速的挂钩为目标。
现有格式化程序¶
有现有的格式化程序可用于满足不同的需求。一些例子包括
andrewdavey/immutable-devtools:Immutable-js 值的自定义格式化程序
disjukr/vector-devtools:向量值的自定义格式化程序
binaryage/cljs-devtools:ClojureScript 开发人员的 DevTools 增强功能集合
Three.js 对象格式化程序