1***@qq.com
1***@qq.com
  • 发布:2024-12-09 11:52
  • 更新:2024-12-09 15:23
  • 阅读:57

【报Bug】uniapp uni.createInnerAudioContext() 安卓onTimeUpdate会触发很多次

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Mac

PC开发环境操作系统版本号: 15.6

HBuilderX类型: 正式

HBuilderX版本号: 4.36

手机系统: Android

手机系统版本号: Android 14

手机厂商: OPPO

手机机型: open reno10

页面类型: vue

vue版本: vue3

打包方式: 云端

项目创建方式: HBuilderX

示例代码:

、、、
const createAudioFn = () => {
audioDom.value = uni.createInnerAudioContext();
audioDom.value.onCanplay(() => {
allTime.value = Math.ceil(audioDom.value?.duration);
uni.hideLoading();
});
audioDom.value.onTimeUpdate(() => {
console.log('这里');
if (!allTime.value) {
allTime.value = audioDom.value.duration;
}
playSlider.value = Math.ceil(audioDom.value?.currentTime);
playTime.value = formatTime(audioDom.value?.currentTime);
if (autoShowImgAudio.value) {
swiperCurrent.value = getCurrentIndex(playSlider.value);
}
});
audioDom.value.onPlay(() => {
play.value = true;
});
audioDom.value.onPause(() => {
play.value = false;
});
audioDom.value.onEnded(() => {
audioTimeEndCangeNextFn();
});
};
、、、
、、、
// 第一个
const goFirstZhangjieFn = () => {
page.value = 0;
playAudio(true);
};
// 下一个
const goNextZhangjieFn = () => {
page.value += 1;
playSlider.value = 0;
swiperCurrent.value = 0;
playAudio(true);
};
// 重0开始
const chongtouFn = () => {
audioDom.value.seek(0);
playSlider.value = 0;
playTime.value = formatTime(0);
swiperCurrent.value = 0;
if (!bofangma.value) return;
audioDom.value.play();
};
// 单个音频的指定章节
const tiaoZhidingdeZhangjieFn = (e) => {
const seekTime = Number(audioInfo.value.fanyeshijian[0][audioInfo.value.zhangjieye[e - 1] - 1]);
audioDom.value.seek(seekTime);
const indexs = audioInfo.value.fanyeshijian[page.value].findIndex((item) => item > seekTime);
swiperCurrent.value = indexs;
playSlider.value = seekTime;
if (!bofangma.value) return;
audioDom.value.play();
};
// 指定的章节
const goZhidingdFn = (e) => {
page.value = e;
playSlider.value = 0;
swiperCurrent.value = 0;
playTime.value = formatTime(0);
console.log(3333);
playAudio();
};
// 属于点击的 恢复到最开始 还要判断当前是不是不允许播放状态
const gofirstTimeFn = () => {
audioDom.value.seek(0);
playSlider.value = 0;
swiperCurrent.value = 0;
if (!bofangma.value) return;
audioDom.value.play();
};
// 公共的类型id 1=next
const returnTypeId = (go = 1) => {
const type = formType.value == 1 || !formType.value ? 'id' : 'book_id';
const index = list.value.findIndex((item) => {
return item[type] == id.value;
});
let num = 0;
if (go == 1) {
num = index == list.value.length - 1 ? 0 : index + 1;
} else {
num = index == 0 ? list.value.length - 1 : index - 1;
}
id.value = list.value[num][type];
getBookDetails(true).finally(() => {
swiperCurrent.value = 0;
});
};
// 公共的播放结束换下一个的事件
/**{

  • @param type =false 正常切换章节 true下本书
    } */
    const audioTimeEndCangeNextFn = (type = false) => {
    if (!type && page.value < audioInfo.value.yinpinurl.length - 1) {
    goNextZhangjieFn();
    return;
    }
    // 单曲循环
    if (!type && autoListPlauAudio.value) {
    if (audioInfo.value.yinpinurl.length != 1) goFirstZhangjieFn();
    if (audioInfo.value.yinpinurl.length == 1) chongtouFn();
    return;
    }
    // 要知道是自己结束的 还是手动的
    if (!type && list.value.length == 1) {
    return;
    }
    returnTypeId();
    };
    // 上一个
    /**{
    • @param type =false 正常切换章节 true上一个书
      } */
      const audioTimeStartFn = (type = false) => {
      const audioList = list.value.length;
      if (audioList == 1 && type) {
      uni.showToast({
      title: '播放列表暂无其他书籍',
      icon: 'none'
      });
      return;
      }
      let zhuangtai = bofangma.value;
      audioDom.value.pause();
      if (type || page.value == 0) {
      playTime.value = formatTime(0);
      swiperCurrent.value = 0;
      playSlider.value = 0;
      returnTypeId(2);
      return;
      }
      audioDom.value.pause();
      // 上个章节
      if (audioInfo.value.yinpinurl.length != 1) {
      showSwiper.value = false;
      page.value -= 1;
      // 隐藏轮播图
      uni.showLoading({
      mask: true,
      title: '加载中'
      });
      audioDom.value.src = audioInfo.value.yinpinurl[page.value];
      // 去上一页的翻页时间
      let hou =
      audioInfo.value.fanyeshijian[page.value].length == 1 ?
      0 :
      audioInfo.value.fanyeshijian[page.value][
      audioInfo.value.fanyeshijian[page.value].length - 2
      ];
      changeAudio(0);
      bofangaaaa();
      audioDom.value.pause()
      setTimeout(() => {
      changeAudio(hou);
      playSlider.value = hou;
      swiperCurrent.value = audioInfo.value.tupianurl[page.value].length - 1;
      if (!zhuangtai) {
      setTimeout(() => {
      audioDom.value.pause();
      bofangma.value = false;
      showSwiper.value = true;
      uni.hideLoading();
      }, 100);
      } else {
      showSwiper.value = true;
      uni.hideLoading();
      }
      }, 800);
      }
      };
      、、、

