uni-app中实现音乐播放器

news2025/1/12 9:42:01

uni-app中实现音乐播放器

1、主要利用的是uni-app中提供的uni.createInnerAudioContext()来进行实现;

2、代码示例

(1)主页面代码展示

<template>
  <view class="music-layout">
    <view class="tn-flex">
      <view class="left-content">
        <view class="left-pic-layout">
          <img :src="bgUrl" :class="isPlay ? 'img-rotate' : ''">
          <view class="small-circle"></view>
        </view>
        <view class="like-layout">
          <text class="tn-icon-like-fill" v-if="musicDetail.liked" @click="onLikeMusic(false, musicDetail)"></text>
          <text class="tn-icon-like" v-else @click="onLikeMusic(true, musicDetail)"></text>
        </view>
      </view>
      <view class="right-content">
        <view class="song-name-layout">
          <view>{{ musicDetail.bsmb002 }}</view>
          <view v-if="isPlay"><PlayerAnimation></PlayerAnimation></view>
        </view>
        <view class="progress-layout">
          <text>{{ formatTime(musicCurrentTime) }}</text>
          <tn-slider
              :min="0"
              :max="musicTotalTime"
              class="progress"
              v-model="musicCurrentTime"
              inactiveColor="#EAEAEA"
              activeColor="#FF3370"
              :blockWidth="1"
              :lineHeight="4">
          </tn-slider>
          <text>{{formatTime(musicTotalTime)}}</text>
        </view>
        <view class="actions-layout">
          <view class="toggle-type-layout" @click="handleToggleType">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/loop-black-icon.png" v-if="toggleType == 1" >
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/single-black-icon.png" v-else-if="toggleType == 2">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/random-black-icon.png" v-else>
          </view>
          <view class="action-center">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/previous-icon.png" class="previous-icon" @click="handlePreviousPlay">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/play-icon.png" v-if="isPlay" class="player-icon" @click="handlePlay(false)">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/stop-icon.png" v-else class="player-icon" @click="handlePlay(true)">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/next-icon.png" class="next-icon" @click="handleNextPlay">
          </view>
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/music-list.png" class="music-list-icon" @click="handleMusicListShow">
        </view>
      </view>
    </view>
    <view class="add-music" @click="handleAddWisk">
      点这里添加您的音乐心愿单~
    </view>
  </view>
</template>

<script>

import { formatTime } from '@/utils/util'; // 代码在下方对应文件中
import PlayerAnimation from "../../../components/player-animation/player-animation.vue"; // 播放效果动画(代码在下方对应文件中)
import { musicList, saveCollect, cancleCollect } from "@/api/fetusMovement"; // 接口
import { mediaUrl } from '@/utils/env'; // 静态资源地址前缀

