1# 动画帧
2
3## 请求动画帧
4
5请求动画帧时通过requestAnimationFrame函数逐帧回调,在调用该函数时传入一个回调函数。
6
7runframe在调用requestAnimationFrame时传入带有timestamp参数的回调函数step,将step中的timestamp赋予起始的startTime。当timestamp与startTime的差值小于规定的时间时将再次调用requestAnimationFrame,最终动画将会停止。
8
9```html
10<!-- xxx.hml -->
11<div class="container">
12  <tabs onchange="changecontent">
13    <tab-content>
14      <div class="container">
15        <stack style="width: 300px;height: 300px;margin-top: 100px;margin-bottom: 100px;">
16          <canvas id="mycanvas" style="width: 100%;height: 100%;background-color: coral;">
17          </canvas>
18          <div style="width: 50px;height: 50px;border-radius: 25px;background-color: indigo;position: absolute;left: {{left}};top: {{top}};">
19          </div>
20        </stack>
21        <button type="capsule" value="play" onclick="runframe"></button>
22      </div>
23    </tab-content>
24  </tabs>
25</div>
26```
27
28```css
29/* xxx.css */
30.container {
31  flex-direction: column;
32  justify-content: center;
33  align-items: center;
34  width: 100%;
35  height: 100%;
36}
37button{
38  width: 300px;
39}
40```
41
42```js
43// xxx.js
44export default {
45  data: {
46    timer: null,
47    left: 0,
48    top: 0,
49    flag: true,
50    animation: null,
51    startTime: 0,
52  },
53  onShow() {
54    var test = this.$element("mycanvas");
55    var ctx = test.getContext("2d");
56    ctx.beginPath();
57    ctx.moveTo(0, 0);
58    ctx.lineTo(300, 300);
59    ctx.lineWidth = 5;
60    ctx.strokeStyle = "red";
61    ctx.stroke();
62  },
63  runframe() {
64    this.left = 0;
65    this.top = 0;
66    this.flag = true;
67    this.animation = requestAnimationFrame(this.step);
68  },
69  step(timestamp) {
70    if (this.flag) {
71      this.left += 5;
72      this.top += 5;
73      if (this.startTime == 0) {
74        this.startTime = timestamp;
75      }
76      var elapsed = timestamp - this.startTime;
77        if (elapsed < 500) {
78          console.log('callback step timestamp: ' + timestamp);
79          this.animation = requestAnimationFrame(this.step);
80        }
81      } else {
82        this.left -= 5;
83        this.top -= 5;
84        this.animation = requestAnimationFrame(this.step);
85      }
86      if (this.left == 250 || this.left == 0) {
87        this.flag = !this.flag
88     }
89    },
90    onDestroy() {
91      cancelAnimationFrame(this.animation);
92    }
93}
94```
95
96![zh-cn_image_0000001174756860](figures/zh-cn_image_0000001174756860.gif)
97
98> **说明:**
99>
100> requestAnimationFrame函数在调用回调函数时在第一个参数位置传入timestamp时间戳,表示requestAnimationFrame开始去执行回调函数的时刻。
101
102
103## 取消动画帧
104
105通过cancelAnimationFrame函数取消逐帧回调,在调用cancelAnimationFrame函数时取消requestAnimationFrame函数的请求。
106
107```html
108<!-- xxx.hml -->
109<div class="container">
110  <tabs onchange="changecontent">
111    <tab-content>
112      <div class="container">
113        <stack style="width: 300px;height: 300px;margin-top: 100px;margin-bottom: 100px;">
114          <canvas id="mycanvas" style="width: 100%;height: 100%;background-color: coral;">
115          </canvas>
116          <div style="width: 50px;height: 50px;border-radius: 25px;background-color: indigo;position: absolute;left: {{left}};top: {{top}};">
117          </div>
118        </stack>
119        <button type="capsule" value="play" onclick="runframe"></button>
120      </div>
121    </tab-content>
122  </tabs>
123</div>
124```
125
126```css
127/* xxx.css */
128.container {
129  flex-direction: column;
130  justify-content: center;
131  align-items: center;
132  width: 100%;
133  height: 100%;
134}
135button{
136  width: 300px;
137}
138```
139
140```js
141// xxx.js
142export default {
143  data: {
144    timer: null,
145    left: 0,
146    top: 0,
147    flag: true,
148    animation: null
149  },
150  onShow() {
151    var test = this.$element("mycanvas");
152    var ctx = test.getContext("2d");
153    ctx.beginPath();
154    ctx.moveTo(0, 0);
155    ctx.lineTo(300, 300);
156    ctx.lineWidth = 5;
157    ctx.strokeStyle = "red";
158    ctx.stroke();
159  },
160  runframe() {
161    this.left = 0;
162    this.top = 0;
163    this.flag = true;
164    this.animation = requestAnimationFrame(this.step);
165  },
166  step(timestamp) {
167    if (this.flag) {
168      this.left += 5;
169      this.top += 5;
170      this.animation = requestAnimationFrame(this.step);
171    } else {
172      this.left -= 5;
173      this.top -= 5;
174      this.animation = requestAnimationFrame(this.step);
175    }
176    if (this.left == 250 || this.left == 0) {
177      this.flag = !this.flag
178    }
179  },
180  onDestroy() {
181    cancelAnimationFrame(this.animation);
182  }
183}
184```
185
186![zh-cn_image_0000001220316655](figures/zh-cn_image_0000001220316655.gif)
187
188> **说明:**
189>
190> 在调用该函数时需传入一个具有标识id的参数。
191