日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
HarmonyOS自定義控件之JS進(jìn)度條

想了解更多內(nèi)容,請(qǐng)?jiān)L問:

創(chuàng)新互聯(lián)是一家專業(yè)提供阿爾山企業(yè)網(wǎng)站建設(shè),專注與成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、H5建站、小程序制作等業(yè)務(wù)。10年已為阿爾山眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進(jìn)行中。

和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.

前言

在我們?nèi)粘i_發(fā)的里面,很多場(chǎng)景經(jīng)常會(huì)用到進(jìn)度條,而系統(tǒng)提供的進(jìn)度條樣式又無法滿足我們的使用,這時(shí)候我們就需要自定義一個(gè)進(jìn)度條,自定義JS進(jìn)度條主要涉及以下知識(shí)點(diǎn):

  • 如何自定義組件及引用
  • 如何自定義繪制圖形(draw)
  • 如何創(chuàng)建并執(zhí)行動(dòng)畫(animation)
  • 如何設(shè)置自定義組件的參數(shù)(setter)
  • 如何監(jiān)聽自定義組件的參數(shù)(getter)

效果演示

代碼實(shí)現(xiàn)

如何自定義組件及引用

1.Js自定義組件,只需要新創(chuàng)建一個(gè)包,直接在里面編寫界面,樣式,邏輯代碼即可。如果需要使用該組件,將其完整拷貝到自己的項(xiàng)目結(jié)構(gòu)下進(jìn)行引用即可。我們自定義一個(gè)Progress進(jìn)度條控件,項(xiàng)目結(jié)構(gòu)如下圖:

2.使用的時(shí)候,我們需要給自定義組件進(jìn)行標(biāo)簽聲明,然后就可以使用該標(biāo)簽了:

 
 
 
 
  1. // src表示我們引用的自定義組件的文件,name表示我們給該自定義組件聲明一個(gè)標(biāo)簽名
  2.     // 聲明之后,就可以使用這個(gè)自定義的標(biāo)簽了
  3.     
  4.     ...

如何自定義繪制圖形

說到自定義繪制,自然離不開canvas,首先我們給自定義組件增加一個(gè)標(biāo)簽,并在JS文件中描述繪制:

 
 
 
 
  1.     
  2.     {{ progressText }}

在JS中定義一個(gè)draw方法,并且傳入一個(gè)CanvasRenderingContext2D參數(shù),這個(gè)參數(shù)我們可以理解為canvas + paint,所有繪制都是通過它進(jìn)行調(diào)用:

 
 
 
 
  1. draw(ctx) {
  2.      this.display = true
  3.      ctx.lineWidth = this.circleWidth
  4.      ctx.lineCap = 'round'
  5.      // ctx可以理解為canvas + paint
  6.      ctx.clearRect(0, 0, this.width, this.height) // 會(huì)閃屏,系統(tǒng)渲染問題
  7.      ctx.save() // save1
  8.      ctx.translate(this.width / 2, this.height / 2)
  9.      // draw background
  10.      ctx.beginPath()
  11.      ctx.strokeStyle = this.backgroundColor
  12.      ctx.arc(0, 0, 100, 0, 2 * Math.PI) // r = 100, 參數(shù)是弧度,角度 = 弧度 / PI * 180
  13.      ctx.stroke() // 繪制
  14.      ctx.closePath()
  15.      // draw progress
  16.      ctx.save()
  17.      ctx.rotate(-90 / 180 * Math.PI)
  18.      ctx.beginPath()
  19.      ctx.strokeStyle = this.progressColor
  20.      ctx.arc(0, 0, 100, 0, this.angle / 180 * Math.PI) // r = 100, 參數(shù)是弧度,角度 = 弧度 / PI * 180
  21.      ctx.stroke() // 繪制
  22.      ctx.closePath()
  23.      ctx.restore()
  24.      ctx.restore() // save1
  25.      this.notifyChanged()
  26.  }

這部分邏輯并不復(fù)雜,都有注釋,就是繪制一個(gè)圓環(huán)背景,然后根據(jù)進(jìn)度參數(shù)在圓環(huán)上繪制一個(gè)圓弧進(jìn)度,相信做過自定義控件的同學(xué)都能夠非常熟悉。

如何創(chuàng)建并執(zhí)行動(dòng)畫