export default {
  components: {
    PlayerAnimation
  },
  data() {
    return {
      isPlay: false, // 是否播放
      toggleType: 1, // 播放顺序 (1:循环;2:单曲循环;3:随机)
      musicDetail : { }, // 音乐详情
      current: null, // 当前播放的是哪首
      currentSrc: '', // 当前音乐路径
      musicPlayCtx: null, // 音频上下文
      musicCurrentTime: 0, // 音乐当前播放进度
      musicTotalTime: 100, // 音乐总的时间
      musicList: [], // 音乐列表
      bgUrl: 'http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/tjyy_bg.png',
      timers: null,
      openId: ''
    }
  },
  watch: {
    currentSrc: {
      handler() {
        if(this.musicPlayCtx) {
          this.musicPlayCtx.destroy();
        }
        this.musicPlayCtx = uni.createInnerAudioContext();
        this.musicPlayCtx.obeyMuteSwitch = false;
        this.musicCurrentTime = 0;
        this.musicPlayCtx.src = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        this.musicTotalTime = this.musicDetail.bsmb009;
        if(this.isPlay){
          this.handleAudioPlay();
        }
      },
      immediate: true,
      deep: true,
    }
  },
  mounted() {
    this.openId = getApp().globalData.openId;
    this.getMusicList();
  },
  methods: {
    // 打开音乐列表
    getMusicList() {
      musicList(this.openId).then(res => {
        if (res.success) {
          this.musicList = res.result;
          this.current = 0;
          this.musicDetail = this.musicList[this.current];
          this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        }
      })
    },
    // 播放列表弹窗显示
    handleMusicListShow() {
      const { isPlay, toggleType, musicList, current} = this;
      this.$emit('handleMusicListShow', {
        bool: true,
        isPlay,
        toggleType,
        musicList,
        current
      });
    },
    formatTime,
    // 处理播放
    handlePlay(bool) {
      this.isPlay = bool;
      if(bool) {
        this.musicPlayCtx.seek(this.musicCurrentTime + 1);
        this.handleAudioPlay();
      } else {
        this.musicPlayCtx.stop();
      }
    },
    // 播放
    handleAudioPlay() {
      this.musicPlayCtx.play();
      if(this.timers) {
        clearTimeout(this.timers);
      }
      this.timers = setTimeout(() => {
        console.log(this.musicPlayCtx.paused);
      }, 200);
      // 播放完成
      this.musicPlayCtx.onEnded(() => {
        if(this.toggleType == 1) {
          this.handleNextPlay(); // 列表循环
        } else if(this.toggleType == 2) {
          this.musicPlayCtx.play(); // 单曲循环
        } else {
          this.current = Math.floor(Math.random() * this.musicList.length);
          this.musicDetail = this.musicList[this.current];
          this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        }
      })
      // 更新播放时间
      this.musicPlayCtx.onTimeUpdate(() => {
        this.onTimeUpdate();
      })
      // 播放出现错误
      this.musicPlayCtx.onError(() => {
        this.onError();
      })
    },
    // 下一首
    handleNextPlay() {
      this.isPlay = true;
      if(this.current < this.musicList.length - 1) {
        uni.showToast({
          title: '即将播放下一首',
          icon: 'none'
        })
        this.current ++;
        this.musicDetail = this.musicList[this.current];
        this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        return
      }
      uni.showToast({
        title: '已经为最后一首了',
        icon: 'none'
      })
    },
    // 上一首
    handlePreviousPlay() {
      this.isPlay = true;
      if(this.current) {
        this.current --;
        uni.showToast({
          title: '即将播放上一首',
          icon: 'none'
        })
        this.musicDetail = this.musicList[this.current];
        this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        return;
      }
      uni.showToast({
        title: '已经为第一首了',
        icon: 'none'
      })
    },
    // 播放类型
    handleToggleType(parmas) {
      if(parmas) {
        this.toggleType = parmas;
        const { isPlay, toggleType, musicList, current} = this;
        this.$emit('handleMusicListShow', {
          bool: true,
          isPlay,
          toggleType,
          musicList,
          current
        });
        return;
      }
      this.toggleType = this.toggleType == 1 ? 2 : this.toggleType == 2 ? 3 : 1;
    },
    // 切换音乐
    handleMusicChange(index) {
      this.isPlay = true;
      this.musicDetail = this.musicList[index];
      this.current = index;
      this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
      this.handleMusicListShow();
    },
    // 加载失败
    onError() {
      uni.showToast({
        title: '音频加载失败',
        icon: 'none'
      })
    },
    // 时间更新
    onTimeUpdate() {
      if (this.musicPlayCtx.currentTime > 0 && this.musicPlayCtx.currentTime <= 1) {
        this.musicCurrentTime = 1;
      } else if (this.musicCurrentTime !== Math.floor(this.musicPlayCtx.currentTime)) {
        this.musicCurrentTime = Math.floor(this.musicPlayCtx.currentTime);
      }
    },
    // 喜欢
    onLikeMusic(bool, item) {
      this.musicDetail.liked = bool;
      if (bool) {
        //收藏
        saveCollect({
          bsmId: item.id,
          openId: this.openId
        }).then(res => {
          if (res.success) {
            uni.showToast({
              title: '收藏成功',
              icon: 'none'
            })
            this.getMusicList()
          }
        })
      } else {
        //取消收藏
        cancleCollect({
          bsmId: item.id,
          openId: this.openId,
          id: item.collectId
        }).then(res => {
          if (res.success) {
            uni.showToast({
              title: '已取消收藏',
              icon: 'none'
            })
            this.getMusicList()
          }
        })
      }
    },
    // 心愿歌单
    handleAddWisk() {
      uni.navigateTo({
        url: '/toolsPages/fetusMovement/addWish'
      })
    }
  },
  // 销毁
  destroyed() {
    if(this.musicPlayCtx) this.musicPlayCtx.destroy();
    if(this.timers) clearTimeout(this.timers);
  }
}
</script>

