1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
---
title: MozAfterPaint
slug: Web/Events/MozAfterPaint
translation_of: Archive/Add-ons/Events/MozAfterPaint
---
<p><code>MozAfterPaint事件在页面呈现给用户屏幕时触发,并提供页面重绘的信息,主要应用于页面优化审查。</code></p>
<p><code>注意</code>MozAfterPaint并非在页面重绘时立即触发,而是在重绘并合成后发生。这意味着有部分内容触发时已经呈现给客户。</p>
<div class="note"><strong>Note:</strong>
<ul>
<li>This event is available to add-ons but since Firefox 4 it is <strong>not</strong> available to web pages by default. It can only be made available to web pages by setting the preference <code>dom.send_after_paint_to_content</code> to <code>true</code>. (源于<strong> </strong><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=539356"><strong>Bug 539356</strong></a>, 这个属性设置为<code>true</code>, 所有的<code>MozAfterPaint</code> 时间都被发动到web页面. 更多信息请查看 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=829330"><strong>Bug 829330</strong></a>)</li>
<li>Web pages that want to take an action after a repaint of the page can use <a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a> with a callback that sets a timeout of zero to then call the code that takes the desired post-repaint action.</li>
<li>If the handler for this event does anything that triggers repainting (such as changing the style of an element), an infinite loop will probably be triggered.</li>
<li>Repainting of areas scrolled outside the viewport is reported, but repainting of areas scrolled outside <code>overflow:auto</code> elements and the like is not.</li>
<li>Repainting in windowed plug-ins (which is most plug-ins on Windows and GTK) is not reported.</li>
</ul>
</div>
<h2 id="General_info">General info</h2>
<dl>
<dt style="float: left; text-align: right; width: 120px;">Specification</dt>
<dd style="margin: 0 0 0 120px;"><em>Add-ons specific</em></dd>
<dt style="float: left; text-align: right; width: 120px;">Interface</dt>
<dd style="margin: 0 0 0 120px;">Event</dd>
<dt style="float: left; text-align: right; width: 120px;">Bubbles</dt>
<dd style="margin: 0 0 0 120px;">Yes</dd>
<dt style="float: left; text-align: right; width: 120px;">Cancelable</dt>
<dd style="margin: 0 0 0 120px;">Yes</dd>
<dt style="float: left; text-align: right; width: 120px;">Target</dt>
<dd style="margin: 0 0 0 120px;">window</dd>
<dt style="float: left; text-align: right; width: 120px;">Default Action</dt>
<dd style="margin: 0 0 0 120px;">None</dd>
</dl>
<h2 id="Properties">Properties</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Property</th>
<th scope="col">Type</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>target</code> {{readonlyInline}}</td>
<td>{{domxref("EventTarget")}}</td>
<td>The event target (the topmost target in the DOM tree).</td>
</tr>
<tr>
<td><code>type</code> {{readonlyInline}}</td>
<td>{{domxref("DOMString")}}</td>
<td>The type of event.</td>
</tr>
<tr>
<td><code>bubbles</code> {{readonlyInline}}</td>
<td><code>boolean</code></td>
<td>Does the event normally bubble?</td>
</tr>
<tr>
<td><code>cancelable</code> {{readonlyInline}}</td>
<td><code>boolean</code></td>
<td>Is it possible to cancel the event?</td>
</tr>
<tr>
<td><code>boundingClientRect</code></td>
<td>clientRect</td>
<td>The equivalent of {{domxref("Element.getBoundingClientRect", "getBoundingClientRect()")}} for the repainted zone. Read only.</td>
</tr>
<tr>
<td><code>clientRects</code></td>
<td>clientRectList</td>
<td>The equivalent of {{domxref("Element.getClientRects", "getClientRects()")}} for the repainted zone. Read only.</td>
</tr>
<tr>
<td><code>transactionId</code></td>
<td><code>uint64_t</code></td>
<td>The transaction id of the composition that just occurred to present something to the user. Read only.</td>
</tr>
</tbody>
</table>
<h2 id="Example">Example</h2>
<p>This example highlights elements that get repainted while hovering the document with a cursor.</p>
<pre class="brush: js">(function(){
var store = [];
// every repaint will be logged in store
window.addEventListener("MozAfterPaint", log, false);
if ( document.body )
bind();
else
window.addEventListener("load", bind, false);
function log(e){
store.push( [(new Date).getTime(), e.clientRects] );
}
function bind(){
// clicking anywhere on the document will prevent other repaint to be logged
// as well as display the visual "repaint heatmap"
document.body.addEventListener("click", function onClick(){
window.removeEventListener("MozAfterPaint", log, false);
for ( var pos = 0; pos < store.length; pos++ ) {
var rects = store[pos][1];
for ( var i = 0; i < rects.length; i++ ) {
// will simply "draw" semi-transparent red divs where
// repaints where recorded
var rect = rects[i];
var div = document.createElement("div");
with (div.style) {
background = "red";
opacity = "0.1";
position = "absolute";
top = rect.top + "px";
left = rect.left + "px";
width = (rect.right - rect.left) + "px";
height = (rect.bottom - rect.top) + "px";
}
document.body.appendChild( div );
}
}
document.body.removeEventListener("click", onClick, false);
}, false);
}
})();
</pre>
<p>This example is for measuring how long something took to paint to the user.</p>
<pre class="brush: js">// Suppose we want to measure how long it takes to paint the
// next frame after a click event is fired on element "target".
let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// The last transaction id is the last id that was sent to the
// compositor before our script started to execute.
let lastTransactionId = winUtils.lastTransactionId;
let start = window.performance.now();
// Set up our MozAfterPaint listener, but we only care about
// MozAfterPaint events where the transaction id is GREATER
// than lastTransactionId. This is to account for the possibility
// that a composite is underway at the time this script is running.
addEventListener("MozAfterPaint", function onPaint(event) {
if (event.transactionId > lastTransactionId) {
// Since the transaction id is greater than the last transaction
// id, that means we're safe to assume that whatever effect that
// clicking on the "target" element was supposed to have, if the
// change should have been instantaneous, then it has been presented
// to the user.
let finish = window.performance.now();
alert(`Time to present: ${finish - start}ms`);
removeEventListener("MozAfterPaint", onPaint);
}
});
document.getElementById("target").click();
</pre>
<h2 id="See_also">See also</h2>
<ul>
<li><a href="/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIDOMWindowUtils#isMozAfterPaintPendingen-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIDOMWindowUtils#isMozAfterPaintPending">nsIDOMWindowUtils.isMozAfterPaintPending</a></li>
</ul>
|