1.首先我們需要在init的時(shí)候創(chuàng)建一個(gè)動(dòng)畫對(duì)象,并且設(shè)置好初始的動(dòng)畫參數(shù):

 
 
 
 
  1. onInit() {
  2.       // 動(dòng)畫參數(shù)(具體參數(shù)類型和參數(shù)說明參考官方文檔)
  3.       var options = {
  4.           duration: this.animDuration, // 動(dòng)畫時(shí)長(zhǎng)
  5.           direction: 'normal', // 播放模式
  6.           easing: 'linear', // 差值器
  7.           fill: 'forwards', // 動(dòng)畫結(jié)束后狀態(tài)
  8.           iterations: 1, // 執(zhí)行次數(shù)
  9.           begin: 0, // 起始值
  10.           end: 360.0 // 終止值
  11.       };
  12.       var _this = this
  13.       this.animator = Animator.createAnimator(options)
  14.       this.animator.onframe = function (value) {
  15.           // 動(dòng)畫每一幀回調(diào),類似我們熟悉的onAnimateUpdate回調(diào)
  16.           _this.angle = value
  17.           // 刷新繪制
  18.           _this.draw(_this.ctx)
  19.       }
  20.       ...
  21.   }, 

2.接著我們需要在特定的時(shí)候開啟動(dòng)畫,例如我們?cè)诮邮盏酵獠總鬟M(jìn)來的進(jìn)度參數(shù)后,我們需要更新動(dòng)畫的起始值和終止值,并且開始執(zhí)行動(dòng)畫:

 
 
 
 
  1. onProgressChanged(oldV, newV) { 
  2.      console.log("onProgressChanged from:" + oldV + " to: " + newV)
  3.      this.initWidget()
  4.      // 進(jìn)度值范圍限定為[0, 1]
  5.      if (oldV >= 1) {
  6.          oldV = 1
  7.      }
  8.      if (newV >= 1) {
  9.          newV = 1
  10.      }
  11.      // 更新動(dòng)畫的起始和終止參數(shù)
  12.      var options = {
  13.          duration: this.animDuration,
  14.          direction: 'alternate-reverse',
  15.          easing: 'linear',
  16.          fill: 'forwards',
  17.          iterations: 1,
  18.          begin: oldV * 360,
  19.          end: newV * 360
  20.      };
  21.      this.animator.update(options)
  22.      // 開始執(zhí)行動(dòng)畫
  23.      this.animator.play()
  24.  },

如何設(shè)置自定義組件的參數(shù)

1.我們自定義組件,并不能像之前一樣簡(jiǎn)單的暴露個(gè)公開方法給外部調(diào)用。由于其數(shù)據(jù)驅(qū)動(dòng)的設(shè)計(jì),我們可以定義一些自定義屬性參數(shù),當(dāng)外部修改參數(shù)時(shí)我們就可以接收到信息進(jìn)行主動(dòng)動(dòng)作(setter):

 
 
 
 
  1. props: [
  2.       'progress', // 進(jìn)度
  3.       'backgroundColor', // 圓環(huán)背景顏色
  4.       'progressColor' // 進(jìn)度前景顏色
  5.   ],
  6.   ...

2.監(jiān)聽這些對(duì)外暴露的屬性值變化(listener):

 
 
 
 
  1. onInit() {
  2.      ...
  3.      // 監(jiān)聽自定義屬性值變化
  4.      this.$watch('progress', 'onProgressChanged')
  5.      this.$watch('backgroundColor', 'onBackgroundChanged')
  6.      this.$watch('progressColor', 'onForegroundChanged')
  7.      ...
  8.  },   
  9.  // backgroundColor變化時(shí)會(huì)觸發(fā)該回調(diào)
  10.  onBackgroundChanged(oldV, newV) {
  11.      this.backgroundColor = newV
  12.  },
  13.  // progressColor變化時(shí)會(huì)觸發(fā)該回調(diào)
  14.  onForegroundChanged(oldV, newV) {
  15.      this.progressColor = newV
  16.  },
  17.  // progress變化時(shí)會(huì)觸發(fā)該回調(diào)
  18.  onProgressChanged(oldV, newV) {
  19.      console.log("onProgressChanged from:" + oldV + " to: " + newV)
  20.      this.initWidget()
  21.      if (oldV >= 1) {
  22.          oldV = 1
  23.      }
  24.      if (newV >= 1) {
  25.          newV = 1
  26.      }
  27.      var options = {
  28.          duration: this.animDuration,
  29.          direction: 'alternate-reverse',
  30.          easing: 'linear',
  31.          fill: 'forwards',
  32.          iterations: 1,
  33.          begin: oldV * 360,
  34.          end: newV * 360
  35.      };
  36.      this.animator.update(options)
  37.      this.animator.play()
  38.  }, 

3..外部設(shè)置參數(shù),當(dāng)外部改變這些參數(shù)時(shí),我們自定義組件內(nèi)部的回調(diào)方法就會(huì)觸發(fā),并執(zhí)行刷新邏輯:

 
 
 
 
  1.     
  2.                   progress-color="#6bfc33"
  3.                   progress="{{ progress }}">
  4.     
  5.     ...