操作步骤:

、、、
<script setup>
import {
ref,
computed,
reactive,
onMounted,
nextTick,
watch
} from 'vue';
import {
onShow,
onHide,
onUnload,
onLoad,
onResize
} from '@dcloudio/uni-app';
import {
bodanApi,
userInfoApi,
jieshuApi,
bofanggengduoapi,
tuozhuaiapi
} from '/api/request.js';
import Header from '/components/header/index.vue';
import haoSlider from '/components/hao-slider/hao-slider.vue';
import switchs from './switch.vue';
import xxgSortableList from '../audio/xxgSortableList.vue';
import xxgSortableLists from '../audio/xxgSortableLists.vue';
const platform = uni.getStorageSync('platform');
/**

  • @param window_android 初始化系统相关
    */
    const window_android = ref(null);
    if (platform == 'Android') {
    var Color = plus.android.importClass('android.graphics.Color');
    plus.android.importClass('android.view.Window');
    var mainActivity = plus.android.runtimeMainActivity();
    window_android.value = mainActivity.getWindow();
    }
    /**
  • @param types 横屏landscape 竖屏portrait
    */
    const types = ref('');
    const createAudioFn = () => {
    audioDom.value = uni.createInnerAudioContext();
    audioDom.value.onCanplay(() => {
    allTime.value = Math.ceil(audioDom.value?.duration);
    uni.hideLoading();
    });
    audioDom.value.onTimeUpdate(() => {
    console.log('这里');
    if (!allTime.value) {
    allTime.value = audioDom.value.duration;
    }
    playSlider.value = Math.ceil(audioDom.value?.currentTime);
    playTime.value = formatTime(audioDom.value?.currentTime);
    if (autoShowImgAudio.value) {
    swiperCurrent.value = getCurrentIndex(playSlider.value);
    }
    });
    audioDom.value.onPlay(() => {
    play.value = true;
    });
    audioDom.value.onPause(() => {
    play.value = false;
    });
    audioDom.value.onEnded(() => {
    audioTimeEndCangeNextFn();
    });
    };
    // 第一个
    const goFirstZhangjieFn = () => {
    page.value = 0;
    playAudio(true);
    };
    // 下一个
    const goNextZhangjieFn = () => {
    page.value += 1;
    playSlider.value = 0;
    swiperCurrent.value = 0;
    playAudio(true);
    };
    // 重0开始
    const chongtouFn = () => {
    audioDom.value.seek(0);
    playSlider.value = 0;
    playTime.value = formatTime(0);
    swiperCurrent.value = 0;
    if (!bofangma.value) return;
    audioDom.value.play();
    };
    // 单个音频的指定章节
    const tiaoZhidingdeZhangjieFn = (e) => {
    const seekTime = Number(audioInfo.value.fanyeshijian[0][audioInfo.value.zhangjieye[e - 1] - 1]);
    audioDom.value.seek(seekTime);
    const indexs = audioInfo.value.fanyeshijian[page.value].findIndex((item) => item > seekTime);
    swiperCurrent.value = indexs;
    playSlider.value = seekTime;
    if (!bofangma.value) return;
    audioDom.value.play();
    };
    // 指定的章节
    const goZhidingdFn = (e) => {
    page.value = e;
    playSlider.value = 0;
    swiperCurrent.value = 0;
    playTime.value = formatTime(0);
    console.log(3333);
    playAudio();
    };
    // 属于点击的 恢复到最开始 还要判断当前是不是不允许播放状态
    const gofirstTimeFn = () => {
    audioDom.value.seek(0);
    playSlider.value = 0;
    swiperCurrent.value = 0;
    if (!bofangma.value) return;
    audioDom.value.play();
    };
    // 公共的类型id 1=next
    const returnTypeId = (go = 1) => {
    const type = formType.value == 1 || !formType.value ? 'id' : 'book_id';
    const index = list.value.findIndex((item) => {
    return item[type] == id.value;
    });
    let num = 0;
    if (go == 1) {
    num = index == list.value.length - 1 ? 0 : index + 1;
    } else {
    num = index == 0 ? list.value.length - 1 : index - 1;
    }
    id.value = list.value[num][type];
    getBookDetails(true).finally(() => {
    swiperCurrent.value = 0;
    });
    };
    // 公共的播放结束换下一个的事件
    /**{

    • @param type =false 正常切换章节 true下本书
      } */
      const audioTimeEndCangeNextFn = (type = false) => {
      if (!type && page.value < audioInfo.value.yinpinurl.length - 1) {
      goNextZhangjieFn();
      return;
      }
      // 单曲循环
      if (!type && autoListPlauAudio.value) {
      if (audioInfo.value.yinpinurl.length != 1) goFirstZhangjieFn();
      if (audioInfo.value.yinpinurl.length == 1) chongtouFn();
      return;
      }
      // 要知道是自己结束的 还是手动的
      if (!type && list.value.length == 1) {
      return;
      }
      returnTypeId();
      };
      // 上一个
      /**{
      • @param type =false 正常切换章节 true上一个书
        } */
        const audioTimeStartFn = (type = false) => {
        const audioList = list.value.length;
        if (audioList == 1 && type) {
        uni.showToast({
        title: '播放列表暂无其他书籍',
        icon: 'none'
        });
        return;
        }
        let zhuangtai = bofangma.value;
        audioDom.value.pause();
        if (type || page.value == 0) {
        playTime.value = formatTime(0);
        swiperCurrent.value = 0;
        playSlider.value = 0;
        returnTypeId(2);
        return;
        }
        audioDom.value.pause();
        // 上个章节
        if (audioInfo.value.yinpinurl.length != 1) {
        showSwiper.value = false;
        page.value -= 1;
        // 隐藏轮播图
        uni.showLoading({
        mask: true,
        title: '加载中'
        });
        audioDom.value.src = audioInfo.value.yinpinurl[page.value];
        // 去上一页的翻页时间
        let hou =
        audioInfo.value.fanyeshijian[page.value].length == 1 ?
        0 :
        audioInfo.value.fanyeshijian[page.value][
        audioInfo.value.fanyeshijian[page.value].length - 2
        ];
        changeAudio(0);
        bofangaaaa();
        audioDom.value.pause()
        setTimeout(() => {
        changeAudio(hou);
        playSlider.value = hou;
        swiperCurrent.value = audioInfo.value.tupianurl[page.value].length - 1;
        if (!zhuangtai) {
        setTimeout(() => {
        audioDom.value.pause();
        bofangma.value = false;
        showSwiper.value = true;
        uni.hideLoading();
        }, 100);
        } else {
        showSwiper.value = true;
        uni.hideLoading();
        }
        }, 800);
        }
        };
        onLoad((options) => {
        lockPortrait(); //一开始就锁住为竖屏
        let bofang = uni.getStorageSync('bofangfangshi');
        if (bofang) autoShowImgAudio.value = bofang;
        id.value = options.id;
        formType.value = options.typess;
        bodanId.value = options.bodanid;
        createAudioFn();
        uni.getSystemInfo({
        success: (res) => {
        width.value = res.screenWidth;
        }
        });
        });
        const enableScreenRotation = () => {
        plus.screen.unlockOrientation(); // 允许屏幕旋转
        };
        const lockPortrait = () => {
        plus.screen.lockOrientation('portrait-primary');
        types.value = 'portrait';
        touming.value = false;
        };
        // 隐藏按键 横板的时候
        const touming = ref(false);
        const showTouMing = () => {
        if (types.value == 'landscape') {
        touming.value = !touming.value;
        }
        };
        // 顶部的距离
        const topHeights = ref(10);
        onShow(() => {
        if (!audioDom.value) {
        uni.navigateBack()
        }
        enableScreenRotation(); //允许旋转
        touming.value = false;
        topHeights.value = uni.getStorageSync('gaodus__lai');
        });
        let deml
        onResize((res) => {
        if (deml) {
        clearTimeout(deml)
        }
        deml = setTimeout(() => {
        types.value = res.deviceOrientation;
        if (types.value == 'landscape') {
        window_android.value.setNavigationBarColor(Color.parseColor('#fef7e3'));
        } else {
        window_android.value.setNavigationBarColor(Color.parseColor('#f3f3f3'));
        touming.value = false;
        }
        clearTimeout(deml)
        }, 20)
        });
        const showImgModeType = ref('widthFix');
        const showTop = ref(false); //切换章节的弹窗
        const kuaiojinde = ref(1); //当前的播放速度
        const list = ref([]); //我的播单里面的数据
        const maskStyle = computed(() => {
        return {
        position: 'fixed',
        bottom: 0,
        top: 0,
        left: 0,
        right: '0',
        zIndex: 999,
        backgroundColor: 'rgba(0, 0, 0, 0.4)',
        transition: 'right 0.3s ease, background-color 0.3s ease'
        };
        });
        const nowZhangjie = computed(() => {
        const shijian = playSlider.value;
        const index = audioInfo.value.fanyeshijian[0].findIndex((item) => shijian < item);
        const item = audioInfo.value.zhangjieye.findIndex((i) => index < i);
        return item !== -1 ? item : audioInfo.value.zhangjieye.length - 1;
        });
        const changeImgs = (e) => {
        if (page.value == e) return;
        if (audioInfo.value.yinpinurl.length === 1) {
        if (e === 0) {
        gofirstTimeFn();
        } else {
        tiaoZhidingdeZhangjieFn(e);
        }
        showTop.value = false;
        return;
        }
        goZhidingdFn(e);
        showTop.value = false;
        };
        const bofangfangshiPopup = ref(null);
        const getPopupPosition = () => (types.value === 'portrait' ? 'bottom' : 'center');
        const getPopupPositions = () => (types.value === 'portrait' ? 'bottom' : 'right');
        const showBofangFnagshi = () => {
        bofangfangshiPopup.value.open(getPopupPosition());
        };
        const shoufei = ref(null);
        const showBottomsssssss = ref(null);
        const changeBoFangShunxu = () => {
        showBottomsssssss.value.open(getPopupPositions());
        };
        const newLists = async (e) => {
        list.value = e;
        const str = e.map((item) => item.id).join(',');
        if (!str) return;
        try {
        const res = await tuozhuaiapi({
        sort_ids: str
        });
        if (res.code !== 1) {
        uni.showToast({
        title: res.msg || '请求失败',
        icon: 'none'
        });
        }
        } catch (error) {
        uni.showToast({
        title: error.message || '请求失败',
        icon: 'none'
        });
        }
        };
        const showMulu = () => {
        showTop.value = true;
        };
        const changebofangde = async (isd) => {
        if (audioInfo.value.id == isd) {
        return;
        }
        id.value = isd;
        getBookDetails();
        showBottomsssssss.value.close();
        };
        // 获取书籍列表
        const getQitaBookList = async () => {
        try {
        let ssssss = await bofanggengduoapi({
        book_id: id.value,
        type: formType.value || 3,
        play_id: bodanId.value
        });
        list.value = ssssss.data;
        } catch (e) {
        console.log(e);
        }
        };
        const goback = () => {
        shoufei.value.close();
        uni.navigateBack();
        };
        const open = () => {
        shoufei.value.close();
        uni.setStorageSync('zhankaiba', true);
        uni.switchTab({
        url: '/pages/user/index'
        });
        };
        // 播放速度
        const gengxin = (index) => {
        audioDom.value.playbackRate = index;
        kuaiojinde.value = index;
        };
        const formatTime = (timeInSeconds) => {
        const hours = Math.floor(timeInSeconds / 3600); // 获取小时
        const minutes = Math.floor((timeInSeconds % 3600) / 60); // 获取分钟
        const seconds = Math.floor(timeInSeconds % 60); // 获取秒数
        const pad = (num) => String(num).padStart(2, '0');
        return ${pad(hours)}:${pad(minutes)}:${pad(seconds)};
        };

    function getCurrentIndex(currentTime) {
    let yinPinList =
    audioInfo.value.fanyeshijian[audioInfo.value.yinpinurl.length == 1 ? 0 : page.value];
    const index = yinPinList.findIndex((item) => item > currentTime);
    if (index != -1) {
    return index;
    } else {
    return yinPinList.length - 1;
    }
    }
    const id = ref('');
    const formType = ref('');
    const autoShowImgAudio = ref(true);
    const autoListPlauAudio = ref(false); //是否单曲循环
    const width = ref('');
    const showSwiper = ref(true);
    const showNextPage = () => {
    if (swiperCurrent.value == 0 && audioInfo.value.tupianurl[page.value].length != 1) return;
    audioTimeEndCangeNextFn();
    };
    const changeSwiper = (e) => {
    if (!showSwiper.value) return;
    let pages = e.detail.current;
    if (!autoShowImgAudio.value) {
    swiperCurrent.value = pages;
    return;
    }
    let go = () => {
    // audioDom.value.pause();
    let time = audioInfo.value.fanyeshijian[page.value][pages - 1];
    playSlider.value = Math.ceil(audioInfo.value.fanyeshijian[page.value][pages - 1]);
    playTime.value = formatTime(time);
    audioDom.value.seek(time);
    if (!bofangma.value) return;
    // audioDom.value.play();
    };
    if (!play.value) {
    //不存在就说明是进度条过来的
    if (!startValue.value) {
    return;
    }
    //不是第一个图片过来的话
    if (swiperCurrent.value != 0) {
    startValue.value = 0;
    }
    if (pages == 0) {
    chongtouFn();
    } else {
    go();
    }
    swiperCurrent.value = pages;
    }
    if (swiperCurrent.value == pages) {
    return;
    }
    if (autoShowImgAudio.value) {
    if (pages == 0) {
    chongtouFn();
    } else {
    if (!startValue.value) {
    return;
    }
    go();
    }
    }
    };
    const bofangaaaa = () => {
    audioDom.value.play();
    bofangma.value = true;
    };
    const zantingaaa = () => {
    audioDom.value.pause();
    bofangma.value = false;
    };
    const changeAudio = (e) => {
    if (typeof e === 'object' && e.detail && e.detail.value !== undefined) {
    audioDom.value.seek(e.detail.value);
    } else {
    audioDom.value.seek(e);
    }
    if (!autoShowImgAudio.value) {
    return;
    }
    if (!bofangma.value) {
    const index = audioInfo.value.fanyeshijian[page.value].findIndex((item) => item > e);
    swiperCurrent.value = index;
    }
    if (!play.value) {
    audioDom.value.pause();
    startValue.value = 0;
    }
    };
    const swiperCurrent = ref(0);
    const page = ref(0);
    const play = ref(true);
    const audioInfo = ref({});
    const audioDom = ref(null);
    const playSlider = ref(0);
    const allTime = ref(0);
    const playTime = ref('');
    const playAudio = () => {
    uni.showLoading()
    audioDom.value.pause();
    audioDom.value.src = audioInfo.value.yinpinurl[page.value];
    audioInfo.value.autoplay = true;
    if (!bofangma.value) return;
    bofangaaaa();
    let imgList = audioInfo.value.tupianurl[page.value];
    let arrs = [];
    if (imgList.length > 1) {
    arrs.push(imgList[0]);
    arrs.push(imgList[imgList.length - 1]);
    } else {
    arrs.push(imgList[0]);
    }
    getImgInfoValues(arrs);
    };

    const getImgInfoValues = async (arr) => {
    uni.showLoading({
    title: '加载中',
    mask: true
    });
    let heightCount = 0;
    let widthCount = 0;
    const promises = arr.map((item) => {
    return new Promise((resolve) => {
    uni.getImageInfo({
    src: item,
    success(e) {
    if (e.height > e.width) {
    heightCount++;
    } else if (e.width > e.height) {
    widthCount++;
    }
    resolve();
    },
    fail() {
    resolve();
    }
    });
    });
    });
    await Promise.all(promises);
    if (heightCount > widthCount) {
    showImgModeType.value = 'heightFix';
    } else if (widthCount > heightCount) {
    showImgModeType.value = 'widthFix';
    } else {
    showImgModeType.value = 'heightFix';
    }
    uni.hideLoading();
    console.log(showImgModeType.value); // 输出最终的模式
    };
    const getBookDetails = async (type = false) => {
    let res = await bodanApi({
    book_id: id.value
    });
    console.log(res);
    if (res.code != 1) {
    uni.showToast({
    title: res.msg,
    icon: 'none'
    });
    setTimeout(() => {
    uni.navigateBack();
    }, 1000);
    return;
    }
    try {
    audioInfo.value = res.data.data;
    page.value = 0;
    playAudio(type);
    } catch (e) {
    console.log(e);
    }
    };

    const changeZiDong = (e) => {
    autoShowImgAudio.value = e;
    console.log(autoShowImgAudio.value);
    uni.setStorageSync('bofangfangshi', autoShowImgAudio.value);
    console.log(uni.getStorageSync('bofangfangshi'));
    };
    const changeshoudong = (e) => {
    autoListPlauAudio.value = e;
    uni.setStorageSync('xunhuan', autoListPlauAudio.value);
    };
    let bodanId = ref('');
    onMounted(async () => {
    let res = await userInfoApi();
    if (res.data.is_member == 1) {
    getBookDetails();
    getQitaBookList();
    } else {
    shoufei.value.open('center');
    }
    });
    const showSwiperIndex = computed(() => {
    let sum = 0;
    let arr = Array.from({
    length: page.value
    });
    arr.forEach((item, index) => {
    if (audioInfo.value.tupianurl[index] && Array.isArray(audioInfo.value.tupianurl[index])) {
    sum += audioInfo.value.tupianurl[index].length;
    }
    });
    sum = sum + (autoShowImgAudio.value ? swiperCurrent.value + 1 : swiperCurrent.value + 1);
    return sum; // 返回
    });
    const allSwiperListImgLength = computed(() => {
    if (!audioInfo.value.tupianurl) {
    return 0;
    }
    let sum = audioInfo.value.tupianurl.reduce((num, item) => num + item.length, 0);
    return sum;
    });

    const startValue = ref(0);
    const endValue = ref(0);
    const minDistance = 40;
    const handleTouchStart = (event) => {
    startValue.value = event.touches[0].clientX; // 获取触摸开始时的水平坐标
    };
    const bofangma = ref(true);
    const touchend = (event) => {
    if (autoShowImgAudio.value) {
    if (startValue.value == 0) {
    return;
    }
    if (!play.value) {
    bofangma.value = false;
    } else {
    bofangma.value = true;
    }
    // 单个图片的
    if (audioInfo.value.tupianurl[page.value].length == 1) {
    endValue.value = event.changedTouches[0].clientX;
    if (startValue.value > endValue.value) {
    let distance;
    distance = startValue.value - endValue.value;
    if (distance < minDistance) {
    return;
    } else {
    audioDom.value.pause()
    showNextPage();
    return;
    }
    } else {
    let distance;
    distance = endValue.value - startValue.value;
    if (distance < minDistance) {
    return;
    } else {
    audioDom.value.pause()
    audioTimeStartFn();
    return;
    }
    }
    }

        // 上滑  
        if (  
            swiperCurrent.value == 0 &&  
            ((page.value != 0 && list.value.length == 1) || list.value.length != 1)  
        ) {  
            endValue.value = event.changedTouches[0].clientX;  
            let distance;  
            distance = endValue.value - startValue.value;  
            if (distance < minDistance) {  
                return;  
            } else {  
                audioTimeStartFn();  
            }  
        } else {  
            // 下滑  
            if (swiperCurrent.value == audioInfo.value.tupianurl[page.value].length - 1) {  
                if (  
                    list.value.length == 1 &&  
                    page.value != audioInfo.value.tupianurl.length - 1 &&  
                    audioInfo.value.yinpinurl.length != 1  
                ) {  
                    endValue.value = event.changedTouches[0].clientX;  
                    let distance;  
                    distance = startValue.value - endValue.value;  
                    if (distance < minDistance) {  
                        return;  
                    } else {  
                        showNextPage();  
                    }  
                } else if (list.value.length != 1) {  
                    endValue.value = event.changedTouches[0].clientX;  
                    let distance;  
                    distance = startValue.value - endValue.value;  
                    if (distance < minDistance) {  
                        return;  
                    } else {  
                        showNextPage();  
                    }  
                }  
            }  
        }  
    }  

    };
    const jingyin = ref(1);
    const changessssss = () => {
    jingyin.value = jingyin.value == 0 ? 1 : 0;
    audioDom.value.volume = jingyin.value;
    };
    const addHistory = async () => {
    let query = {
    book_id: id.value,
    listen_time: '',
    page: '',
    page_number: ''
    };
    await jieshuApi(query);
    id.value = '';
    };
    const closePage = () => {
    audioDom.value.pause();
    audioDom.value.src = ''
    audioDom.value.offTimeUpdate();
    audioDom.value.destroy();
    audioDom.value = null;
    console.log(audioDom.value);
    lockPortrait();
    uni.hideLoading();
    addHistory();
    };
    onHide(() => {
    closePage();
    });
    onUnload(() => {
    closePage();
    });
    </script>

