@ oplitude/ session- replay- 浏览器
正式会话重放 SDK
安装
该软件包发布在国家预防机制登记册上,可用npm和纱线安装.
# npm
npm install @amplitude/session-replay-browser
# yarn
yarn add @amplitude/session-replay-browser
使用量
这个SDK提供了对"振幅会话回放"产品的访问.
此插件要求启用会话的默认跟踪 。 如果配置中未启用对会话的默认跟踪,插件会自动启用.
1. 进口宽度包
@amplitude/session-replay-browser
import * as sessionReplay from '@amplitude/session-replay-browser';
2. 初始化会话重放集
SDK必须通过以下代码配置. 此调用可踢出用户的回放集.
sessionReplay.init(API_KEY, {
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
sampleRate: 0.5,
});
3. 评价目标选择(可选)
在会话回放期间发生的任何事件,都必须交给SDK,以对照目标条件进行评估. 应该这么做 在此之前 第4步,获得事件属性。 如果您没有使用通过 Amplition UI 提供的目标条件逻辑,则不需要此步骤 .
const sessionTargetingMatch = sessionReplay.evaluateTargetingAndCapture({ event: {
event_type: EVENT_NAME,
time: EVENT_TIMESTAMP,
event_properties: eventProperties
} });
4. 获取会话重放事件属性
在会话重放期间发生的任何事件,都必须被标记为向振幅信号的属性,以将其纳入重放范围. 以下是如何使用属性的示例
const sessionReplayProperties = sessionReplay.getSessionReplayProperties();
track(EVENT_NAME, {
...eventProperties,
...sessionReplayProperties
})
5. 最新会议d
每当用户的会话 ID 更改时,必须将此更改通知会话重放 SDK 。 通过下列方法更新会话编号:
sessionReplay.setSessionId(UNIX_TIMESTAMP)
您也可以选择通过一个新的设备 ID 作为第二个参数 :
sessionReplay.setSessionId(UNIX_TIMESTAMP, deviceId)
6. 开始和停止录音(可选)
使用 stop() 暂停抓取而不拆卸 SDK (会话 id, 配置, 以及事件听众留在原地) 。 打电话 start() 继续 取样、确定目标和选择退出仍然适用—— start() 将不记录选择退出、不抽样或选择目标排除的会话.
// Pause capture, for example on a sensitive screen
sessionReplay.stop()
// Resume capture
sessionReplay.start()
stop() 冲出任何已经捕获的事件。 停止录制时的事件不标记为会话回放属性 .
7. 关闭(可选)
如果您想在任何时刻停止会话重放的集合, 例如在您的应用程序中您不希望被收集会话的部分, 您可以使用以下方法停止收集并删除收藏事件听众 。 之后 shutdown()电话 init() 重新开始.. start() 单凭一个人是不够的,因为听众已被删除.
sessionReplay.shutdown()
选项
| 名称 | 类型 | 需求 | 默认 | 说明 |
|---|---|---|---|---|
deviceId | string | 对 | undefined | 设置运行应用程序的设备的标识符. |
sessionId | number | 对 | undefined | 为当前会话的用户设置标识符。 值必须是自时代起的毫秒(Unix Timestamp). |
sampleRate | number | 没有 | 0 | 使用此选项来控制将选择多少会话进行回放收藏 。 将收集一个选定的会话进行回放,而未选择的会话将不进行回放. 数字应该是0到1之间的小数 0.01,代表您希望随机选择重放收藏的会话的分数。 在大量会议上, 0.01 将选择 1% 这些届会. |
optOut | boolean | 没有 | false | 设置为会话收集回放的权限 。 设置真实值可防止曝光度收集会话重放 . |
flushMaxRetries | number | 没有 | 2 | 设置失败的上传尝试的最大重试次数 。 这仅适用于可重试错误. |
logLevel | number | 没有 | LogLevel.Warn | LogLevel.None 或者说 LogLevel.Error 或者说 LogLevel.Warn 或者说 LogLevel.Verbose 或者说 LogLevel.Debug设置日志级别. |
loggerProvider | Logger | 没有 | Logger | 从 Logger 设置自定义日志机类, 以发送日志消息到想要的目的地 . |
serverZone | string | 没有 | US | 欧盟或美国。 设置振幅服务器区域。 设定为欧盟数据中心创建的振幅项目 . |
privacyConfig | object | 没有 | undefined | 支持高级口罩配置与 CSS 选择器. |
debugMode | boolean | 没有 | false | 添加额外的调试事件属性来帮助调试仪器问题(如不匹配的app). 只推荐调试初始设置,不推荐生产. |
configServerUrl | string | 没有 | undefined | 指定获取远程配置的端点 URL。 如果提供,它会覆盖默认服务器区配置. |
trackServerUrl | string | 没有 | undefined | 指定发送会话重放数据的端点 URL。 如果提供,它会覆盖默认服务器区配置. |
shouldInlineStylesheet | boolean | 没有 | true | 如果样式表被内化,样式表的内容将被存储. 在回放时,将使用所存储的样式表,而不是试图远程取取. 这可以防止由于缺少样式表而出现被损坏的回放. 注:内置样式表可能不会在所有情况下都有效。 如果这是 undefined 样式表将被内置. |
inlineImages | boolean | 没有 | false | 当真实时, 图像源被内入为 rrweb 快照中的数据 URL, 因此重放不依赖于在播放时获取远程图像资产 。 增加快照有效载荷大小。 传到rrweb's inlineImages 记录选项. |
storeType | string | 没有 | idb | 指定如何存储重放事件. idb 当所有事件在抓取时无法发送时,使用 IndexedDB 来持续重放事件. memory 存储重放事件只存在于内存中,指在页面关闭时事件会丢失. 如果索引DB不可用,系统会回到 memory。 。 。 . |
performanceConfig.enabled | boolean | 没有 | true | 如果启用, 事件压缩将会被推迟到浏览器闲置期间进行. |
performanceConfig.timeout | number | 没有 | undefined | 可选超时( 毫秒) requestIdleCallback API (英语). 如果指定,这个值将用来设定浏览器在执行被推迟的压缩任务之前等待的最大时间,即使浏览器没有闲置. |
useWebWorker | boolean | 没有 | false | 如果是真的,SDK会使用网络工人来压缩回放事件. 这个卸载压缩到一个单独的线程,提高了主线程上的性能. |
crossOriginIframes.enabled | boolean | 没有 | false | 启用跨源iframe记录 。 必须设定为 true 在母页和每个孩子的iframe页上。 见 跨奥里金框架记录。 。 。 . |
crossOriginIframes.coordinateChildren | boolean | 没有 | true | 何时 true中,父母SDK自动向通过 postMessage设置为 false 管理孩子记录生命周期你自己. |
handleSendEvents | function | 没有 | undefined | 自定义重放事件上传的传输 。 允许您完全拥有输出的 HTTP 呼叫( 例如, 附加 JWT) Authorization 在SDK继续分批,重试和串行化的同时,通过认证的代理机头和路由). 见 自定义运输。 。 。 . |
handleFetchConfig | function | 没有 | undefined | 自定义远程配置获取的传输 。 合同与 handleSendEvents,为配置获取。 见 自定义运输。 。 。 . |
自定义运输(认证代理/JWT)
默认情况下, SDK 发送重放事件并获取其内部的远程配置 fetch。 。 。 .
如果您的环境要求每一次外出通话都有自定义请求逻辑—— 例如 JWT
Authorization 向 Amplition 转发前, 由您的代理机构验证页眉
handleSendEvents 和(或) handleFetchConfig 召回电话。 SDK手 每一个召回a
完全成型的请求和召回的唯一工作是执行并返回 Response编辑
SDK 保存其他所有文件: URL 分辨率(包括 trackServerUrl 编号 : configServerUrl, (中文(简体) ),
分批、重试/后退、序列化、压缩和错误处理.
import * as sessionReplay from '@amplitude/session-replay-browser';
import type { SendEventsRequest, FetchConfigRequest } from '@amplitude/session-replay-browser';
sessionReplay.init(API_KEY, {
deviceId,
sessionId,
// Optional: point at your proxy. The resolved URL is passed into the callbacks.
trackServerUrl: 'https://my-proxy.example.com/sr-events',
configServerUrl: 'https://my-proxy.example.com/sr-config',
handleSendEvents: async ({ url, method, headers, body, keepalive }: SendEventsRequest) => {
return fetch(url, {
method,
// Spread the SDK headers so you don't drop Content-Encoding etc., then add your auth.
headers: { ...headers, Authorization: `Bearer ${getJwt()}` },
body,
keepalive, // forward this so page-exit batches survive unload
});
},
handleFetchConfig: async ({ url, method, headers, signal }: FetchConfigRequest) => {
return fetch(url, {
method,
headers: { ...headers, Authorization: `Bearer ${getJwt()}` },
signal, // honor the SDK's fetch-timeout abort signal
});
},
});
对于饼干认证的代理,省略 Authorization 页眉并添加 credentials: 'include'
相反,形状在其他方面是相同的.
连接它为您的整合
无论您如何安装会话重放, 两个回调是相同的 你通过他们的地方
内 变化。 以上实例是: 独立 SDK(英语:SDK). 如果您使用分析插件或
统一 SDK, 放下相同的 handleSendEvents 编号 : handleFetchConfig 输入您已有的条目 :
插头 - @amplitude/plugin-session-replay-browser (与 @amplitude/analytics-browser:
import * as amplitude from '@amplitude/analytics-browser';
import { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser';
amplitude.add(
sessionReplayPlugin({
sampleRate: 1,
trackServerUrl: 'https://my-proxy.example.com/sr-events',
configServerUrl: 'https://my-proxy.example.com/sr-config',
handleSendEvents: async ({ url, method, headers, body, keepalive }) =>
fetch(url, { method, headers: { ...headers, Authorization: `Bearer ${getJwt()}` }, body, keepalive }),
handleFetchConfig: async ({ url, method, headers, signal }) =>
fetch(url, { method, headers: { ...headers, Authorization: `Bearer ${getJwt()}` }, signal }),
}),
);
amplitude.init(API_KEY);
统一—— @amplitude/unified (回叫声在下面) sessionReplay 块 :
import { initAll } from '@amplitude/unified';
initAll(API_KEY, {
sessionReplay: {
sampleRate: 1,
trackServerUrl: 'https://my-proxy.example.com/sr-events',
configServerUrl: 'https://my-proxy.example.com/sr-config',
handleSendEvents: async ({ url, method, headers, body, keepalive }) =>
fetch(url, { method, headers: { ...headers, Authorization: `Bearer ${getJwt()}` }, body, keepalive }),
handleFetchConfig: async ({ url, method, headers, signal }) =>
fetch(url, { method, headers: { ...headers, Authorization: `Bearer ${getJwt()}` }, signal }),
},
});
本节其他一切——合同,代理方要求,网工支持—— 适用于所有三个方面.
合同
SDK保证你的回话:
- 它传递了一个完全成型的请求(已解析的URL,默认头,序列化正文). 你唯一一份工作是怎样的
执行并返回 a
Response。 。 。 . - 这叫回调 每个逻辑请求尝试一次。重试/后退由 SDK 处理 周围 召回,所以不要执行您自己的重试.
- Non-2xx 回复和扔出错误 / 被拒绝的许诺被浮出SDK的现有重试 和记录逻辑, 正是内在路径对待他们.
SDK从你的回话中要求的:
- 它必须返回a
Response(或类似反应的物体与ok, (中文(简体) ),status, (中文(简体) ),text()) (中文(简体) ). - 它不能改变SDK供给体的语义. 运输时
压缩活动,
body是一个gzipUint8Array财务报告和审定财务报表headers已包含Content-Encoding: gzip,所以保持它们在一起(在转发 压缩后的身体,否则有效载荷不会解码服务器侧.
页:1
- 你拥有的是Auth,而不是"振荡". 振幅永远不会验证您的 JWT; 认证发生在 您的代理, 将请求( 重认证) 转发到 Amplition .
- 支持Web Worker模式. 何时
useWebWorker: trueSDK不断压缩 主线和代表只有网络调回主线来运行您的回调. - 页面出道. 在卸下通常使用的 SDK 时
navigator.sendBeacon,不能携带自定义 头. 何时handleSendEvents已经设定, SDK 转而通过您的最后批次 调用keepalive: true,因此出口批次仍然经过认证. - 覆盖所有外出交通. 何时
handleSendEvents每出一出,都用它做工具 会话重放请求: 重放事件上传,出页信标,以及交互/滚动 信标(以其他方式通过navigator.sendBeacon也不愿携带你的宝物。 所以没有 会话重放请求未校正页面 .
执行代理方
上面的回调只是故事的一半 ——用您从浏览器中获取请求 认证附后。 另一个是 您的代理服务器,它必须检查认证,然后转发 请求到振幅。 你建立和运行这个代理; 振幅不提供一个, 而你不提供 需要我们站起任何新的终点。 这是所有你需要的 使它正确.
向何处前进
您的代理转发到 Amplitude 现有的公开会话 重放结束点 — 和 SDK 相同的 会直接击中。 选择匹配您项目数据区域的行 :
| 什麽 | 美国 | 欧盟 |
|---|---|---|
重放事件( POST 从 handleSendEvents(中文(简体) ) | https://api-sr.amplitude.com/sessions/v2/track | https://api-sr.eu.amplitude.com/sessions/v2/track |
远程配置 GET 从 handleFetchConfig(中文(简体) ) | https://sr-client-cfg.amplitude.com/config | https://sr-client-cfg.eu.amplitude.com/config |
因此,往返只是: 浏览器 / 您的代理 / 高度 / 您的代理 / 浏览器 . 您的代理服务器 坐在中间,检查JWT, 并转发其他一切通过.
您的代理机构需要做什么
-
验证你的认证,然后剥去它. 读取JWT(或您在召回中附上的任何内容), 随你安全小组如何核实 拒绝请求 不要通过你的 JWT上"振幅"——振幅不知道是什么,也不需要.
-
将路径和查询字符串保持原样 . SDK 构建 URL 如
…/sessions/v2/track?device_id=…&session_id=…&type=replay财务报告和审定财务报表…/config/<apiKey>?config_group=browser. 这些查询段落很重要——转发它们不变. 不要掉下来或重写它们. -
把尸体移开,保持原状
Content-Encoding。 。 。 . 重播体型通常为克兹克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克, 请求载有Content-Encoding: gzip标题是这样说的。 通过字节 和收到的一样,保持头部。 如果你解压, 重新压缩, 或者放下头条, 振幅无法读取有效载荷. -
确定振幅仍然能看到您的 API 键 . 这是旅行的人 见下文.
API- key gotcha (读这个)
从您的图像中识别您的工程 高度 API 密钥SDK放进去的
Authorization: Bearer <amplitudeApiKey> 头曰. 如果你的回话是显而易见的
覆盖 aPI 键在请求离开时已消失
浏览器 – Amplition 将拒绝转发的请求, 因为无法分辨哪个工程
属于.
治取二法. 我们推荐第二个 - 更简单更难搞错
-
选项 A — 您的代理将 API 密钥放回 . 您的回调覆盖
Authorization与 jWT; 您的代理验证了 JWT, 然后互换Authorization返回到Bearer <amplitudeApiKey>在转发前。 有用,但你的代理现在必须知道你的高度 API密钥. -
选择B(建议)——将JWT发送到不同的标题. 离开SDK的
Authorization单枪匹马地把你的JWT放在别处,例如:.X-Customer-Auth您的代理检查 头条,把它剥去, 并转发其他一切(包括未触及的)Authorization直线 通过。 您的代理从不需要知道或处理 Amplition API 密钥 .handleSendEvents: async ({ url, method, headers, body, keepalive }) => fetch(url, { method, // Don't overwrite Authorization — add the JWT under your own header instead. headers: { ...headers, 'X-Customer-Auth': await getJwt() }, body, keepalive, }),
快速疗养检查
一旦你的代理机上架,做一个快速的端到端测试: 用SDK指向你的代理机加载一页,
并确认(a) 您的代理日志显示 JWT 到达并正在验证
(b) 重放实际出现在Amplitude。 如果重播不降落,几乎总是四人之一
以上分数——最常使用API-键头头(上方为gotcha)或下放 Content-Encoding。 。 。 .
跨奥里金框架记录
SDK可以捕捉到跨源内的事件 <iframe> 元素并将其合并到主页的会话回放中.
如何运作
母页和每个 Iframe 页面必须装入 SDK crossOriginIframes.enabled: true。父母SDK使用 postMessage 信号和rweb的内置 跨源中继.
Parent page (yoursite.com)
┌─────────────────────────────────────────────────────────────────┐
│ sessionReplay.init(API_KEY, { crossOriginIframes: { enabled: true } })
│ │
│ CrossOriginIframeCoordinator │
│ ┌────────────────────────┐ │
│ │ MutationObserver │ postMessage("start") ──────────────► │
│ │ watches for <iframe> │ │
│ │ additions/removals │ postMessage("stop") ──────────────► │
│ └────────────────────────┘ │
│ │
│ rrweb (recordCrossOriginIframes: true) │
│ ◄─────────────── child rrweb events relayed via postMessage ──── │
│ Merges child events into parent snapshot stream │
└─────────────────────────────────────────────────────────────────┘
│ postMessage("start" / "stop")
▼
Child iframe page (payments.example.com)
┌─────────────────────────────────────────────────────────────────┐
│ sessionReplay.init(API_KEY, { crossOriginIframes: { enabled: true } })
│ │
│ isInIframe() === true → child mode │
│ listenForParentSignals() │
│ ┌──────────────────────────────────┐ │
│ │ Waits for "start" signal │ │
│ │ → initialises rrweb recording │ │
│ │ On "stop" signal │ │
│ │ → stops rrweb, flushes events │ │
│ └──────────────────────────────────┘ │
│ │
│ rrweb events ──► postMessage relay ──► parent rrweb │
└─────────────────────────────────────────────────────────────────┘
儿童活动由儿童网页本身的rrweb实例进行序列化,并通过 postMessage。父 rrweb stream 存储它们内置,因此再播放查看器可以从单个会话中重建两个帧.
设置
父页面 :
sessionReplay.init(API_KEY, {
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
crossOriginIframes: { enabled: true },
});
儿童 Iframe 页面 (也必须装入SDK):
sessionReplay.init(API_KEY, {
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
crossOriginIframes: { enabled: true },
});
儿童SDK检测它正在一个iframe内运行并自动进入儿童模式——它会等父母发出起动信号,而不是立即开始录制.
选项
| 名称 | 类型 | 需求 | 默认 | 说明 |
|---|---|---|---|---|
crossOriginIframes.enabled | boolean | 对 | —— 说 | 启用父版和子版的跨源iframe记录. |
crossOriginIframes.coordinateChildren | boolean | 没有 | true | 何时 true,父母SDK向孩子iframes发送起/止信号并保持其记录生命周期同步. 设定为 false 管理孩子记录自己. |
隐私
儿童网页的rrweb实例进行自己的DOM序列化. 父的隐私配置( 任务级别、 块选择器等) 没有 自动在 iframe 内应用 —— 独立配置儿童页面上的隐私设置.
限制
- 第三方框架 (如花纹,Google Maps)无法被捕获. 父页和子页必须装入 SDK
crossOriginIframes.enabled: true。 。 。 . coordinateChildren: false选择退出协奏器;在此模式下,孩子SDK在直接管理其生命周期之前不会开始录音.
网络请求抓取
SDK可以捕捉通过 fetch 并将它们作为活动列入会话重放。 此选项默认已禁用 .
基本设置
通过设置启用远程配置的网络捕获 sr_logging_config.network.enabled: true。除了标准的SDK初始化外,不需要修改代码.
请求和答复机构
身体捕捉是网络捕捉中一个单独的选入. 为了启动它,设置 body.request 和(或) body.response 在网络配置中 :
// This is configured server-side via sr_logging_config, not in the SDK init call.
// The shape of the remote config that enables body capture:
{
sr_logging_config: {
network: {
enabled: true,
body: {
request: true, // capture fetch request bodies
response: true, // capture fetch response bodies
maxBodySizeBytes: 10240, // optional, defaults to 10KB
}
}
}
}
行为
- 请求机构: 为
string, (中文(简体) ),URLSearchParams,以及FormData身体类型.Blob, (中文(简体) ),ArrayBuffer,以及ReadableStream尸体被跳过. - 反应机构:收到答复后抓取. 二进制内容类型( E)
image/*, (中文(简体) ),audio/*, (中文(简体) ),video/*, (中文(简体) ),application/octet-stream, (中文(简体) ),font/*)被跳过,事件将responseBodyStatus: 'skipped_binary'。 。 。 . - 截断: 超过
maxBodySizeBytes被切入到限制内(多字节字符的字节精确)。 活动将responseBodyStatus: 'truncated'。 。 。 . - 错误: 如果读取响应正文失败, 事件将会有
responseBodyStatus: 'error'。 。 。 .
网络事件字段
| 外地 | 类型 | 说明 |
|---|---|---|
url | string | 请求 URL |
method | string | HTTP 方法 |
status | number | 反应状态代码 |
duration | number | 以毫秒计的往返时间 |
requestHeaders | object | 请求信头 |
responseHeaders | object | 答复信头 |
requestBody | string | 请求正文( 如果启用实体抓取) |
responseBody | string | 反应机构(如果能够捕获尸体) |
responseBodyStatus | string | 'captured', (中文(简体) ), 'truncated', (中文(简体) ), 'skipped_binary',或 'error' |
error | object | 如果请求失败, 错误名称和信件 |
释放
预发件通过电子邮件向 npm 发布 发布 v2.x GitHub 动作工作流程 。 已发布的软件包会被标记为分支名(例如. @amplitude/session-replay-browser@SR-2728所以它不会影响 latest dis.
步骤
- 转到 动作 – 发布 v2.x 在 GitHub 重播时
- 点击 运行工作流程
- 设定输入 :
- 使用工作流程从数字 :
main(需要——工作流程执行) - 发行类型数字 :
prerelease - 分支创建预释: 您的特性分支( 如 .
SR-2728(中文(简体) )
- 使用工作流程从数字 :
- 点击 运行工作流程
工作流程将:
- 检查您的特性分支
- 构建和运行测试
- 使用常规承诺跳出版本,以分支名称为前缀(如:.
1.33.0-SR-2728.0(中文(简体) ) - 以 npm 发布
--tag <branch-name>
安装预放
npm install @amplitude/session-replay-browser@SR-2728
# or a specific version:
npm install @amplitude/[email protected]
页:1
- 这个
--tag值来自有非字母的分支名称(除-剥去,所以SR-2728标签SR-2728, (中文(简体) ),feature/my-branch标签featuremy-branch - 从除此以外的分支触发
main将失败授权检查——总是使用main在“ 使用工作流程从” 下拉
组合大小优化
会话重放SDK使用动态导入来优化捆绑大小并改进初始页面负载性能. 关键模块按需加载,而不是包含在初始捆绑中 :
@amplitude/rrweb-record: 当sessionReplay.init()应该开始抓捕。 在用户没有取样或选择退出的情况下,会话重放SDK将不会导入这些依赖性.
这种办法确保:
- 您应用程序的初始 JavaScript 捆绑仍尽可能小 .
- 只装入必要的会话重放依赖 .
动态导入是同步进行的,不会阻碍您的应用程序初始化. 如果进口因任何原因失败,SDK将不会启动捕获.
隐私
默认情况下,会话重放会掩盖所有输入,这意味着输入中的文本会以星号重放的形式出现: ***。您可能根据您的使用情况需要更具体的遮盖控制,所以我们提供以下控制:
1. 解密投入
在您的应用程序代码中, 添加类 .amp-unmask 对任意 投入 你想在重播中解开他的短信 在会话回放中,可以读取输入此类输入的准确文本,文本不会被转换为星号.
2. 面具非输入要素
在您的应用程序代码中, 添加类 .amp-mask 对任意 非输入元素 你希望从重播中掩盖出他的短信 元素中的文本,以及它的孩子,都会被转换为星号.
3. 块式非文本元素
在您的应用程序代码中, 添加类 .amp-block 到任何您想要从重播集中屏蔽的元素。 该元素会作为具有相同维度的占位符出现在回放中.
4. CSS选取器的块状元素.
在SDK初始化代码中,可以配置SDK来以基于CSS选择器来阻断元素.
sessionReplay.init(AMPLITUDE_API_KEY, {
sampleRate: 0.01,
privacyConfig: {
blockSelector: ['.ignoreClass', '#ignoreId']
}
})
5. 使用数据属性
使用 data-amp-block, (中文(简体) ), data-amp-mask,以及 data-amp-unmask 作为替代
amp-block, (中文(简体) ), amp-mask,以及 amp-unmask 课程。 不需要配置 .
<section data-amp-block>Excluded from replay</section>
<p data-amp-mask>Masked text</p>
<input data-amp-unmask />
属性存在使注释成为可能,而不论其价值如何。 明确 在元素或祖先上蒙上面具优先于取出面具,并被屏蔽 亚树仍被排除在外.