<style scoped lang="scss">

.music-layout {
  position: relative;
  width: 690rpx;
  padding: 20rpx 30rpx;
  background: #FFFFFF;
  border-radius: 30rpx;
  backdrop-filter: blur(16px);
}

.left-content {
  width: 130rpx;
  .like-layout {
    margin-top: 20rpx;
    > text {
      color: #FF3370;
      font-size: 40rpx;
    }
  }
}

.left-pic-layout {
  position: relative;
  width: 100rpx;
  height: 100rpx;
  border-radius: 50%;
  overflow: hidden;
  img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
  }
  .small-circle{
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 20rpx;
    height: 20rpx;
    background-color: white;
    border-radius: 50%;
  }
}

.right-content {
  flex: 1;
  margin-left: 30rpx;
}

.song-name-layout {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 32rpx;
  color: #323A59;
  line-height: 40rpx;
  height: 40rpx;
  text {
    color: rgba(115, 121, 141, 1);
  }
}

.progress-layout {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 25rpx 0 0 2rpx;
  font-size: 26rpx;
  color: #73798D;
  line-height: 36rpx;
  .progress {
    display: flex;
    align-items: center;
    flex: 1;
    margin: 0 20rpx;
  }
}

.actions-layout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 25rpx 0 0 4rpx;
  .toggle-type-layout {
    > img {
      width: 30rpx;
      height: 26rpx;
    }
  }

  .action-center {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex: 1;
    margin: 0 86rpx;
  }

  .previous-icon, .next-icon {
    width: 30rpx;
    height: 32rpx;
  }

  .player-icon {
    width: 42rpx;
    height: 42rpx;
  }

  .music-list-icon {
    width: 30rpx;
    height: 30rpx;
  }
}