<template> <view :style="{ filter: !showSwiper ? 'blur(5px)' : '' }" class="wrap uni-col" class="types == 'landscape' ? 'hengde' : ''"> <Header v-show="types != 'landscape'" :title="audioInfo?.shuming || ''" />
<scroll-view class="wraps" :scroll-y="true">
<view class="page uni-col" @click="showTouMing">
<view class="banner" v-if="
audioInfo &&
audioInfo?.tupianurl &&
audioInfo?.tupianurl.length &&
audioInfo?.tupianurl[page] &&
audioInfo?.tupianurl[page].length
">
<swiper :style="{
opacity: showSwiper ? 1 : 0
}" @touchstart="handleTouchStart" @touchend="touchend"
v-if="audioInfo?.tupianurl[page] && audioInfo?.tupianurl[page].length" @change="changeSwiper" current="swiperCurrent" class="swiper" id="swiper" :autoplay="false" :indicator-dots="false" indicator-color="#d9d9d9" style="height: 100%; max-width: 100%">
<swiper-item v-for="(item, index) in audioInfo.tupianurl[page]" :key="index" class="swiper-item" class="width > 400 ? 'ipad' : 'phone'" style="height: 100%; max-width: 100%; text-align: center">
<view class="father" style="
height: 100%;
display: flex;
justify-content: center;
align-items: center;
">
<image class="banner-img" :mode="showImgModeType" :src="item" class="showImgModeType == 'widthFix'?'active':'defalt'"> </image>
<image v-if="types != 'landscape'" src="/static/img/play/swiper-bg.png" style="
position: absolute;
bottom: -2rpx;
left: 0rpx;
right: 0rpx;
width: 100%;
height: 368px;
" class="swiper-bg"></image>
</view>
</swiper-item>
</swiper>
</view>
<view class="" v-else style="flex: 1; width: 100%"> </view>
<view :style="{
opacity: touming ? '0' : '1'
}" class="slider uni-row" v-if="
audioInfo &&
audioInfo?.tupianurl &&
audioInfo?.tupianurl.length &&
audioInfo?.tupianurl[page] &&
audioInfo?.tupianurl[page].length
">
{{ showSwiperIndex || 1 }} / {{ allSwiperListImgLength }}
</view>
<view @click.stop :style="{
opacity: touming ? '0' : '1'
}" :class="types == 'landscape' ? 'xindedibu' : ''" class="uni-col biede">
<view class="audio uni-row" v-if="audioInfo && audioInfo.yinpinurl && audioInfo.yinpinurl[page]">
<haoSlider :style="{
opacity: showSwiper ? '1' : 0
}" v-if="types == 'portrait'" sliderBlockShadow="0rpx 2rpx 4rpx 0rpx rgba(182,121,8,0.59)" isTip="false" :max="allTime" :value="Number(playSlider)" :min="0" :sliderHeight="12" sliderBlockSize="28" :sliderRightColor="'#FBEBB8'" :sliderLeftColor="'#FBEBB8'" sliderBgColor="'#FFA602'" @change="changeAudio" /> <slider v-else :style="{
opacity: showSwiper ? '1' : 0
}" class="bottomssss" :block-size="14" :min="0" :max="allTime" :value="Number(playSlider)"

