圆环进度条 css3-带有小程序进度和状态的铃声音频播放自定义组件

2023-08-26 0 1,434 百度已收录

根据功能需求,花了很长时间,终于完成了我的第一个小程序自定义组件的开发,用于音频播放和暂停控制,同时按钮外面的圆环用于显示播放进度。 疗效图如下:

第一个图标等待播放,第二个图标正在播放,圆环按比例显示进度。 由于是自己开发的第一个自定义组件,所以还是遇到了很多坑,记录如下:

1. 自定义组件

进度环组件有两个主要想法。 第一种是使用canvas在视口上绘制,另一种是使用CSS生成。 这两个组件我都试过了,还是觉得用canvas来控制比较好。 小程序定制部分的四个文件如下。

1.1wxml文件

一、根据调用组件上传的铃声盒大小

第一个组件是图中的播放和暂停按钮,根据状态动态显示。 根据所画线(2)的长度圆环进度条 css3,经过反复测试,尺寸比盒子小10,显示更协调。

这个理论非常有用。 经过反复比较,采用了cover-image。 使用image在地图上显示图标是有问题的,但是cover-image会影响一些参数的传输,所以要非常小心。

还要注意图像文件名的大小写。 开发工具调试的时候大小写不敏感,可以正常显示,但是在真机环境下是区分大小写的,导致我在真机上时显示异常。 暂停按钮不显示,说明上面还是认为父子组件参数传递不正常,或者子组件没有动态刷新,或者cover-image阻止了参数传递,导致解决时走了很多弯路这个问题。

圆环进度条 css3-带有小程序进度和状态的铃声音频播放自定义组件

第二个组件是环形背景,它是白色的,在js文件中定义

第三个组件根据播放进度在一列中显示,可以是亮色的,也可以是彩色的圆环进度条 css3,在js文件中定义

wxml文件中还有一个draw参数,该参数是从调用组件传过来的,这样当同一个页面有多个环时,可以通过ID来区分,这样就可以方便的通过控制不同的子组件父组件。



    
    
    

1.2wxss文件

样式文件不多,定义如下。

.circle_box,.circle_draw{ position: relative; }
.circle_bg{position: absolute;}
.circle_box{
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
}
.audioImg{
    position: absolute;
}

1.3json文件

一定要把自己定义为一个组件,可以在你面前使用。

{
  "component": true,
  "usingComponents": {}
}

1.4js文件

程序文件注释:

1. 组件有属性和数据,并且数据仅在生命周期的attached中加载一次。 可以根据父组件的参数更改属性。 该子组件有4个属性参数,分别是画板元素代码draw、显示比例per、直径r,默认为30px,无论是否播放。

子组件的数据数据不会直接随父组件改变。 要更改它,需要获取子组件的id并通过init进行更改。

2. 圆圈动态变化。 该子组件中定义了一个 updateCircle 函数,用于更新圆显示的比例。