.img-rotate {
  transform-origin: center center;
  animation: rotate 5s infinite linear; /* 实现旋转动画效果 */
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.add-music {
  margin-top: 20rpx;
  text-align: center;
  font-size: 20rpx;
  color: #999999;
  text-decoration: underline #999999;
}
</style>

(2)utils中util.js文件代码

function fixedZero(val) {
    return val * 1 < 10 ? `0${val}` : val;
}

const formatTime = (time) =>  {
    const minutes = 60;
    const m = Math.floor(time / minutes);
    const s = Math.floor(time % 60);
    return `${fixedZero(m)}:${fixedZero(s)}`;
}

(3)components中player-animation文件夹player-animation.vue文件代码

<template>
    <view class="loading">
      <view class="item"></view>
      <view class="item"></view>
      <view class="item"></view>
      <view class="item"></view>
      <view class="item"></view>
    </view>
</template>

<script>
export default {
  name: "player-animation"
}
</script>

<style scoped>
/* 设置位置 */
.loading {
  height: 24rpx;
  display: flex;
  align-items: center;
}

.item {
  height: 24rpx;
  width: 2rpx;
  background: #FF3370;
  margin: 0 3rpx;
  border-radius: 10rpx;
  animation: loading 2s infinite;
}

/* 设置动画 */
@keyframes loading {
  0% {
    height: 0;
  }

  50% {
    height: 24rpx;
  }

  100% {
    height: 0;
  }
}

/* 为每一个竖条设置延时 */
.item:nth-child(2) {
  animation-delay: 0.2s;
}

.item:nth-child(3) {
  animation-delay: 0.4s;
}

.item:nth-child(4) {
  animation-delay: 0.6s;
}

.item:nth-child(5) {
  animation-delay: 0.8s;
}

</style>

(4)播放器列表弹窗代码

<template>
  <tn-popup v-model="show"
            safeAreaInsetBottom
            mode="bottom"
            height="1200rpx"
            @close="handleClose">
    <view class="music-container">
      <view class="header-layout">
        <view class="header-left">
          胎教音乐列表<text>({{ musicLst.length }}首)</text>
        </view>
        <view class="header-right" @click="() => handleToggle()">
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/loop-icon.png" v-if="toggleType == 1" >
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/single-icon.png" v-else-if="toggleType == 2">
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/random-icon.png" v-else>
          顺序播放
        </view>
      </view>
      <scroll-view scroll-y style="height: 1050rpx;">
        <view class="music-list">
          <view :class="['music-item', current  == index && isPlay ? 'active' : '']"
                v-for="(item, index) in musicLst"
                :key="index"
                @click="handleItemClick(index)">
            <view class="name">{{item.bsmb002}}</view>
            <PlayerAnimation v-if="current == index && isPlay"></PlayerAnimation>
          </view>
        </view>
      </scroll-view>
    </view>
  </tn-popup>

</template>

<script>
import PlayerAnimation from "../../../components/player-animation/player-animation.vue";
export default {
  props: {
    musicLst : {
      type: Array,
      default: []
    },
    current: {
      type: Number,
      default: 0
    },
    toggleType:{
      type:Number,
      default: 1
    },
    isPlay:{
      type:Boolean,
      default: false
    }
  },
  components: {
    PlayerAnimation
  },
  data() {
    return {
      show: false
    }
  },
  methods: {
    // 切换歌曲
    handleItemClick(index) {
      this.$emit('handleMusicChange', index);
    },
    // 关闭
    handleClose() {
      this.show = false;
    },
    // 播放类型切换
    handleToggle() {
      const playType = this.toggleType == 1 ? 2 : this.toggleType == 2 ? 3 : 1;
      this.$emit('handleToggleType', playType);
    },
  }
}
</script>

<style scoped lang="scss">
.music-container {
  padding: 0 30rpx 0;
  .header-layout {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 10rpx;
    height: 90rpx;
  }
  .header-left {
    display: flex;
    align-items: center;
    font-size: 32rpx;
    font-weight: 500;
    color: #333333;
    line-height: 44rpx;
    text {
      font-size: 24rpx;
      font-weight: 400;
      color: #666666;
      line-height: 34rpx;
    }
  }
  .header-right {
    display: flex;
    align-items: center;
    height: 56rpx;
    background: linear-gradient(135deg, #FF74A2 0%, #FF3370 100%);
    border-radius: 28rpx;
    padding: 0 12rpx;
    font-size: 26rpx;
    color: white;
    img {
      margin-right: 10rpx;
      width: 26rpx;
      height: 26rpx;
    }
  }
}

.music-list {
  font-size: 28rpx;
  color: #333333;
  line-height: 40rpx;

  .music-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20rpx 0;
    font-size: 28rpx;
    color: #333333;
    line-height: 40rpx;
  }
}

.active {
  color: #FF3370;
}

</style>

3、实现也面向效果展示

(1)播放器
在这里插入图片描述
(2)播放器弹窗
在这里插入图片描述
4、实现该功能过程所遇到的问题总结

(1)当一首歌曲播完之后,进度条不更新问题,在网上查看到的方法都是说:该问题是存在的一个bug,解决的方案是我们再代码中要主动的调用paused()方法

this.timers = setTimeout(() => {
    console.log(this.musicPlayCtx.paused);
}, 200);

(2)当点击暂停播放后,音乐从头播放的问题,解决方案:利用seek()方法使其跳转到指定位置

 this.musicPlayCtx.seek(this.musicCurrentTime + 1);

(3)音乐播放器的地址,含有中文名称,在模拟器上面可以正常播放,手机上面不可以,解决方案:需要将该地址进行编码,编译成编译器可以识别地址

this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);