background-color="'#FBEBB8'" :active-color="'#FBEBB8'" :block-color="'#FFA602'" @change="changeAudio" />

                <view class="jindu">  
                    {{ playTime || '00:00:00' }}  
                </view>  
            </view>  
            <view class="caozuo uni-row" style="padding: 0 128rpx">  
                <image @click.stop="changeBoFangShunxu" style="width: 52rpx; height: 52rpx" class="lieb"  
                    src="/static/img/play/liebiao.png"></image>  
                <image @click.stop="audioTimeStartFn(true)" style="width: 52rpx; height: 52rpx"  
                    src="/static/img/play/left.png">  
                </image>  
                <image @click.stop="zantingaaa" v-if="play" class="censsss" src="/static/img/play/bofang.png">  
                </image>  
                <image @click.stop="bofangaaaa" class="censsss" v-else src="/static/img/play/zanting.png">  
                </image>  
                <image @click.stop="audioTimeEndCangeNextFn(true)" style="width: 52rpx; height: 52rpx"  
                    src="/static/img/play/right.png"></image>  
                <image @click.stop="showBofangFnagshi" style="width: 52rpx; height: 52rpx"  
                    src="/static/img/play/shezhi.png"></image>  
            </view>  
        </view>  
    </view>  
</scroll-view>  

