vue3.0 安卓和ios h5 移动端音频自定义圆环可拖拽播放(兼容微信浏览器)
安装 npm install weixin-js-sdk
引入
import wx from 'weixin-js-sdk'
<template>
<div class="circle_box">
<div id="content"></div>
<img class="img_0" src="https://img.yzcdn.cn/vant/cat.jpeg" alt="">
<img @click="changeType" class="img_1" v-show="playbool" src="@/assets/decompression/pressure_audio_play.png" alt="">
<img @click="changeType" class="img_1" v-show="!playbool" src="@/assets/decompression/pressure_audio_pause.png" alt="">
<div v-show="false">
<audio ref="audio" controls @timeupdate="updateTime">
<source src="@/assets/decompression/tiankong.mp3" type="audio/mpeg">
</audio>
</div>
</div>
</template>
<script>
import wx from "weixin-js-sdk";
export default {
data(){
return{
value:'',
outColor:'',
playbool:true,
second:0,
than:''
}
},
mounted(){
this.init()
this.main()
},
methods:{
init(){
let that = this
let u = navigator.userAgent;
//ios手机
var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if(isIOS){
this.$nextTick(() => {
this.autoPlayAudio();
})
}else{
this.$nextTick(() => {
let time = setTimeout(function () {
let audio = that.$refs.audio;
//音频总时长 秒
that.second = audio.duration;
that.than = 100/audio.duration;
that.$parent.calculationTime(audio.duration);
clearInterval(time);
}, 500)
})
}
},
autoPlayAudio() {
let ua = window.navigator.userAgent.toLowerCase();
let that = this;
let audio = this.$refs.audio;
if(ua.match(/MicroMessenger/i) == 'micromessenger'){
//微信浏览器
wx.config({
debug: false,
appId: '',
timestamp: 1,
nonceStr: '',
signature: '',
jsApiList: []
});
wx.ready(function() {
audio.play();
audio.pause();
let time = setTimeout(function () {
if(audio.duration>0){
//音频总时长 秒
that.second = audio.duration;
that.than = 100/audio.duration;
that.$parent.calculationTime(audio.duration);
}else{
that.autoPlayAudio();
}
clearInterval(time);
}, 500)
});
}else{
let time = setTimeout(function () {
if(audio.duration>0){
//音频总时长 秒
that.second = audio.duration;
that.than = 100/audio.duration;
that.$parent.calculationTime(audio.duration);
}else{
that.autoPlayAudio();
}
clearInterval(time);
}, 500)
}
},
//监测播放进度
updateTime(){
let audio = this.$refs.audio;
let time = Number(this.second)-Number(audio.currentTime);
this.$parent.calculationTime(time);
this.draw(this.than*audio.currentTime);
},
changeType(){
this.playbool = !this.playbool;
let audio = this.$refs.audio;
if(this.playbool){
//暂停
audio.pause()
}else{
audio.play()
}
},
event(dom) { //事件绑定
if(this.isMobile){
dom.addEventListener("touchstart", this.OnMouseDown.bind(this), false);
dom.addEventListener("touchmove", this.throttle(this.OnMouseMove.bind(this)), false);
dom.addEventListener("touchend", this.OnMouseUp.bind(this), false);
return
}
dom.addEventListener("mousedown", this.OnMouseDown.bind(this), false);
dom.addEventListener("mousemove", this.throttle(this.OnMouseMove.bind(this)), false);
dom.addEventListener("mouseup", this.OnMouseUp.bind(this), false);
},
OnMouseDown(evt) {
let audio = this.$refs.audio;
//暂停音频
audio.pause()
this.clearLocation(evt);
let range = 10;
let X = this.getx(evt);
let Y = this.gety(evt);
let P = this.P
let minX = P.x - this.slider - range;
let maxX = P.x + this.slider + range;
let minY = P.y - this.slider - range;
let maxY = P.y + this.slider + range;
if (minX < X && X < maxX && minY < Y && Y < maxY) { //判断鼠标是否在滑块上
this.isDown = true;
} else {
this.isDown = false;
}
},
main(){
const dom = document.getElementById("content")
const obj = {
el: dom,
startDeg:1.5 ,
endDeg: 3.5,
outColor: 'rgba(50, 50, 70, .2)',
counterclockwise: false
}
this.constructor(obj)
},
constructor(param) {
this.initParam(param)
this.draw(this.value)
},
initParam(param) {
const {
el,
startDeg = 1.5,
endDeg = 3.5,
outColor = "rgba(50, 50, 70, .2)",
innerLineWidth = 1,
outLineWidth = 5,
counterclockwise = true,
slider = 8,
color = ["#ffffff", "#ffffff"],
sliderColor = "#fff",
sliderBorderColor = "#33aaff",
value = 0,
change = (v)=> { },
textShow = true
} = param;
this.el = el;
this.width = el.offsetWidth;
this.height = el.offsetHeight;
this.center = this.width / 2
this.radius = this.width / 2 - 30; //滑动路径半径
this.initCanvas(el);
this.startDeg = startDeg;
this.endDeg = endDeg;
this.outColor = outColor;
this.innerLineWidth = innerLineWidth;
this.outLineWidth = outLineWidth;
this.counterclockwise = counterclockwise;
this.slider = slider;
this.color = color;
this.sliderColor = sliderColor;
this.sliderBorderColor = sliderBorderColor;
this.value = value;
this.textShow = textShow;
this.change = change;
this.isDown = false;
this.event(el)
},
OnMouseMove(evt) {
if (!this.isDown) return;
let evpoint = {};
evpoint.x = this.getx(evt);
evpoint.y = this.gety(evt);
let point = this.spotchangeXY(evpoint);
let deg = this.XYToDeg(point.x, point.y);
deg = this.counterclockwise ? deg : Math.PI * 2 - deg;
let val = (deg/ Math.PI - this.startDeg) / (this.endDeg - this.startDeg) * 100
if(val<0) val = 100 + val;
if(val >= 100) val = 100;
if(val <= 0) val = 0;
if(Math.abs (val - this.value) > 10) return;
//音频定位播放
let time = val/this.than;
let audio = this.$refs.audio;
audio.currentTime = time
this.animate = requestAnimationFrame(this.draw.bind(this,val));
if(this.value != Math.round(val)){
this.value = Math.round(val);
this.change(this.value)
}
},
OnMouseUp(evt) { //鼠标释放
const _this = this
cancelAnimationFrame(_this.animate);
this.isDown = false;
if(this.distance(evt)){
this.playbool = false;
let audio = this.$refs.audio;
//播放音频
audio.play()
}
},
distance(evt){
let x = this.getx(evt);
let y = this.gety(evt);
let distance = Math.abs(Math.sqrt(Math.pow(x - 135, 2) + Math.pow(y - 135, 2)));
if(0<distance && distance<130){
return true
}else{
return false
}
},
//点击定位
clearLocation(evt){
let evpoint = {};
evpoint.x = this.getx(evt);
evpoint.y = this.gety(evt);
let point = this.spotchangeXY(evpoint);
let deg = this.XYToDeg(point.x, point.y);
deg = this.counterclockwise ? deg : Math.PI * 2 - deg;
let val = (deg/ Math.PI - this.startDeg) / (this.endDeg - this.startDeg) * 100
if(val<0) val = 100 + val;
if(val >= 100) val = 100;
if(val <= 0) val = 0;
if(this.distance(evt)){
this.animate = requestAnimationFrame(this.draw.bind(this,val));
//音频定位播放
let time = val/this.than;
let audio = this.$refs.audio;
audio.currentTime = time
audio.play()
audio.pause()
if(this.value != Math.round(val)){
this.value = Math.round(val);
this.change(this.value)
}
}
},
//绘图
draw(value) {
this.ctx.clearRect(0, 0, this.width, this.width);
this.ctx.save();
let startDeg = this.counterclockwise ? Math.PI * (2 - this.startDeg) : Math.PI * this.startDeg
let endDeg = this.counterclockwise ? Math.PI * (2 - this.endDeg) : Math.PI * this.endDeg
// 绘制外侧圆弧
this.ctx.beginPath();
this.ctx.arc(this.center, this.center, this.radius, startDeg, endDeg, this.counterclockwise); // 绘制外侧圆弧
this.ctx.strokeStyle = this.outColor;
this.ctx.lineCap = "round";
this.ctx.lineWidth = this.outLineWidth;
this.ctx.stroke();
let Deg = this.valToDeg(value)
// 绘制可变圆弧
let themeColor = (typeof this.color == 'String') ? this.color : this.setLinearGradient()
this.ctx.beginPath();
this.ctx.arc(this.center, this.center, this.radius, startDeg, Deg, this.counterclockwise); // 可变圆弧
this.ctx.strokeStyle = themeColor;
this.ctx.lineCap = "round";
this.ctx.lineWidth = this.outLineWidth;
this.ctx.stroke();
// 绘制滑块
this.P = this.DegToXY(Deg)
this.ctx.beginPath();
this.ctx.moveTo(this.center, this.center);
this.ctx.arc(this.P.x, this.P.y, this.slider, 0, Math.PI * 2, false); // 绘制滑块
this.ctx.fillStyle = this.sliderColor;;
this.ctx.fill();
},
initCanvas(dom) {
this.canvas = document.createElement("canvas");
this.canvas.setAttribute("id", "dragArc");
this.canvas.setAttribute("width", this.width);
this.canvas.setAttribute("height", this.width);
dom.appendChild(this.canvas);
this.ctx = this.canvas.getContext("2d");
this.isMobile = /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent);
},
//将值转化为弧度
valToDeg(v) {
let range = this.endDeg - this.startDeg;
let val = range / 100 * v;
if(this.counterclockwise && (val !=0) ) val = 2 -val;
let startDeg = this.counterclockwise ? (2 - this.startDeg) : this.startDeg;
return (startDeg + val) * Math.PI;
},
// 弧度转化为对应坐标值
DegToXY(deg) {
let d = 2 * Math.PI - deg;
return this.respotchangeXY({
x: this.radius * Math.cos(d),
y: this.radius * Math.sin(d)
})
},
//canvas坐标转化为中心坐标
spotchangeXY(point) {
const spotchangeX = (i) => {
return i - this.center
}
const spotchangeY = (i) => {
return this.center - i
}
return {
x: spotchangeX(point.x),
y: spotchangeY(point.y)
}
},
//中心坐标转化为canvas坐标
respotchangeXY(point) {
const spotchangeX = (i) => {
return i + this.center
}
const spotchangeY = (i) => {
return this.center - i
}
return {
x: spotchangeX(point.x),
y: spotchangeY(point.y)
}
},
setLinearGradient(){
const grad = this.ctx.createLinearGradient(0,0, 0,this.width);
this.color.forEach((e, i) => {
if(i == 0){
grad.addColorStop(0, e)
}else if(i == this.color.length - 1){
grad.addColorStop(1, e)
}else{
grad.addColorStop(1/this.color.length * (i+1), e);
}
});
return grad;
},
// 将坐标点转化为弧度
XYToDeg(lx, ly) {
let adeg = Math.atan(ly / lx)
let deg;
if (lx >= 0 && ly >= 0) {
deg = adeg ;
}
if (lx <= 0 && ly >= 0) {
deg = adeg + Math.PI;
}
if (lx <= 0 && ly <= 0) {
deg = adeg + Math.PI;
}
if (lx > 0 && ly < 0) {
deg = adeg + Math.PI * 2;
}
return deg
},
//获取鼠标在canvas内坐标x
getx(ev) {
if(!this.isMobile) return ev.clientX - this.el.getBoundingClientRect().left;
if(ev.touches.length){
return ev.touches[0].pageX - this.el.getBoundingClientRect().left;
}else{
return ev.changedTouches[0].pageX - this.el.getBoundingClientRect().left;
}
},
//获取鼠标在canvas内坐标y
gety(ev) {
if(!this.isMobile) return ev.clientY - this.el.getBoundingClientRect().top;
if(ev.touches.length){
return ev.touches[0].pageY - this.el.getBoundingClientRect().top;
}else{
return ev.changedTouches[0].pageY - this.el.getBoundingClientRect().top;
}
},
//节流
throttle(func) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > 10) {
func.apply(context, args);
previous = now;
}
}
},
}
}
</script>
<style scoped>
.circle_box{
position: relative;
padding-top: 130px;
top: 0;
left: 0;
width: 100%;
height: 245px;
}
#content{
position: absolute;
left: 50%;
transform: translateX(-50%);
height: 240px;
width: 270px;
}
.img_0{
position: absolute;
top: 175px;
left: 50%;
transform: translateX(-50%);
width: 180px;
height: 180px;
border-radius: 50%;
z-index: 5;
}
.img_1{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 243px;
width: 34px;
height: 46px;
z-index: 10;
}
.posi{
position: absolute;
left: 0;
top: 10px;
z-index: 1000;
}
</style>
vue3.0 安卓和ios h5 移动端音频自定义圆环可拖拽播放(兼容微信浏览器)相关推荐
- 精品手游小精灵大作战源码 安卓+IOS+H5三端Cocos Creator 客户端 JAVA服务端
小精灵大作战 数据库说明 数据库使用MySQL,推荐管理软件Navicat For MySQL. 创建数据库命名为pet_battle,字符集选用utf8 -- UTF-8 Unicode,排序规则选 ...
- pc 端与移动端区分点击与拖拽事件
pc 端与移动端区分点击与拖拽事件 PC 端 移动端 在 html 的应用中,拖拽事件为 mousedown -> mousemove -> mouseup 三个事件组成,在一个有拖拽事件 ...
- ios keychain 不被清理_卧槽牛弊了,已完美破姐!支持 安卓、ios、PC端,爽....
感谢您抽出 . . 阅读本文 谢谢您的关注写在前面 点击上方 " 老鬼黑科技 " 选择 " 置顶公众号 " 关键时刻,第一时间送达 老鬼会把全网最好的软件分享给 ...
- H5进入页面音乐播放兼容微信,浏览器,APP内嵌
最近公司接到要做个活动页,需要背景音乐要进入页面就播放,H5与浏览器都要兼容,但看了浏览器好像禁止页面进入播放音乐,然后就找各种文档.废话不多说上代码... HTML代码 <input type ...
- 安卓开发仿微信图片拖拽_Android 仿微信朋友圈图片拖拽返回
目前的app的动画效果是越来越炫了,很多主流app的图片预览返回都有类似功能,比较常见的是ios自带相册,微信朋友圈等等.自己项目中也有类似功能,最近整理了一下这个功能的代码,做个笔记记录,有兴趣的朋 ...
- iOS开发——仿微信图片浏览交互的实现(向下拖拽图片退出图片浏览器)
点击上方"iOS开发",选择"置顶公众号" 关键时刻,第一时间送达! DEMO的github地址:https://github.com/YYProgrammer ...
- 点击图片放大,实现移动端双指缩放,单指拖拽功能
记录一下最近项目中用到的点击图片出现一个遮罩层,同时放大图片显示,移动端可双指缩放图片并单指拖拽图片.再次点击遮罩层透明区域,遮罩层消失 一.实现效果: 页面原图展示: 点击图片后: 二.代码实现: ...
- 安卓开发仿微信图片拖拽_Android 仿微信朋友圈发表图片拖拽和删除功能
朋友圈实现原理 我们使用 Android Device Monitor 来分析朋友圈发布图片的界面实现原理.如果需要分析其他应用的界面实现也是采用这种方法哦. 打开 Android Device Mo ...
- 安卓开发仿微信图片拖拽_仿微信朋友圈发表图片拖拽和删除功能
原标题:仿微信朋友圈发表图片拖拽和删除功能 中国联通在香港公布了上市公司2017年中期业绩.2017年上半年,公司主要业绩指标持续向好,收入稳步回升,服务收入达到人民币1,241.1亿元,同比增长3. ...
最新文章
- ucint核心边缘分析_5G、云计算、物联网与边缘计算的相辅相承
- 如何批量给数字前面加半角单引号[转]
- Split in Java
- 深度学习(七十四)半监督Mean teachers
- 过年了,就别再背电脑回家。
- 【编译原理笔记09】语法制导翻译:语法制导翻译方案,在非递归的预测分析过程中进行翻译
- NLP︱LDA主题模型的应用难题、使用心得及从多元统计角度剖析
- DirectX修复工具 4.0 标准版
- 走全渠道电商O2O模式的优势体现在哪些地方?
- 时光轴一之listView实现时光轴效果
- 【coq】函数语言设计 笔记 06 -logic
- ValueError: Weights for model sequential have not yet been created. Weights are created when the Mod
- 嘉曼服饰上市破发,大跌16%:公司市值37亿 刘溦家族色彩浓厚
- 【考研经验】一个苍山的不入流的学生的考研之路
- ibatis中resultMap和resultClass的区别 以及parameterClass 的取值
- html中onfocus和onblur的使用
- JAVA面试题100道
- FL Studio教程之如何外接设备
- Unity内实现MMD
- 互联网、因特网、万维网的区别