前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(七) -> JS动画(二)

【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(七) -> JS动画(二)

作者头像
枫叶丹
发布2025-03-06 08:25:42
发布2025-03-06 08:25:42
3400
代码可运行
举报
文章被收录于专栏:C++C++
运行总次数:0
代码可运行

1 -> 动画动效

1.1 -> 创建动画对象

通过createAnimator创建一个动画对象,通过设置参数options来设置动画的属性。

代码语言:javascript
代码运行次数:0
复制
<!-- test.hml -->
<div class="container">
  <div style="width: 300px;height: 300px;margin-top: 100px;background: linear-gradient(pink, purple);transform: translate({{translateVal}});">
  </div>
  <div class="row">
    <button type="capsule" value="play" onclick="playAnimation"></button>
  </div>
</div>
代码语言:javascript
代码运行次数:0
复制
/* test.css */
.container {
  width:100%;
  height:100%;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
button{
  width: 200px;
}
.row{
  width: 65%;
  height: 100px;
  align-items: center;
  justify-content: space-between;
  margin-top: 50px;
  margin-left: 260px;
}
代码语言:javascript
代码运行次数:0
复制
/* test.js */
import animator from '@ohos.animator';
export default {
  data: {
    translateVal: 0,
    animation: null
  },
  onInit() {},
  onShow(){
    var options = {
      duration: 3000,
      easing:"friction",
      delay:"1000",
      fill: 'forwards',
      direction:'alternate',
      iterations: 2,
      begin: 0,
      end: 180
    };//设置参数
    this.animation = animator.createAnimator(options)//创建动画
  },
  playAnimation() {
    var _this = this;
    this.animation.onframe = function(value) {
      _this.translateVal= value
    };
    this.animation.play();
  }
}

说明

  • 使用createAnimator创建动画对象时必须传入options参数。
  • begin插值起点,不设置时默认为0。
  • end插值终点,不设置时默认为1。

1.2 -> 添加动画事件和调用接口

animator支持事件和接口,可以通过添加frame、cancel、repeat、finish事件和调用update、play、pause、cancel、reverse、finish接口自定义动画效果。animator支持的事件和接口具体见动画中的createAnimator。

代码语言:javascript
代码运行次数:0
复制
<!-- test.hml -->
<div style="flex-direction: column;align-items: center;width: 100%;height: 100%;">
  <div style="width:200px;height: 200px;margin-top: 100px;background: linear-gradient(#b30d29, #dcac1b);
  transform: scale({{scaleVal}});"></div>
  <div style="width: {{DivWidth}};height: {{DivHeight}};margin-top: 200px;
  background: linear-gradient(pink, purple);margin-top: 200px;transform:translateY({{translateVal}});">
  </div>
  <div class="row">
    <button type="capsule" value="play" onclick="playAnimation"></button>
    <button type="capsule" value="update" onclick="updateAnimation"></button>
  </div>
  <div class="row1">
    <button type="capsule" value="pause" onclick="pauseAnimation"></button>
    <button type="capsule" value="finish" onclick="finishAnimation"></button>
  </div>
  <div class="row2">
    <button type="capsule" value="cancel" onclick="cancelAnimation"></button>
    <button type="capsule" value="reverse" onclick="reverseAnimation"></button>
  </div>
</div>
代码语言:javascript
代码运行次数:0
复制
/* test.css */
button{
  width: 200px;
}
.row{
  width: 65%;
  height: 100px;
  align-items: center;
  justify-content: space-between;
  margin-top: 150px;
  position: fixed;
  top: 52%;
  left: 120px;
}
.row1{
  width: 65%;
  height: 100px;
  align-items: center;
  justify-content: space-between;
  margin-top: 120px;
  position: fixed;
  top: 65%;
  left: 120px;
}
.row2{
  width: 65%;
  height: 100px;
  align-items: center;
  justify-content: space-between;
  margin-top: 100px;
  position: fixed;
  top: 75%;
  left: 120px;
}
代码语言:javascript
代码运行次数:0
复制
/* test.js */
import animator from '@ohos.animator';
import prompt from '@system.prompt';
export default {
  data: {
    scaleVal:1,
    DivWidth:200,
    DivHeight:200,
    translateVal:0,
    animation: null
  },
  onInit() {
    var options = {
      duration: 3000,
      fill: 'forwards',
      begin: 200,
      end: 270
    };
    this.animation = animator.createAnimator(options);
  },
  onShow() {
    var _this= this;
    //添加动画重放事件
    this.animation.onrepeat = function() {
      prompt.showToast({
        message: 'repeat'
      });
      var repeatoptions = {
        duration: 2000,
        iterations: 1,
         direction: 'alternate',
         begin: 180,
         end: 240
       };
        _this.animation.update(repeatoptions);
        _this.animation.play();
      };
  },
  playAnimation() {
    var _this= this;
    //添加动画逐帧插值回调事件
    this.animation.onframe = function(value) {
      _this. scaleVal= value/150,
      _this.DivWidth = value,
      _this.DivHeight = value,
      _this.translateVal = value-180
    };
    this.animation.play();
  },
  updateAnimation() {
    var newoptions = {
      duration: 5000,
      iterations: 2,
      begin: 120,
      end: 180
    };
    this.animation.update(newoptions);
    this.animation.play();//调用动画播放接口
  },
  pauseAnimation() {
    this.animation.pause();//调用动画暂停接口
  },
  finishAnimation() {
    var _this= this;
   //添加动画完成事件
    this.animation.onfinish = function() {
      prompt.showToast({
        message: 'finish'
      })
    };
    this.animation.finish(); //调用动画完成接口
  },
  cancelAnimation() {
    this.animation.cancel(); //调用动画取消接口
  },
  reverseAnimation() {
    this.animation.reverse(); //调用动画倒放接口
  }
}

说明

在调用update接口的过程中可以使用这个接口更新动画参数,入参与createAnimator一致。

2 -> 动画帧

2.1 -> 请求动画帧

请求动画帧时通过requestAnimationFrame函数逐帧回调,在调用该函数时传入一个回调函数。

runframe在调用requestAnimationFrame时传入带有timestamp参数的回调函数step,将step中的timestamp赋予起始的startTime。当timestamp与startTime的差值小于规定的时间时将再次调用requestAnimationFrame,最终动画将会停止。

代码语言:javascript
代码运行次数:0
复制
<!-- test.hml -->
<div class="container">
  <tabs onchange="changecontent">
    <tab-content>
      <div class="container">
        <stack style="width: 300px;height: 300px;margin-top: 100px;margin-bottom: 100px;">
          <canvas id="mycanvas" style="width: 100%;height: 100%;background-color: coral;">
          </canvas>
          <div style="width: 50px;height: 50px;border-radius: 25px;background-color: indigo;position: absolute;left: {{left}};top: {{top}};">
          </div>
        </stack>
        <button type="capsule" value="play" onclick="runframe"></button>
      </div>
    </tab-content>
  </tabs>
</div>
代码语言:javascript
代码运行次数:0
复制
/* test.css */
.container {
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
}
button{
  width: 300px;
}
代码语言:javascript
代码运行次数:0
复制
/* test.js */
export default {
  data: {
    timer: null,
    left: 0,
    top: 0,
    flag: true,
    animation: null,
    startTime: 0,
  },
  onShow() {
    var test = this.$element("mycanvas");
    var ctx = test.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(300, 300);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "red";
    ctx.stroke();
  },
  runframe() {
    this.left = 0;
    this.top = 0;
    this.flag = true;
    this.animation = requestAnimationFrame(this.step);
  },
  step(timestamp) {
    if (this.flag) {
      this.left += 5;
      this.top += 5;
      if (this.startTime == 0) {
        this.startTime = timestamp;
      }
      var elapsed = timestamp - this.startTime;
        if (elapsed < 500) {
          console.log('callback step timestamp: ' + timestamp);
          this.animation = requestAnimationFrame(this.step);
        }
      } else {
        this.left -= 5;
        this.top -= 5;
        this.animation = requestAnimationFrame(this.step);
      }
      if (this.left == 250 || this.left == 0) {
        this.flag = !this.flag
     }
    },
    onDestroy() {
      cancelAnimationFrame(this.animation);
    }
}

说明

requestAnimationFrame函数在调用回调函数时在第一个参数位置传入timestamp时间戳,表示requestAnimationFrame开始去执行回调函数的时刻。

2.2 -> 取消动画帧

通过cancelAnimationFrame函数取消逐帧回调,在调用cancelAnimationFrame函数时取消requestAnimationFrame函数的请求。

代码语言:javascript
代码运行次数:0
复制
<!-- test.hml -->
<div class="container">
  <tabs onchange="changecontent">
    <tab-content>
      <div class="container">
        <stack style="width: 300px;height: 300px;margin-top: 100px;margin-bottom: 100px;">
          <canvas id="mycanvas" style="width: 100%;height: 100%;background-color: coral;">
          </canvas>
          <div style="width: 50px;height: 50px;border-radius: 25px;background-color: indigo;position: absolute;left: {{left}};top: {{top}};">
          </div>
        </stack>
        <button type="capsule" value="play" onclick="runframe"></button>
      </div>
    </tab-content>
  </tabs>
</div>
代码语言:javascript
代码运行次数:0
复制
/* test.css */
.container {
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
}
button{
  width: 300px;
}
代码语言:javascript
代码运行次数:0
复制
/* test.js */
export default {
  data: {
    timer: null,
    left: 0,
    top: 0,
    flag: true,
    animation: null
  },
  onShow() {
    var test = this.$element("mycanvas");
    var ctx = test.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(300, 300);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "red";
    ctx.stroke();
  },
  runframe() {
    this.left = 0;
    this.top = 0;
    this.flag = true;
    this.animation = requestAnimationFrame(this.step);
  },
  step(timestamp) {
    if (this.flag) {
      this.left += 5;
      this.top += 5;
      this.animation = requestAnimationFrame(this.step);
    } else {
      this.left -= 5;
      this.top -= 5;
      this.animation = requestAnimationFrame(this.step);
    }
    if (this.left == 250 || this.left == 0) {
      this.flag = !this.flag
    }
  },
  onDestroy() {
    cancelAnimationFrame(this.animation);
  }
}

说明

在调用该函数时需传入一个具有标识id的参数。

3 -> 自定义组件

使用兼容JS的类Web开发范式的方舟开发框架支持自定义组件,用户可根据业务需求将已有的组件进行扩展,增加自定义的私有属性和事件,封装成新的组件,方便在工程中多次调用,提高页面布局代码的可读性。具体的封装方法示例如下:

  • 构建自定义组件
代码语言:javascript
代码运行次数:0
复制
<!-- comp.hml -->
 <div class="item"> 
   <text class="title-style">{{title}}</text>
   <text class="text-style" onclick="childClicked" focusable="true">点击这里查看隐藏文本</text>
   <text class="text-style" if="{{showObj}}">hello world</text>
 </div>
代码语言:javascript
代码运行次数:0
复制
/* comp.css */
 .item { 
   width: 700px;  
   flex-direction: column;  
   height: 300px;  
   align-items: center;  
   margin-top: 100px; 
 }
 .text-style {
   width: 100%;
   text-align: center;
   font-weight: 500;
   font-family: Courier;
   font-size: 36px;
 }
 .title-style {
   font-weight: 500;
   font-family: Courier;
   font-size: 50px;
   color: #483d8b;
 }
代码语言:javascript
代码运行次数:0
复制
// comp.js
 export default {
   props: {
     title: {
       default: 'title',
     },
     showObject: {},
   },
   data() { 
     return {
       showObj: this.showObject,
     };
   }, 
   childClicked () { 
     this.$emit('eventType1', {text: '收到子组件参数'});
     this.showObj = !this.showObj; 
   }, 
 }
  • 引入自定义组件
代码语言:javascript
代码运行次数:0
复制
<!-- test.hml -->
 <element name='comp' src='../../common/component/comp.hml'></element> 
 <div class="container"> 
   <text>父组件:{{text}}</text>
   <comp title="自定义组件" show-object="{{isShow}}" @event-type1="textClicked"></comp>
 </div>
代码语言:javascript
代码运行次数:0
复制
/* test.css */
 .container { 
   background-color: #f8f8ff; 
   flex: 1; 
   flex-direction: column; 
   align-content: center;
 } 
代码语言:javascript
代码运行次数:0
复制
// test.js
 export default { 
   data: {
     text: '开始',
     isShow: false,
   },
   textClicked (e) {
     this.text = e.detail.text;
   },
 }

感谢各位大佬支持!!!

互三啦!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 -> 动画动效
    • 1.1 -> 创建动画对象
    • 1.2 -> 添加动画事件和调用接口
  • 2 -> 动画帧
    • 2.1 -> 请求动画帧
    • 2.2 -> 取消动画帧
  • 3 -> 自定义组件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档