5、以上代码可以直接粘贴复制到项目即可使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1374711.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nvm管理多版本Node.js

nvm管理多版本Node.js 可能大家都曾苦恼于Node环境问题&#xff0c;某个项目需要升版本&#xff0c;某项目又需要降&#xff0c;甚至还出现npm版本与Node对不上的情况。 通过nvm进行版本管理&#xff0c;即可解决。 卸载Node 通过命令行输入node -v命令查看是否已安装Node&…

Realm Management Extension领域管理扩展之颗粒保护检查

本节描述了RME引入的颗粒保护检查。颗粒保护检查使得能够在不同的物理地址空间之间动态分配内存区域。 本节将向您介绍以下功能: 颗粒保护表的结构用于颗粒保护检查的故障报告区域在物理地址空间之间的过渡正如在物理地址一节中所述,RME提供了四个物理地址空间。以下图表显示…

金额用Long还是BigDecimal?

问题 今天在网上看到一个有意思的问题&#xff0c;金额的数据类型用Long还是BigDecimal&#xff1f; 具体问题大概是这样的&#xff1a;关于金额的数据类型&#xff0c;组长认为使用BigDecimal比较稳妥&#xff0c;总监认为使用Long才不会出问题&#xff0c;然后开发认为Long…

85.乐理基础-记号篇-速度记号

内容来源于&#xff1a;三分钟音乐社 上一个内容&#xff1a;85.乐理基础-记号篇-力度记号-CSDN博客 速度记号在下方两个里面已经写过一部分了&#xff0c;这些标记总体上是属于 不变速度 的标记&#xff0c;比如一首乐谱就记了 每分钟60拍&#xff0c;那整首速度就都是不变的…

软件测试|如何在Linux中下载和安装软件包

简介 在Linux操作系统中&#xff0c;下载和安装软件包是一项基本任务。不同的Linux发行版可能有不同的包管理工具和方式&#xff0c;但总体流程是类似的。以下是在Linux中下载和安装软件包的详细步骤。 步骤1&#xff1a;选择适当的包管理工具 因为Linux有不同的发行版本&am…

【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer

【Kafka-3.x-教程】专栏&#xff1a; 【Kafka-3.x-教程】-【一】Kafka 概述、Kafka 快速入门 【Kafka-3.x-教程】-【二】Kafka-生产者-Producer 【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft 【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer 【Kafka-3.x-教程】-【五…

JDBC初体验(二)——增、删、改、查

本课目标 理解SQL注入的概念 掌握 PreparedStatement 接口的使用 熟练使用JDBC完成数据库的增、删、改、查操作 SQL注入 注入原理&#xff1a;利用现有应用程序&#xff0c;将&#xff08;恶意的&#xff09;SQL命令注入到后台数据库引擎执行能力&#xff0c;它可以通过在…

芯片命名大全:完整的器件型号包括主体型号、前缀、后缀等!

不少公司的采购会发现&#xff0c;拿到工程师提供的BOM中的器件去采购物料时&#xff0c;经常供应商还会问得更仔细&#xff0c;否则就不知道供给你哪种物料&#xff0c;严重时&#xff0c;采购回来的物料用不了。为什么会有这种情况呢&#xff1f;问题就在于&#xff0c;很多经…

PFA撞击滤尘器-PFA冲击瓶-PFA缓冲瓶

还在用玻璃材质冲击瓶吗&#xff1f;一碰就会碎的辛酸谁能理解啊&#xff1f;还会被各种酸气腐蚀&#xff0c;怎办&#xff1f; 进口氟树脂材质PFA冲击瓶&#xff0c;值得拥有。 与玻璃撞击器不同&#xff0c;PFA冲击瓶坚固&#xff0c;不易损坏&#xff0c;并且由于PFA材质本…

自动驾驶状态观测1-坡度估计

背景 自动驾驶坡度对纵向的跟踪精度和体感都有一定程度的影响。行车场景虽然一般搭载了GPS和IMU设备&#xff0c;但pitch角一般不准&#xff0c;加速度也存在波动大的特点。泊车场景一般在室内地库&#xff0c;受GPS信号遮挡影响&#xff0c;一般无法获取高程和坡度。搭载昂贵…

