当前位置: 首页 > news >正文

vue3+ts封装类似于微信消息的组件

组件代码如下:

<template><div:class="['voice-message', { sent: isSent, received: !isSent }]":style="{ backgroundColor: backgroundColor }"@click="togglePlayback"><!-- isSent为false在左侧,为true在右侧--><!-- 语言条要按照语音时长显示不同的宽度,所以增加了一块宽度,发送者的时候,加在左侧,接收者的时候,加在右侧--><div v-if="isSent" :style="`width:${(duration / 10) * 30}px`"></div><span class="duration" v-if="isSent">{{ duration }}''&nbsp;</span><div :class="['voice-icon', { 'sent-icon': isSent }]"><div :class="['small']" :style="smallStyle"></div><div :class="['middle', { animate: isPlaying }]" :style="middleStyle"></div><div :class="['large', { animate: isPlaying }]" :style="largeStyle"></div></div><span class="duration" :style="{ color: iconColor }" v-if="!isSent">{{ duration }}&nbsp;''</span><div v-if="!isSent" :style="`width:${(duration / 10) * 30}px`"></div></div>
</template><script setup lang="ts">
import { ref, computed, withDefaults, onBeforeUnmount } from "vue";// 使用 withDefaults 提供默认值
const props = withDefaults(defineProps<{isSent?: boolean;iconColor?: string;backgroundColor?: string;smallSize?: number;middleSize?: number;largeSize?: number;duration?: number;audioSrc?: string;}>(),{isSent: false,iconColor: "#000000",backgroundColor: "",smallSize: 10,middleSize: 20,largeSize: 30,duration: 0,audioSrc: ""}
);const isPlaying = ref(false);
let audio: HTMLAudioElement | null = null;// 计算动态样式
const smallStyle = computed(() => ({color: props.iconColor,width: `${props.smallSize}px`,height: `${props.smallSize}px`,marginRight: -props.smallSize + "px"
}));const middleStyle = computed(() => ({color: props.iconColor,width: `${props.middleSize}px`,height: `${props.middleSize}px`,marginRight: -props.middleSize + "px"
}));const largeStyle = computed(() => ({color: props.iconColor,width: `${props.largeSize}px`,height: `${props.largeSize}px`,marginRight: "1px"
}));// 切换播放状态的函数
const togglePlayback = () => {if (isPlaying.value) {pauseVoice();} else {playVoice(props.audioSrc || "");}
};// 播放音频的函数
const playVoice = (voiceSrc: string) => {if (!voiceSrc) {console.error("音频源不能为空");return;}// 如果音频上下文不存在,则创建新的 HTMLAudioElementif (!audio) {audio = new Audio(voiceSrc);} else {audio.src = voiceSrc;}isPlaying.value = true;// 播放音频audio.play().catch(error => console.error("音频播放失败", error));// 监听播放结束事件audio.onended = () => {isPlaying.value = false;};
};// 暂停音频的函数
const pauseVoice = () => {isPlaying.value = false;if (audio) {audio.pause();}
};// 组件卸载时销毁音频上下文
onBeforeUnmount(() => {if (audio) {audio.pause();audio = null;}
});defineExpose({pauseVoice
});
</script><style scoped>
.voice-message {display: inline-flex;align-items: center;cursor: pointer;border-radius: 10px;padding: 4px 12px;
}.voice-message.sent {justify-content: flex-end;
}.voice-message.received {justify-content: flex-start;
}.voice-icon {display: flex;align-items: center;
}.voice-icon.sent-icon {transform: rotate(180deg);
}.small,
.middle,
.large {border-style: solid;border-top-color: transparent;border-left-color: transparent;border-bottom-color: transparent;border-radius: 50%;box-sizing: border-box;vertical-align: middle;display: inline-block;background-color: transparent; /* 默认背景颜色为透明 */
}.middle.animate {animation: show2 3s ease-in-out infinite;
}.large.animate {animation: show3 3s ease-in-out infinite;
}@keyframes show2 {0% {opacity: 0;}30% {opacity: 1;}100% {opacity: 0;}
}@keyframes show3 {0% {opacity: 0;}60% {opacity: 1;}100% {opacity: 0;}
}.duration {margin-left: 8px;font-size: 20px;color: #ffffff;font-weight: 400;
}
</style>

使用时:

<VoicePlayback:isSent="false"iconColor="#ffffff"backgroundColor="rgba(255 255 255 / 20%)":smallSize="5":middleSize="16":largeSize="28":duration="30"audioSrc="http://music.163.com/song/media/outer/url?id=447925558.mp3"
/>

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • @Transactional 参数详解
  • OpenGL/GLUT实践:实现反弹运动的三角形动画与键盘控制(电子科技大学信软图形与动画Ⅱ实验)
  • 数据分析——基础
  • cowrie部署中遇到的坑
  • sqlite3 相关知识
  • 【佳学基因检测】在bagisto中,grouped products(同组产品)和bundled products(打包产品)有什么不同?
  • Nvidia GPU benchmark压力测试工具
  • 003: Visual Studio 配置 VTK 开发环境的方法与比较
  • Qt工程实践_06_Qt MSVC2O17编译器下的程序添加VS2017生成的动态链接库方法
  • Windows用户取消共享文件夹密码方法(Method for Windows Users to Cancel Shared Folder Password)
  • 科研绘图系列:R语言柱状图分布(histogram plot)
  • Mybatis【分页插件,缓存,一级缓存,二级缓存,常见缓存面试题】
  • 重头开始嵌入式第三十四天(数据库二)
  • html备忘录
  • IDEA 2024最新软件下载
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 08.Android之View事件问题
  • CentOS7 安装JDK
  • css选择器
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • Vue官网教程学习过程中值得记录的一些事情
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 动态魔术使用DBMS_SQL
  • 服务器之间,相同帐号,实现免密钥登录
  • ------- 计算机网络基础
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 理解在java “”i=i++;”所发生的事情
  • 七牛云假注销小指南
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 线上 python http server profile 实践
  • 学习笔记TF060:图像语音结合,看图说话
  • 用Visual Studio开发以太坊智能合约
  • HanLP分词命名实体提取详解
  • puppet连载22:define用法
  • ​Python 3 新特性:类型注解
  • ​secrets --- 生成管理密码的安全随机数​
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • (160)时序收敛--->(10)时序收敛十
  • (3)STL算法之搜索
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第6节 (嵌套的Finally代码块)
  • (ibm)Java 语言的 XPath API
  • (六)激光线扫描-三维重建
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (一)Dubbo快速入门、介绍、使用
  • (转)EOS中账户、钱包和密钥的关系
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .net 4.0发布后不能正常显示图片问题
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET Micro Framework初体验
  • .NET Reactor简单使用教程
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NetCore部署微服务(二)
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?