</view>
<image @click.stop="showMulu" src="/static/img/play/icon.png" :class="types == 'portrait' ? 'shuo' : 'xxxxxxxxxx'"

style="{ top: (types == 'portrait' ? topHeights + 28 : 30) + 'rpx',
opacity: touming ? '0' : '1'
}" />
<image @click.stop="changessssss" :src="jingyin == 1 ? '/static/img/play/laba.png' : '/static/img/play/labano.png'"
class="shuo" :style="{
top: (types == 'portrait' ? topHeights + 28 : 30) + 'rpx',
opacity: touming ? '0' : '1'
}" :class="types == 'portrait' ? 'xxx' : 'xxxxxx'" />
<!-- 切换章节 -->
<uni-transition :show="showTop" :style="maskStyle" @click="showTop = false" name="slide-fade" mode="out-in">
<uni-transition :show="showTop" :modeClass="['fade', 'slide-right']">
<view class="" :class="types == 'portrait' ? '' : 'xindeos'">
<view class="mask" :class="types == 'portrait' ? '' : 'xindeo'" style="{ marginTop: topHeights + 'rpx' }"> <view class="titlessss uni-row">
<view class="left"> 我的章节 </view>
<image @click.stop="showTop = false" src="/static/img/play/close.png" class="closes"></image>
</view>
<scroll-view :scroll-y="true" class="masks" @click.stop>
<view class="item uni-row" v-for="(item, index) in audioInfo.zhangjieming" :key="index" :class="
index == (audioInfo.yinpinurl.length == 1 ? nowZhangjie : page)
? 'active' '' " @click.stop="changeImgs(index)">
<image :src="
index == (audioInfo.yinpinurl.length == 1 ? nowZhangjie : page)
? '/static/img/audio/bofangzhong.png' '/static/img/audio/bofang.png' " class="bofang" style="margin-right: 10rpx"></image>
<view class="book-name yincang"> {{ item }} </view>
</view>
</scroll-view>
</view>
</view>
</uni-transition>
</uni-transition>
<!-- 收费 -->
<uni-popup ref="shoufei" :is-mask-click="false">
<view class="add-bodan wode">
<image @click.stop="goback" class="close" src="/static/img/close.png"> </image>
<view class="texts"> 此板块为付费内容 快去开通会员吧 </view>
<view class="foorter-list uni-row">
<view class="btns uni-row" @click.stop="goback"> 取消 </view>
<view class="open uni-row" @click.stop="open"> 去开通 </view>
</view>
</view>
</uni-popup>
<!-- 切换播放模式 -->
<uni-popup ref="bofangfangshiPopup">
<view class="waisss" :class="types == 'portrait' ? 'ss' : 'ssssssssssss'">
<view class="titles"> 更多 </view>
<view class="items uni-row">
<text>画音同步</text>
<switchs v-model="autoShowImgAudio" @changeValue="changeZiDong"></switchs>
</view>
<view class="items uni-row">
<text>单本循环</text>
<switchs v-model="autoListPlauAudio" @changeValue="changeshoudong"></switchs>
</view>
<view class="titles sfasfasf" style="margin-top: 50rpx; border: none"> 倍速设置 </view>
<view class="lefr-jindu uni-row">
<text v-for="(item, index) in ['0.5', '1', '1.5', '2']" :key="index" class="item == kuaiojinde ? 'active' : ''" @click.stop="gengxin(item)"> {{ item }}X
</text>
</view>
</view>
</uni-popup>
<!-- 播放顺序 -->
<uni-popup ref="showBottomsssssss" v-if="types == 'portrait'">
<view :scroll-y="true" class="waisss listssss" :style="{ height: width > 400 ? '500px' : '1022rpx' }">
<view class="titles"> 当前播放 </view>
<scroll-view :scroll-y="true" class="listsssssss" :style="{ height: width > 400 ? '400px' : '900rpx' }">
<xxgSortableList :sortable="formType == 2" v-if="list && list.length > 0" :list="list" height="width >= 400 ? 100 : 69" @lists="newLists"> <template v-slot:item="{ item, index }">
<view class="itemssssss uni-row" :style="{ height: width >= 400 ? 100 + 'px' : 69 + 'px' }"
@click.stop="
changebofangde(formType == 1 || !formType ? item.id : item.book_id)
" :class="
((formType == 1 || !formType) && id == item.id) ||
((formType == 2 || !formType) && id == item.book_id)
? 'actuve' '' ">
<view class="uni-row">
{{ index + 1 }}
<view class="left">
<view class="title yincang" :style="{ width: formType == 2 ? '400rpx' : '600rpx' }">
{{ item.shuming }}
</view>
<view class="label uni-row">
<image class="bofang" style="flex-shrink: 0" :src="
((formType == 1 || !formType) && id == item.id) ||
(formType == 2 && id == item.book_id)
? '/static/img/audio/bofangzhong-2.png' '/static/img/audio/bofang-2.png' ">
</image>
<view class="lianghang">
{{
formType == 1 || !formType
? item.jianjie item.create_time }}
</view>
</view>
</view>
</view>
<view class="right" v-if="formType == 2">
<image class="tuozhuai" src="/static/img/audio/tuozhuai.png">
</image>
<image class="shanchu" style="opacity: 0" src="/static/img/audio/shanchu.png">
</image>
</view>
</view>
</template>
</xxgSortableList>
<view class="meiyoul" v-else>
<image src="/static/img/meiyou.png"></image>
<view class="text"> 目前没有数据~ </view>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 播放顺序 -->
<uni-popup ref="showBottomsssssss" v-if="types == 'landscape'">
<view class="hengpingde">
<view class="titles"> 当前播放 </view>
<scroll-view :scroll-y="true" class="listsssssss">
<xxgSortableLists :sortable="formType == 2" v-if="list && list.length > 0" :list="list" :height="50"
@lists="newLists">
<template v-slot:item="{ item, index }">
<view class="itemssssss uni-row" @click.stop="
changebofangde(formType == 1 || !formType ? item.id : item.book_id)
" :class="
((formType == 1 || !formType) && id == item.id) ||
((formType == 2 || !formType) && id == item.book_id)
? 'actuve' '' " style="height: 50px !important">
<view class="uni-row">
{{ index + 1 }}
<view class="left">
<view class="title yincang" :style="{ width: formType == 2 ? '150rpx' : '80%' }">
{{ item.shuming }}
</view>
<view class="label uni-row">
<image class="bofang" style="flex-shrink: 0" :src="
((formType == 1 || !formType) && id == item.id) ||
(formType == 2 && id == item.book_id)
? '/static/img/audio/bofangzhong-2.png' '/static/img/audio/bofang-2.png' ">
</image>
<view class="lianghang">
{{
formType == 1 || !formType
? item.jianjie item.create_time }}
</view>
</view>
</view>
</view>
<view class="right" v-if="formType == 2">
<image class="tuozhuai" src="/static/img/audio/tuozhuai.png">
</image>
</view>
</view>
</template>
</xxgSortableLists>
<view class="meiyoul" v-else>
<image src="/static/img/meiyou.png"></image>
<view class="text"> 目前没有数据~ </view>
</view>
</scroll-view>
<view class="" style="height: 10rpx"> </view>
</view>
</uni-popup>
</template>