vue前端开发自学demo-input标签数据双向绑定

vue前端开发自学demo-input标签数据双向绑定&#xff01;今天为大家 展示的内容是&#xff0c;前端开发常见的&#xff0c;form表单里面的&#xff0c;一些输入数据的元素&#xff0c;动态绑定数据的案例。比如input,以及checkbox的状态绑定案例。 首先&#xff0c;老规矩&…

别不信,搭建企业知识库后真的效率翻倍了

在当今信息时代&#xff0c;知识是最宝贵的财富。一个企业要想越办越大&#xff0c;就需要保证信息的透明度和流通率。而搭建一套企业知识库&#xff0c;就能实现这个目标。今天我们就来聊聊为什么建立企业知识库后&#xff0c;你的工作效率会大大提高。同时&#xff0c;我们会…

C/C++ 有关质数(素数)的问题

第一题:判断是否为质数 代码&#xff1a; #include <bits/stdc.h> using namespace std; int main() {int a;int flag 1;cin>>a;for(int j2;j<a;j){if(a % j 0){cout<<a<<"不是质数";flag0;break;}}if(flag1) cout<<a<<&quo…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-3(2) 刚体的位形 Configuration of Rigid Body

本文仅供学习使用&#xff0c;总结很多本现有讲述运动学或动力学书籍后的总结&#xff0c;从矢量的角度进行分析&#xff0c;方法比较传统&#xff0c;但更易理解&#xff0c;并且现有的看似抽象方法&#xff0c;两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…

Open100: 开源系统杰出成果

了解更多&#xff1a;芝士AI吃鱼 背景 开源的根源可以追溯到计算机的早期&#xff0c;并在20世纪末发展迅猛。贝尔实验室在20世纪70年代开发的AT&T Unix是开源的关键里程碑&#xff0c;其共享源代码的概念为开源运动奠定了基础。开源已重溯软硬件产业生态&#xff0c;并正…

C++ 之LeetCode刷题记录(八)

&#x1f604;&#x1f60a;&#x1f606;&#x1f603;&#x1f604;&#x1f60a;&#x1f606;&#x1f603; 开始cpp刷题之旅&#xff0c;多学多练&#xff0c;尽力而为。 先易后难&#xff0c;先刷简单的。 35. 搜索插入位置 给定一个排序数组和一个目标值&#xff0c;…

数字图像处理练习题

数字图像处理练习题 文章目录 数字图像处理练习题第 一 章1.什么是数字图像?2.数字图像有哪些特点?3.数字图像处理的目的是什么?4.简述数字图像的历史。5.数字图像有哪些主要应用?6.列举生活中数字图像的获得途径。7.结合自己的生活实例,举出一个数字图像的应用实例8.数字图…

【SSO】统一授权中心v1.0.0版本正式上线(多租户)

目录 背景 体验 技术栈 菜单 示例 背景 为了方便权限管理、用户登录授权、应用授权等&#xff0c;特地开发了当前的统一授权中心。 体验 邮箱注册即可登录体验 后台系统&#xff1a;https://sso.behappyto.cn/#/switch 技术栈 vue3tsspringbootmybatismysql 菜单 …

Qt框架学习 --- CTK

系列文章目录 文章目录 系列文章目录前言一、准备阶段二、使用介绍1.核心思想2.源码2.1.框架部分资源目录树2.2.框架部分源码2.3.插件部分资源目录树2.4.插件部分源码 3.文件结构4.运行效果 总结 前言 随着开发的深入&#xff0c;CTK框架还是要关注一下。了解CTK还是有必要的。…

Aurora中显示中文

Aurora是可以在word里面作为插件使用&#xff0c;可以画一些三线表&#xff0c;是一款非常好用的工具&#xff0c;写论文必备。 我们可以通过现在excel里面创建表格&#xff0c;然后将excel转成latex格式&#xff0c;具体做法参考如下&#xff1a; Aurora Equation——Latex表…