/* components/circle/circle.js */
Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  properties: {
    draw: {//画板元素名称id
      type: String,
      value: 'draw'
    },
    per:{ //百分比 通过此值转换成step
      type: String,
      value: '0'
    },
    r:{//半径
      type: String,
      value: '30'
    },
    isPlay:{//是否播放状态
      type: Boolean,
      value: false,
    },
  },
  data: { /*  私有数据,可用于模版渲染 */
    step: 1, //用来算圆的弧度0-2
    size:0, //画板大小
    screenWidth:750, //实际设备的宽度
    txt:0,
  },
  methods: {
    /**
     * el:画圆的元素
     * r:圆的半径
     * w:圆的宽度
     * 功能:画背景
     */
    drawCircleBg: function (el, r, w) {
      const ctx = wx.createCanvasContext(el,this);
      ctx.setLineWidth(w);// 设置圆环的宽度
      ctx.setStrokeStyle('#E5E5E5'); // 设置圆环的颜色
      ctx.setLineCap('round') // 设置圆环端点的形状
      ctx.beginPath();//开始一个新的路径
      ctx.arc(r, r, r - w, 0, 2 * Math.PI, false);
      //设置一个原点(110,110),半径为100的圆的路径到当前路径
      ctx.stroke();//对当前路径进行描边
      ctx.draw();
    },
    /**
     * el:画圆的元素
     * r:圆的半径
     * w:圆的宽度
     * step:圆的弧度 (0-2)
     * 功能:彩色圆环
     */
    drawCircle: function (el, r, w, step) {
      var context = wx.createCanvasContext(el,this);
      // 设置渐变
      var gradient = context.createLinearGradient(2 * r, r, 0);
      gradient.addColorStop("0", "#ff3f39");
      gradient.addColorStop("0.5", "#ff3f39");
      gradient.addColorStop("1.0", "#ff3f39");
      context.setLineWidth(w);
      context.setStrokeStyle(gradient);
      context.setLineCap('round')
      context.beginPath();//开始一个新的路径
      // step 从0到2为一周
      context.arc(r, r, r - w, -Math.PI / 2, step * Math.PI - Math.PI / 2, false);
      context.stroke();//对当前路径进行描边
      context.draw()
    },
    updateCircle: function (per) {
      let _this = this;
      //初始化
      let el = _this.data.draw; //画板元素
      let r = Number(_this.data.r); //圆形半径
      let step = (2 * Number(per)) / 100;
      let rpx = (_this.data.screenWidth / 750) * r;
      const w = 2;//圆形的宽度
      //组件入口,调用下面即可绘制 背景圆环和彩色圆环。
      _this.drawCircle(el, rpx, w, step);//绘制 彩色圆环
    },
  },
  lifetimes: {
    // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
    attached: function () {
      const _this = this;
      //获取屏幕宽度
      wx.getSystemInfo({
        success: function(res) {
          _this.setData({
            screenWidth: res.windowWidth
          });
        },
      });
      //初始化
      const el = _this.data.draw; //画板元素
      const per = _this.data.per; //圆形进度
      const r = Number(_this.data.r); //圆形半径
      _this.setData({
        step: (2 * Number(_this.data.per)) / 100,
        txt: _this.data.per
      });
      //获取屏幕宽度(并把真正的半径px转成rpx)
      let rpx = (_this.data.screenWidth / 750) * r;
      //计算出画板大小
      this.setData({
        size: rpx * 2
      });
      const w = 2;//圆形的宽度
      //组件入口,调用下面即可绘制 背景圆环和彩色圆环。
      _this.drawCircleBg(el + 'bg', rpx, w);//绘制 背景圆环
      _this.drawCircle(el, rpx, w, _this.data.step);//绘制 彩色圆环
    }
  },
})

2、子组件引用2.1json中的语句

首先在json文件中声明引用组件,如下所示

圆环进度条 css3-带有小程序进度和状态的铃声音频播放自定义组件

{
  "navigationBarTitleText": "景区导游",
  "usingComponents": {
    "circle": "/pages/components/circle/circle"
  }
}

2.2 wxml中的引用

1.这里用在地图上,用cover-view引用

2、本页面只引用一次,draw采用静态定义,定义了per和isplay两个动态参数。

3.特别注意,因为viewport的关系,请将bindtap定义在outer cover-view上,而不是在circle上。 点击圆圈非常有效,而且经常没有反应。 这个坑坑了我好久。


    

2.3 同一页面的多次引用

此页面使用循环和多个引用。 id 使用公园代码作为后缀。 速率和状态控制需要判断当前播放是否是公园的音频


    

圆环进度条 css3-带有小程序进度和状态的铃声音频播放自定义组件

3. 子组件显示比例控制

项目中分别使用了wx.createInnerAudioContext和wx.getBackgroundAudioManager两种模式。 我觉得背景音乐比较容易控制,虽然同时只能有一个音频。以下是createInnerAudioContext的控制案例

3.1. 创建音频页面常量

由于需要播放多个音频,因此创建一个页面常量,防止随机播放多个音频。

//创建音频上下文

constmyAudio=wx.createInnerAudioContext();

3.2 音频初始化与销毁

onLoad: function (e) {
    var that = this;
    const version = wx.getSystemInfoSync().SDKVersion;
    if (util.compareVersion(version, '2.3.0') >= 0) {
        wx.setInnerAudioOption({
            obeyMuteSwitch: false
        })
    }else{
        wx.showModal({
            title: '提示',
            content: '当前微信版本过低,静音模式下可能会导致播放音频失败。'
        })
    }
    that.initInnerAudioContext();
},
// 页面卸载时停止播放
onUnload() {
    //停止播放
    //停止播放
    myAudio.stop();
    myAudio.destroy();
},