<style lang="less">
@import url('index.less');

.mask {  
    width: 444rpx;  
    max-height: 764rpx;  
    padding: 32rpx 0;  
    margin-left: auto;  
    margin-right: 28rpx;  
    background: #ffffff;  
    border-radius: 32rpx;  

    .masks {  
        max-height: 600rpx;  
    }  

    .titlessss {  
        padding: 0 28rpx;  
        height: 80rpx;  
        margin-bottom: 8rpx;  
        justify-content: space-between;  

        .left {  
            font-size: 32rpx;  
            color: #333333;  
        }  

        .closes {  
            width: 40rpx;  
            height: 40rpx;  
        }  
    }  

    .item {  
        padding: 0 28rpx;  
        height: 80rpx;  
        border-radius: 16rpx;  

        &.active {  
            background-color: #f7f7f7;  

            .name,  
            .book-name {  
                color: #f47309;  
            }  
        }  

        .bofang {  
            flex-shrink: 0;  
            width: 48rpx;  
            height: 48rpx;  
        }  

        .name {  
            flex-shrink: 0;  
            font-size: 28rpx;  
            color: #666666;  
            margin: 0 16rpx;  
        }  

        .book-name {  
            font-size: 28rpx;  
            color: #666666;  
        }  
    }  
}  