如何監(jiān)聽自定義組件的參數(shù)

上面我們說到了外部如何改變自定義組件內(nèi)部的屬性,本質(zhì)上就是一個(gè)典型觀察者模式。同理,外部調(diào)用者需要監(jiān)聽我們自定義組件的參數(shù)變化,也是通過這種方式:

1.首先我們?cè)谧远x組件中需要定義一個(gè)被觀察者對(duì)象(key),并且在該對(duì)象值變化時(shí)對(duì)外發(fā)送消息:

 
 
 
 
  1. notifyChanged() {
  2.        // currentAngle, currentProgress就是被觀察者對(duì)象,key-value結(jié)構(gòu),value就是我們對(duì)外發(fā)送的值
  3.        // 注意:駝峰命名
  4.        this.$emit("currentAngle", this.angle)
  5.        this.$emit("currentProgress", Math.ceil(this.angle / 3.6) / 100)
  6.        this.progressText = Math.ceil(this.angle / 3.6) + "%"
  7.    },

2.外部使用者需要注冊(cè)監(jiān)聽回調(diào)方法,對(duì)被觀察者對(duì)象(key)進(jìn)行監(jiān)聽:

 

 
 
 
 
  1.     // 通過@current-angle和@current-progress進(jìn)行該參數(shù)的監(jiān)聽,注意參數(shù)前加"@",并且參數(shù)根據(jù)駝峰命名方式拆分單詞,每個(gè)詞語用"-"隔開
  2.     
  3.                   progress-color="#6bfc33"
  4.                   progress="{{ progress }}"
  5.                   @current-angle="onAngleChanged"
  6.                   @current-progress="onProgressChanged">
  7.     
  8.     ... 

 
 
 
 
  1. // 當(dāng)自定義組件內(nèi)部的 currentAngle, currentProgress變化時(shí),會(huì)觸發(fā)下面的回調(diào)方法通知外部使用者
  2.    onAngleChanged(angle) {
  3.        console.log("onAngleChanged: " + angle.detail)
  4.    },
  5.    onProgressChanged(progress) {
  6.        console.log("onProgressChanged: " + progress.detail)
  7.    }

其他關(guān)鍵點(diǎn)

1.標(biāo)簽的繪制內(nèi)容默認(rèn)是不顯示的,我們可以在初始化的時(shí)候監(jiān)聽首幀回調(diào),主動(dòng)進(jìn)行刷新一次:

 
 
 
 
  1. onInit() {
  2.     ...
  3.     // 監(jiān)聽首幀,觸發(fā)首次繪制,類似attachToWindow的觸發(fā)時(shí)機(jī)
  4.     requestAnimationFrame(function () {
  5.         _this.initWidget()
  6.         _this.draw(_this.ctx)
  7.     })
  8. },

2.自定義組件如何獲取寬高信息,在API6+系統(tǒng)已經(jīng)提供相關(guān)的方法可以進(jìn)行獲取,類似onSizeChanged中讀取寬高信息:

 
 
 
 
  1. initWidget() {
  2.      console.log("init widget")
  3.      if (this.ctx === null) {
  4.          // 獲取標(biāo)簽元素
  5.          let widget = this.$element('progress-bar');
  6.          this.ctx = widget.getContext('2d', {
  7.              antialias: true
  8.          })
  9.          // 獲取寬高,并計(jì)算出繪制圓環(huán)的寬高,中心點(diǎn),半徑信息
  10.          this.width = widget.getBoundingClientRect().width
  11.          this.height = widget.getBoundingClientRect().height
  12.          this.centerX = widget.getBoundingClientRect().left + this.width / 2
  13.          this.centerY = widget.getBoundingClientRect().top + this.height / 2
  14.          console.log("canvas size = " + this.width + ", " + this.height)
  15.          console.log("canvas center = " + this.centerX + ", " + this.centerY)
  16.      }
  17.  },

3.canvas畫布和我們通常理解的是不同的,它是存在繪制緩存的,所以每一幀刷新時(shí),我們需要在繪制前先清空之前的繪制內(nèi)容。目前鴻蒙清空畫布時(shí)會(huì)概率出現(xiàn)閃屏問題。

以上就是實(shí)現(xiàn)一個(gè)自定義JS進(jìn)度條的核心代碼了,源代碼:JsProgress

想了解更多內(nèi)容,請(qǐng)?jiān)L問:

和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.


名稱欄目:HarmonyOS自定義控件之JS進(jìn)度條
分享URL:http://www.5511xx.com/article/dhhogso.html