3.3 播放和暂停按钮响应

1、通过以下方法获取被点击的组件,方便对被点击的组件进行操作。

varid=event.currentTarget.id

that.data.currentCircle=that.selectComponent('#myCircle'+id);

2、注意:播放完毕后,延迟获取paused变量,以保证onTimeUpdate能够生效。 这个问题也坑了我很久。

//播放与暂停音频,
playAudio: function (event) {
    var that = this
    if (that.data.currentCircle != ""){
        that.data.currentCircle.updateCircle(0);
    }
	//获取点击事件的组件,以便于准确操作
    var id = event.currentTarget.id
    that.data.currentCircle = that.selectComponent('#myCircle'+id);
    //切换时如果在另一景区在播放状态下,也切换音乐重新播放
    if (that.data.isPlay && event.currentTarget.id == that.data.playId ){
        myAudio.pause();
        this.setData({
            isPlay: false,
            playId: id
        });
    }else{
        var src = OSS_PREFIX + 'scenicfile/' + app.globalData.adcode + '/' + id + '/000.mp3'
        myAudio.src = src
        myAudio.play()
        //延时0.5秒读取一下paused,否则后面的onTimeUpdate不会生效
        setTimeout(() => {
            console.log(myAudio.paused)
        }, 500)
        that.setData({
            isPlay: true,
            playId: id,
        });
    }
},

3.4 音频状态监控

内容很多,程序里有详细的注释。 onTimeUpdate 风暴动态更新

initInnerAudioContext(src) {
    let that = this;
    // 监听音频播放事件
    myAudio.onPlay(function () {
        console.log('onPlay');
        that.setData({
            isplay: true
        });
    });
    // 监听音频播放进度更新事件
    myAudio.onTimeUpdate(() => {
        let per = myAudio.currentTime/myAudio.duration * 100
        //console.log(per)
        if (isNaN(per)) {
            that.data.currentCircle.updateCircle(0); // 通过实例调用组件事件
            that.setData({
                per: 0,
            });
        }else {
            that.data.currentCircle.updateCircle(per); // 通过实例调用组件事件
            that.setData({
                per: per,
            });
        };
    });
    myAudio.onWaiting(function () {
        console.log('onWaiting');
        //myAudio.pause(); //这个方法有问题,真机上不需求,会有时不自动播放问题,调试机没有问题
        that.setData({
            isloading: true
        });
    });
    myAudio.onCanplay(function () {
        console.log('onCanplay')
        that.setData({
            isloading: false
        });
		//确保调用 后能自动播放
        myAudio.play();
    });
    // 监听音频暂停事件
    myAudio.onPause(function () {
        console.log('onPause');
        that.setData({
            isplay: false
        });
    });
    // 监听音频停止事件
    myAudio.onStop(function () {
        console.log('onStop');
        that.setData({
            isplay: false
        });
        myAudio.seek(0);
    });
    // 监听音频自然播放至结束的事件
    myAudio.onEnded(function () {
        console.log('onEnded');
        that.setData({
            isplay: false
        });
        myAudio.seek(0);
    });
    // 监听音频播放错误事件
    myAudio.onError(err => {
        console.log('监听音频播放错误事件', err, myAudio.src);
        that.setData({
            isplay: false,
            isloading: false
        });
        wx.showToast({
            icon: 'none',
            title: '音频播放出错!',
        });
    });
},

四。 概括

这是我的第一个自定义小程序组件。 网上没有完整的参考案例。 有些案例使用了框架,所以不太容易直接引用。 我遇到了很多陷阱,在这个过程中我想放弃。 主要如下:

1、父子组件参数传递,本例使用属性和自定义方法

2、onTimeUpdate不起作用的问题,小程序的音乐播放器组件有bug,问题很多,网上也没有完整的答案,所以只能自己反复测试,最后就可以了是完美的。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 css3 圆环进度条 css3-带有小程序进度和状态的铃声音频播放自定义组件 https://www.wkzy.net/game/157196.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务