</style>
、、、

预期结果:

希望能正常

实际结果:

希望能每次切换url的时候 onUpdatetime函数的任务队列清空在开始

bug描述:

bug1: 测试音频地址https://cdnws.51tyty.com/ugc/audio/2024/8/11/3ed0ce340ed34bb48c11362123b78fff.mp3

当用seek跳转播放位置 比如 214.885秒 手机的214.885和平板的214.885所对应的语音不同 基本上seek跳转的会错开个2秒左右

bug2 onTimeUpdate函数有问题 比如我多次切换url地址 她的onTImeUpdate会一秒内多打印很多次 直到死机

原因是 onTimeupdate内部 没有监听暂停事件 这是第一个。第二个是onTImeUpdate必须要在切换url时候 先暂停 在切换 否则会增加多个队列 虽然打印的是最后一个url的播放时间
在正常情况下。ontimeUpdate一秒出发5次左右。但是当多次切换url后 会触发几十次 直到死机

2024-12-09 11:52 负责人:DCloud_UNI_OttoJi 分享
已邀请:
DCloud_UNI_OttoJi

DCloud_UNI_OttoJi - 日常回复 uni-app/x 问题,如果艾特我没看到,请主动私信

代码太长了,请删减代码,使用简单的 audio 是否可以复现?请提供可以直接运行的简单代码方便我测试和定位问题,提供更多信息,有助于定位和解答你的问题。

  • 1***@qq.com (作者)

    多次切换播放url就会导致 onTimeUpda打印频率增加 并且多次出发play事件也会

    2024-12-09 22:49

  • 1***@qq.com (作者)

    2024 12月10日 最新bug 在平板端 当调用seek播放指定的播放位置的声音和按照顺序的差2秒上下。手机端不会 比如一个10分钟的小说正常播放到214秒和调到214秒声音是不同的 在平板 你好

    2024-12-10 01:10

要回复问题请先登录注册