本文最后更新于 2024-04-04,文章内容可能已经过时。

UI

自己开发,就不画UI图了,主要风格是插画类型的风格,目前已经定版

1711720622173.png

1711720622065.png

前端

☁️ 支持零配置部署 Netlify已配置

UI 框架

Icons

插件

编码风格

开发工具

开发进程

添加音频,

这里主要功能是点击图片切换布洛妮娅的语言,考虑到以后这里可以会做音乐人模块,所以这里用了@ended

 // 点击图片切换          
 <img @click="switchAudio" class="w-md absolute -top-[3rem] -left-[10rem]"
                src="https://haloss.oss-cn-hangzhou.aliyuncs.com/blog/2019110617141939459.png" alt="">
 <audio ref="audioRef" :src="audioSrc" @ended="onAudioEnded"></audio>

import { reactive, ref, onMounted } from "vue";
const audioRef = ref<HTMLAudioElement | null>(null);
const audioSrc = ref<string>('');
const audioFiles = ['https://haloss.oss-cn-hangzhou.aliyuncs.com/MP3/Voice/1.MP3',
    'https://haloss.oss-cn-hangzhou.aliyuncs.com/MP3/Voice/2.MP3',
    'https://haloss.oss-cn-hangzhou.aliyuncs.com/MP3/Voice/3.MP3',
    'https://haloss.oss-cn-hangzhou.aliyuncs.com/MP3/Voice/4.MP3',
    'https://haloss.oss-cn-hangzhou.aliyuncs.com/MP3/Voice/5.MP3'];
let currentIndex = 0;

// 初始化音频源
onMounted(() => {
    loadAudio(currentIndex);
});
// 加载并播放音频
function loadAudio(index: number) {
    if (audioRef.value) {
        audioRef.value.src = audioFiles[index];
        audioRef.value.load();
        audioRef.value.play();
    }
}
// 切换音频
function switchAudio() {
    currentIndex = (currentIndex + 1) % audioFiles.length;
    loadAudio(currentIndex);
}
// 音频播放结束时调用
function onAudioEnded() {
    // switchAudio(); // 如果音频播放结束,则自动切换到下一个音频
}

在这个例子中,我们定义了一个audioFiles数组,其中包含了所有音频文件的路径。currentIndex变量用于跟踪当前播放的音频文件的索引。在onMounted生命周期钩子中,我们调用loadAudio函数来加载并播放第一个音频文件。

switchAudio函数用于切换音频文件。它首先更新currentIndex的值,然后调用loadAudio来加载并播放新的音频文件。

onAudioEnded函数是一个事件处理器,它在音频播放结束时被调用。在这个例子中,它简单地调用switchAudio来自动切换到下一个音频文件。如果你不希望音频自动切换,你可以移除这个函数调用。

书单推荐

<div class="book">
    <img src="https://www.jq22.com/tp/6372846985525987219804667.png" alt="the cast of Schitt’s Creek" />
 </div>

.book {
  width: 18.5em;
  height: 23.0991em;
  margin-top: -4.4em;
  position: relative;
  -webkit-transform: perspective(60em) rotateX(58deg) rotateZ(-34deg) skewY(-7deg);
          transform: perspective(60em) rotateX(58deg) rotateZ(-34deg) skewY(-7deg);
  box-shadow: -1.4em 1.7em 0.3em -0.3em rgba(0,0,0,0.8), -1.6em 1.8em 0.9em -0.2em rgba(0,0,0,0.5), 0.3em 1.9em 1.3em rgba(0,0,0,0.3);
  border-top-right-radius: 0.4em;
}
.book img {
  border-top-right-radius: 0.4em;
  box-sizing: border-box;
  width: 100%;
  clip: rect(0em, 18.5em, 23.1em, 0em);
  display: block;
  position: absolute;
  -webkit-filter: saturate(90%);
          filter: saturate(90%);
}
.book:before,
.book:after {
  content: '';
  position: absolute;
  top: 0;
}
.book:before {
  width: 105%;
  height: 105%;
  left: -5%;
  z-index: -1;
  background-repeat: no-repeat;
  background-image: linear-gradient(115deg, transparent 2.8%, #3f3f3f 3%, #3f3f3f 16%, transparent 16%), linear-gradient(125deg, transparent 10%, #3f3f3f 10%, #3f3f3f 17%, #222 46.8%, transparent 47%), linear-gradient(125deg, transparent 46%, rgba(0,0,0,0.5) 46.5%, rgba(0,0,0,0.25) 49%, transparent 53%), linear-gradient(to right, #444, #666), linear-gradient(#444, #444), linear-gradient(140deg, transparent 45%, #eee 45%, #ccc 96.8%, rgba(170,170,170,0) 97%);
  background-size: 100% 100%, 100% 100%, 100% 100%, 100% 0.4em, 94% 0.2em, 100% 100%;
  background-position: 0 0, 0 0, 0 0, 0 95.8%, 0 100%, 0 0;
}
.book:after {
  width: 100%;
  height: 100%;
  background-repeat: no-repeat;
  background-image: linear-gradient(to right, transparent 2%, rgba(0,0,0,0.1) 3%, rgba(0,0,0,0.1) 4%, transparent 5%), linear-gradient(-50deg, rgba(0,0,0,0.1) 20%, transparent 100%), linear-gradient(-50deg, rgba(0,0,0,0.2) 20%, transparent 100%), linear-gradient(to bottom, rgba(0,0,0,0.1) 20%, transparent 100%), linear-gradient(to bottom, rgba(0,0,0,0.1) 20%, transparent 100%);
  background-size: 100% 100%, 2% 20%, 1% 20%, 2% 20%, 1% 20%;
  background-position: 0 0, 2.2% 100%, 3% 100%, 2.2% 0, 3% 0;

}

添加主题模块

后端