背景
今天周日,本来应该是在家躺着的日子却被迫过来调休,想必各位大佬已经踏上了回家的列车吧,那么小弟在这里提前祝福各位新年快乐!
由于春节将至也确实没有想写业务的打算(boring)于是乎我就来掘金摸鱼,正巧看到了一篇文章😈当一个摆子前端太闲的时候会做什么 - 掘金 (juejin.cn),这位大佬实现了一个桌面小精灵,我突然想起了我小时候充不起的超能NoNo,文章和我逝去的童年一拍即合于是乎我的超能NoNo--Momo诞生了。
作为一名优秀的切图仔,我肯定不能直接搬运(炒)前辈的代码,而且前辈的代码跟我想法不一样,主要是我觉得吧他的大眼虽然很炫但不够萌萌哒,只能自己去画咯。
以下是Momo的简单介绍:
- 名称: Momo
- 性别: 不详
- 情绪: 默认/生气
- 状态: Loading/working
- 自述: 大家好我是Momo,诞生于2024年,我是一名智能桌面助手哦。
Momo生活照
代码
画页面
先画萌萌的外表
搞一个圆滚滚的身体
<style>
*{
padding: 0;
margin: 0;
}
body{
background-color: #000;
display: flex;
height: 100vh;
overflow: hidden;
}
.Momo{
border-radius: 50%;
width: 150px;
height: 150px;
margin: auto;
background-color: #cbe8d7;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
</style>
<main class="Momo">
</main>
效果:
ps: 这啥呀太丑了,
画个脸再加个眼睛呢?
老实讲,画脸这步还真难到我了,因为这种不太规则的椭圆确实不太好弄, 我记得border-radius可以实现这种效果,我还记得有个网站可以可视化拖动 Fancy Border Radius Generator (9elements.github.io)
于是乎...有了下面一行代码, border-radius: 55% 45% 77% 23% / 54% 22% 78% 46% ; 好了小脸蛋有着落了下一步画上去再加个眼睛再加一点细节,请看VCR
<style>
.face{
position: absolute;
width: 100px;
height: 100px;
background-color: #000;
transform: rotate(45deg);
margin-top: -10px;
/* border-radius: 58% 42% 81% 19% / 54% 20% 80% 46%; */
border-radius: 55% 45% 77% 23% / 54% 22% 78% 46% ;
border:7px solid #1e80e260;
}
.inner{
transform: rotate(-45deg);
position: absolute;
width: 100px;
height: 100px;
}
.leftEye,.rightEye{
width: 10px;
border-top: 0px solid #000;
border-bottom: 0px solid #000;
background-color: #02feff;
height: 26px;
box-sizing: border-box;
/* background-color: #02feff; */
position: absolute;
top: 37%;
}
.leftEye{
left: 20%;
}
.rightEye{
left: 70%;
}
</style
<main class="Momo">
<div class="face">
<div class="inner">
<div class="leftEye zy"></div>
<div class="rightEye zy"></div>
</div>
</div>
</main>
效果:
你再看再看?再看我就把你喝掉!!!
解释一下,这里由于画的椭圆是45度的后续有的眼睛需要定位一下,flex也行但是想到后面可能要加东西我就没用flex,但是定位是根据旋转后的进行定位的不太方便,于是乎我加了一个inner 反向旋转负负得正...
萌萌的小耳朵我来咯
耳朵就更难画了呜呜呜,
为什么我说难画,难就难在这里白色的身体是个圆弧状还要把这个耳朵包起来,太难了...由于小弟没有美工,svg也不太熟没办法了上clip-path
<style>
.face{
position: absolute;
width: 100px;
height: 100px;
background-color: #000;
transform: rotate(45deg);
margin-top: -10px;
/* border-radius: 58% 42% 81% 19% / 54% 20% 80% 46%; */
border-radius: 55% 45% 77% 23% / 54% 22% 78% 46% ;
border:7px solid #1e80e260;
}
.inner{
transform: rotate(-45deg);
position: absolute;
width: 100px;
height: 100px;
}
.leftEye,.rightEye{
width: 10px;
border-top: 0px solid #000;
border-bottom: 0px solid #000;
background-color: #02feff;
height: 26px;
box-sizing: border-box;
/* background-color: #02feff; */
position: absolute;
top: 37%;
}
.leftEye{
left: 20%;
}
.rightEye{
left: 70%;
}
.lefEar{
position: absolute;
height: 75px;
width: 30px;
background-color: #02feff;
left: 0;
top: 0;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
/* border-radius: 170% 170% 5% 5%; */
transform: rotate(-35deg);
top: -60px;
left: -25px;
}
.lefEar::after{
content: '';
display: inline-block;
width: 40px;
height: 50px;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
background-color: #cbe8d7;
position: absolute;
transform: rotate(180deg);
bottom: -25px;
left: -5px;
clip-path: polygon(
28% 0,
35% 10%,
70% 0,
90% 40%,
100% 50%,
90% 85%,
90% 90%,
83% 100%,
50% 50%,
20% 100%,
0 43%);
}
.rigEar{
position: absolute;
height: 75px;
width: 30px;
background-color: #02feff;
left: 0;
top: 0;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
/* border-radius: 170% 170% 5% 5%; */
transform: rotate(35deg);
top: -60px;
left: 140px;
}
.rigEar::after{
content: '';
display: inline-block;
width: 40px;
height: 50px;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
background-color: #cbe8d7;
position: absolute;
transform: rotate(180deg);
bottom: -25px;
left: -5px;
clip-path: polygon(
28% 0,
35% 10%,
70% 0,
90% 40%,
100% 50%,
90% 85%,
90% 90%,
83% 100%,
50% 50%,
20% 100%,
0 43%);
}
</style
<main class="Momo">
<div class="face">
<div class="inner">
<div class="leftEye zy"></div>
<div class="rightEye zy"></div>
</div>
</div>
<div class="lefEar"></div>
<div class="rigEar"></div>
</main>
效果
很明显看到这里耳朵不够丝滑,不过效果有了,后面再慢慢调整便是,没啥子问题先做后面的功能 ps: 真的很萌!!!
要用类和css变量吗?
想着,这里精灵的大小不能固定写死就150px了,我得做大做强再创辉煌,于是先后改成了计算大小和类,情况VCR
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<style>
body{
background-color: #000;
display: flex;
height: 100vh;
overflow: hidden;
--blinkTime:1s;
transform-style: preserve-3d;
}
.ToyarMomo{
border-radius: 50%;
width: var(--size);
height: var(--size);
margin: auto;
background-color: var(--mainColor);
position: relative;
display: flex;
align-items: center;
justify-content: center;
transition: all .5s;
}
.ToyarMomo.ball{
overflow: hidden;
}
.Momo-left_Ear{
position: absolute;
height: calc(var(--size)/2);
width: calc(var(--size)/5);
background-color: var(--secondColor);
left: 0;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
/* border-radius: 170% 170% 5% 5%; */
transform: rotate(-35deg);
transform-origin: bottom;
top: calc(var(--size) * -2.8/7);
}
.Momo-left_Ear::after{
content: '';
display: inline-block;
width: calc(var(--size) * 0.27);
height: calc(var(--size) * 1/3);
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
background-color: var(--mainColor);
position: absolute;
transform: rotate(180deg);
bottom: calc(var(--size) * -1/6);
left: -15%;
clip-path: polygon(36% 0, 80% -5%, 93% 0,
95% 48%, 97% 68%, 94% 83%, 93% 86%,
90% 92%,
88% 95%, 91% 90%, 87% 95%, 81% 98%, 79% 98%, 78% 93%, 77% 88%, 76% 83%, 73% 76%, 70% 71%, 67% 66%, 56% 50%,
56% 49%, 39% 70%, 34% 81%, 30% 96%, 27% 100%, 19% 94%, 16% 91%,
11% 78%, 9% 73%, 5% 49%, 0 30%);
}
.Momo-right_Ear{
position: absolute;
height: calc(var(--size)/2);
width: calc(var(--size)/5);
left: 0;
top: 0;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
/* border-radius: 170% 170% 5% 5%; */
transform: rotate(35deg);
top: calc(var(--size) * -2.8/7);
left: calc(var(--size) * 0.81);
transform-origin: bottom;
background-color: var(--secondColor);
z-index: -1;
}
.Momo-right_Ear::after{
content: '';
display: inline-block;
width: calc(var(--size) * 0.27);
height: calc(var(--size) * 1/3);
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
background-color: var(--mainColor);
position: absolute;
transform: rotate(180deg);
bottom: calc(var(--size) * -1/6);
left: -15%;
/* clip-path: polygon(
28% 0,
35% 10%,
70% 0,
90% 40%,
100% 50%,
90% 85%,
90% 90%,
83% 100%,
50% 50%,
20% 100%,
0 43%); */
clip-path: polygon(36% 0, 80% -5%, 93% 0,
95% 48%, 97% 68%, 94% 83%, 93% 86%,
90% 92%,
88% 95%, 91% 90%, 87% 95%, 81% 98%, 79% 98%, 78% 93%, 77% 88%, 76% 83%, 73% 76%, 70% 71%, 67% 66%, 56% 50%,
56% 49%, 39% 70%, 34% 81%, 30% 96%, 27% 100%, 19% 94%, 16% 91%,
11% 78%, 9% 73%, 5% 49%, 0 30%);
}
.MomoBody{
position: absolute;
width: calc( var(--size) * 2/3);
height: calc( var(--size) * 2/3);
background-color: #000;
transform: rotate(45deg);
margin-top: -10px;
/* border-radius: 58% 42% 81% 19% / 54% 20% 80% 46%; */
border-radius: 55% 45% 77% 23% / 54% 22% 78% 46% ;
border:calc(var(--size) * 0.045 ) solid #2f6ead5e;
z-index: 15;
}
.inner{
transform: rotate(-45deg);
position: absolute;
width: calc( var(--size) * 2/3);
height: calc( var(--size) * 2/3);
overflow: hidden
}
.Momo-left_Eye,.Momo-right_Eye{
width: calc(var(--size) * 1.5/15);
border: 0px solid #000;
border-top: 0px solid #000;
border-bottom: 0px solid #000;
background-color: var(--secondColor);
height: calc( var(--size) * 12/75);
box-sizing: border-box;
position: absolute;
top: 37%;
}
.Momo-left_Eye{
left: 20%;
}
.Momo-right_Eye{
left: 70%;
}
.momo-blink{
animation: blink var(--blinkTime) linear;
}
.momo-leftRotate{
animation: lRotate var(--blinkTime) linear;
}
.momo-rightRotate{
animation: rRotate var(--blinkTime) linear;
}
/* .leftVg{
border: 3px solid #000;
width: 50px;
height: 50px;
position: absolute;
left: 0;
bottom: 0;
border-radius: 30% 0 30% 0;
}
.rightVg{
border: 3px solid #000;
width: 50px;
height: 50px;
position: absolute;
right: 0;
bottom: 0;
border-radius: 0 30% 0 30% ;
} */
</style>
<script>
class ToyarMomo {
constructor(size,{
mainColor='#cbe8d7',
secondColor='#02feff',
}) {
this.size=size
this.mainColor = mainColor
this.secondColor = secondColor
this.init()
}
init() {
this.appendStyles()
this.createMomo()
}
createLeftEar(){
const leftEar = document.createElement('div')
leftEar.className = 'Momo-left_Ear ear-light'
this.leftEar =leftEar
return leftEar
}
createRightEar(){
const rightEar = document.createElement('div')
rightEar.className = 'Momo-right_Ear ear-light'
this.rightEar =rightEar
return rightEar
}
createLeftEye(){
const leftEye = document.createElement('div');
leftEye.className ='Momo-left_Eye'
this.leftEye = leftEye
return leftEye
}
createRightEye(){
const rightEye = document.createElement('div');
rightEye.className ='Momo-right_Eye'
this.rightEye = rightEye
return rightEye
}
createInner(){
const inner = document.createElement('div');
inner.className='inner'
this.inner = inner
const leftEye = this.createLeftEye()
const rightEye = this.createRightEye()
inner.append(leftEye)
inner.append(rightEye)
return inner
}
createBody(){
const body = document.createElement('div');
body.className = 'MomoBody'
this.body = body
const inner =this.createInner()
body.append(inner)
return body
}
createMomo() {
let main = document.createElement('main');
main.id='Momo'
main.className = 'ToyarMomo'
main.style.setProperty('--size',this.size+'px')
main.style.setProperty('--mainColor',this.mainColor)
main.style.setProperty('--secondColor',this.secondColor)
this.main = main
const body= this.createBody()
const leftEar= this.createLeftEar()
const rightEar= this.createRightEar()
main.append(body)
main.append(leftEar)
main.append(rightEar)
const open =document.createElement('div')
open.className='open'
main.append(open)
const leftVg =document.createElement('div')
leftVg.className='leftVg'
main.append(leftVg)
const rightVg =document.createElement('div')
rightVg.className='rightVg'
main.append(rightVg)
const dialog =document.createElement('div')
dialog.className='dialog'
this.dialog =dialog
main.append(dialog)
document.body.append(main)
this.loading()
}
appendStyles() {
let staticStyle = `
`
let style = document.createElement('style')
style.innerText = staticStyle
document.body.appendChild(style)
}
}
let momo = new ToyarMomo(150,{
// mainColor:'#cbe8d7',
// secondColor:'#02feff',
// mainColor:'red',
// secondColor:'blue'
})
</script>
</body>
</html>
于是乎,我的代码变成了类和计算(真费时间啊...),类接受一个size大小属性,一个option 传递一些配置项,好啦终于可以实现功能了
实现动效
先来一个萌萌哒的眨眼吧
<style>
@keyframes blink{
0%{
border-top: 0px solid #000;
border-bottom: 0px solid #000;
}
50%{
border-top: calc(var(--size) * 12/150) solid #000;
border-bottom: calc(var(--size) * 12/150) solid #000;
}
100%{
border-top: 0px solid #000;
border-bottom: 0px solid #000;
}
}
.momo-blink{
animation: blink var(--blinkTime) linear;
}
</style>
<script>
class ToyarMomo {
...
blink(){
this.leftEye.classList.toggle('momo-blink')
this.rightEye.classList.toggle('momo-blink')
}
}
</script>
这样只要调用这个blink 就会进行眨眼动画
但是谁家好人一直眨眼啊,所以优化成随机眨眼
<script>
<script>
class ToyarMomo {
...
startStatus() {
setInterval(() => {
let num =Math.random()
if (num > 0 && num < 0.4) {
this.blink()
}
}, 1000)
}
blink(){
this.leftEye.classList.toggle('momo-blink')
this.rightEye.classList.toggle('momo-blink')
}
}
</script>
这样就可以随机进行眨眼了
loading
<style>
.ToyarMomo.ball{
overflow: hidden;
}
.loading{
height:100%;
line-height: calc(var(--size ) * 2/3);
text-align: center;
color: var(--secondColor);;
position: absolute;
width: 100%;
font-weight: bold;
letter-spacing: 1px;
font-size:calc(var(--size ) * 1/10);
}
</style>
<script>
class ToyarMomo {
...
loading(){
const loading = document.createElement('div')
loading.className='loading'
loading.innerText='Loading...'
this.inner.innerHTML=''
this.inner.append(loading)
let left =0
this.main.classList.add('ball')
let timer = setInterval(()=>{
left-=5
if(left <=-this.size* 2/3 ){
left=this.size*2/3
}
loading.style.left= left +'px'
},100)
setTimeout(()=>{
clearInterval(timer)
this.main.classList.remove('ball')
this.open()
},3000)
}
open(){
this.inner.innerHTML=''
this.inner.append(this.leftEye)
this.inner.append(this.rightEye)
this.startStatus()
}
}
</script>
比较简单没啥好说的
眼睛跟随
<script>
class ToyarMomo {
...
mouseMove(e){
const multiple = 80;
const transformElement=(x, y)=> {
let box = this.rightEye.getBoundingClientRect();
let calcX = (y - box.y - (box.height / 2)) / multiple;
let calcY = (x - box.x - (box.width / 2)) / multiple;
this.rightEye.style.transform =
`translate(${calcY}px, ${calcX}px)`
this.leftEye.style.transform =
`translate(${calcY}px, ${calcX}px)`
}
window.requestAnimationFrame(function(){
transformElement(e.clientX, e.clientY);
});
}
startEyeFollow(){
document.getElementsByTagName("body")[0].addEventListener('mousemove', (e) => {
this.mouseMove(e)
});
}
}
</script>
各种不同眼睛
<style>
/* **********不同的眼睛 ***********/
/* 星星眼 */
.Momo-left_Eye.starEye,
.Momo-right_Eye.starEye{
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}
/* 椭圆眼 */
.Momo-left_Eye.ellipse,
.Momo-right_Eye.ellipse{
clip-path: circle(50% at 50% 50%);
}
/* 圆眼 */
.Momo-left_Eye.round,
.Momo-right_Eye.round{
clip-path: circle(50% at 50% 50%);
width: calc(var(--size) * 12/75);
}
/* 左眼 */
.Momo-left_Eye.left,
.Momo-right_Eye.left{
clip-path: polygon(40% 0%, 40% 33%, 100% 33%, 100% 68%, 40% 68%, 40% 100%, 0% 50%);
width: calc(var(--size) * 12/75);
}
/* 右眼 */
.Momo-left_Eye.right,
.Momo-right_Eye.right{
clip-path: polygon(0 34%, 60% 34%, 60% 0%, 100% 50%, 60% 100%, 60% 68%, 0 68%);
width: calc(var(--size) * 12/75);
}
/* 菱形眼 */
.Momo-left_Eye.rhombus,
.Momo-right_Eye.rhombus{
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}
/* 爱心眼 */
.Momo-left_Eye.love,
.Momo-right_Eye.love{
clip-path:polygon(25% 0, 50% 20%, 75% 0, 100% 20%, 100% 60%, 50% 95%, 0 60%, 0 20%);
width: calc(var(--size) * 12/75);
}
</style>
添加不同的类名即可有不同的眼睛
说点什么吧
<style>
.dialog{
width: 230px;
display: inline-block;
/* background-color: red; */
position: absolute;
left: 130%;
top: -50%;
border: 3px solid transparent;
border-image: url("./src/border.png");
border-width: 23px 35px 33px 35px;
border-image-slice: 51 38 20 132;
box-sizing: border-box;
color: #fff;
word-break: break-all;
transition: all 0.5s;
}
.dialog:empty{
/* display: none; */
height: 0;
border-width: 0;
}
</style>
<script>
class ToyarMomo {
...
createMomo() {
const dialog =document.createElement('div')
dialog.className='dialog'
this.dialog =dialog
main.append(dialog)
}
say(info){
this.dialog.innerText=info
setTimeout(()=>{
this.dialog.innerHTML =''
},1000)
}
}
</script
这里用到了一个科技感十足的边框素材,使用边框图片技术,当我们这个dialog没有内容高度为0,这样就做完了一个小动画
动动耳朵?
<style>
@keyframes lRotate{
0%{
transform: rotate(-35deg);
}
50%{
transform: rotate(-55deg);
}
100%{
transform: rotate(-35deg);
}
}
@keyframes rRotate{
0%{
transform: rotate(35deg);
}
50%{
transform: rotate(15deg);
}
100%{
transform: rotate(35deg);
}
}
.momo-leftRotate{
animation: lRotate var(--blinkTime) linear;
}
.momo-rightRotate{
animation: rRotate var(--blinkTime) linear;
}
</style>
<script>
class ToyarMomo {
...
startStatus() {
setInterval(() => {
let data =Math.random()
if (data > 0 && data < 0.4) {
this.blink()
}
if(data>0.1 && data < 0.6){
this.rotateEar()
}
rotateEar(){
this.leftEar.classList.toggle('momo-leftRotate')
this.rightEar.classList.toggle('momo-rightRotate')
}
}, 1000)
}
}
</script
我要生气啦
<style>
</style>
<script>
class ToyarMomo {
...
startStatus() {
setInterval(() => {
let data =Math.random()
if (data > 0 && data < 0.4) {
this.blink()
}
if(data>0.1 && data < 0.6){
this.error()
}
rotateEar(){
this.leftEar.classList.toggle('momo-leftRotate')
this.rightEar.classList.toggle('momo-rightRotate')
}
}, 1000)
},
error(){
if(this.main.style.getPropertyValue('--secondColor') === 'red'){
return this.main.style.setProperty('--secondColor',this.secondColor)
}
this.main.style.setProperty('--secondColor','red')
}
}
</script
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<style>
body{
background-color: #000;
display: flex;
height: 100vh;
overflow: hidden;
--blinkTime:1s;
transform-style: preserve-3d;
}
@keyframes blink{
0%{
border-top: 0px solid #000;
border-bottom: 0px solid #000;
}
50%{
border-top: calc(var(--size) * 12/150) solid #000;
border-bottom: calc(var(--size) * 12/150) solid #000;
}
100%{
border-top: 0px solid #000;
border-bottom: 0px solid #000;
}
}
@keyframes lRotate{
0%{
transform: rotate(-35deg);
}
50%{
transform: rotate(-55deg);
}
100%{
transform: rotate(-35deg);
}
}
@keyframes rRotate{
0%{
transform: rotate(35deg);
}
50%{
transform: rotate(15deg);
}
100%{
transform: rotate(35deg);
}
}
@keyframes startlight{
0%{
background-color: var(--secondColor);
box-shadow: 0px 0px 0px var(--secondColor);
}
100%{
background-color: var(--secondColor);
box-shadow: 0px 0px calc(var(--size) * 1/3) var(--secondColor);
}
}
.ToyarMomo{
border-radius: 50%;
width: var(--size);
height: var(--size);
margin: auto;
background-color: var(--mainColor);
position: relative;
display: flex;
align-items: center;
justify-content: center;
transition: all .5s;
}
.ToyarMomo.ball{
overflow: hidden;
}
.Momo-left_Ear{
position: absolute;
height: calc(var(--size)/2);
width: calc(var(--size)/5);
background-color: var(--secondColor);
left: 0;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
/* border-radius: 170% 170% 5% 5%; */
transform: rotate(-35deg);
transform-origin: bottom;
top: calc(var(--size) * -2.8/7);
}
.Momo-left_Ear::after{
content: '';
display: inline-block;
width: calc(var(--size) * 0.27);
height: calc(var(--size) * 1/3);
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
background-color: var(--mainColor);
position: absolute;
transform: rotate(180deg);
bottom: calc(var(--size) * -1/6);
left: -15%;
clip-path: polygon(36% 0, 80% -5%, 93% 0,
95% 48%, 97% 68%, 94% 83%, 93% 86%,
90% 92%,
88% 95%, 91% 90%, 87% 95%, 81% 98%, 79% 98%, 78% 93%, 77% 88%, 76% 83%, 73% 76%, 70% 71%, 67% 66%, 56% 50%,
56% 49%, 39% 70%, 34% 81%, 30% 96%, 27% 100%, 19% 94%, 16% 91%,
11% 78%, 9% 73%, 5% 49%, 0 30%);
}
.Momo-right_Ear{
position: absolute;
height: calc(var(--size)/2);
width: calc(var(--size)/5);
left: 0;
top: 0;
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
/* border-radius: 170% 170% 5% 5%; */
transform: rotate(35deg);
top: calc(var(--size) * -2.8/7);
left: calc(var(--size) * 0.81);
transform-origin: bottom;
background-color: var(--secondColor);
z-index: -1;
}
.Momo-right_Ear::after{
content: '';
display: inline-block;
width: calc(var(--size) * 0.27);
height: calc(var(--size) * 1/3);
border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
background-color: var(--mainColor);
position: absolute;
transform: rotate(180deg);
bottom: calc(var(--size) * -1/6);
left: -15%;
/* clip-path: polygon(
28% 0,
35% 10%,
70% 0,
90% 40%,
100% 50%,
90% 85%,
90% 90%,
83% 100%,
50% 50%,
20% 100%,
0 43%); */
clip-path: polygon(36% 0, 80% -5%, 93% 0,
95% 48%, 97% 68%, 94% 83%, 93% 86%,
90% 92%,
88% 95%, 91% 90%, 87% 95%, 81% 98%, 79% 98%, 78% 93%, 77% 88%, 76% 83%, 73% 76%, 70% 71%, 67% 66%, 56% 50%,
56% 49%, 39% 70%, 34% 81%, 30% 96%, 27% 100%, 19% 94%, 16% 91%,
11% 78%, 9% 73%, 5% 49%, 0 30%);
}
.MomoBody{
position: absolute;
width: calc( var(--size) * 2/3);
height: calc( var(--size) * 2/3);
background-color: #000;
transform: rotate(45deg);
margin-top: -10px;
/* border-radius: 58% 42% 81% 19% / 54% 20% 80% 46%; */
border-radius: 55% 45% 77% 23% / 54% 22% 78% 46% ;
border:calc(var(--size) * 0.045 ) solid #2f6ead5e;
z-index: 15;
}
.inner{
transform: rotate(-45deg);
position: absolute;
width: calc( var(--size) * 2/3);
height: calc( var(--size) * 2/3);
overflow: hidden
}
.MomoGy{
width: 30px;
height: 18px;
/* background: #fff; */
/* background-color: linear-gradient(#fff, #000); */
/* background: linear-gradient(#fff, #111); */
background: repeating-radial-gradient(
white,
#000 18px
);
position: absolute;
border-radius: 50%;
left: 11px;
top: 18px;
transform: rotate(-40deg);
}
.ear-light{
animation: startlight 2s forwards;
}
.ear-error{
/* animation: startError 2s forwards; */
/* var(--se) */
--secondColor:red
}
.Momo-left_Eye,.Momo-right_Eye{
width: calc(var(--size) * 1.5/15);
border: 0px solid #000;
border-top: 0px solid #000;
border-bottom: 0px solid #000;
background-color: var(--secondColor);
height: calc( var(--size) * 12/75);
box-sizing: border-box;
position: absolute;
top: 37%;
}
.Momo-left_Eye{
left: 20%;
}
.Momo-right_Eye{
left: 70%;
}
.momo-blink{
animation: blink var(--blinkTime) linear;
}
.momo-leftRotate{
animation: lRotate var(--blinkTime) linear;
}
.momo-rightRotate{
animation: rRotate var(--blinkTime) linear;
}
.loading{
height:100%;
line-height: calc(var(--size ) * 2/3);
text-align: center;
color: var(--secondColor);;
position: absolute;
width: 100%;
font-weight: bold;
letter-spacing: 1px;
font-size:calc(var(--size ) * 1/10);
}
.open{
width: calc(var(--size) / 10);
height:calc(var(--size) / 10);
background-image: url('./src/close.svg');
position: absolute;
bottom: calc(var(--size) / 15);
background-repeat: no-repeat;
background-position: center;
background-size: calc(var(--size) / 12) calc(var(--size) / 12);
/* border: 2px solid #666; */
border-radius: 50%;
/* box-shadow: 0 0 3px var(--secondColor); */
}
.open:hover{
cursor: pointer;
/* box-shadow: 0px 0px 5px var(--secondColor); */
}
/* .leftVg{
border: 3px solid #000;
width: 50px;
height: 50px;
position: absolute;
left: 0;
bottom: 0;
border-radius: 30% 0 30% 0;
}
.rightVg{
border: 3px solid #000;
width: 50px;
height: 50px;
position: absolute;
right: 0;
bottom: 0;
border-radius: 0 30% 0 30% ;
} */
.dialog{
width: 230px;
display: inline-block;
/* background-color: red; */
position: absolute;
left: 130%;
top: -50%;
border: 3px solid transparent;
border-image: url("./src/border.png");
border-width: 23px 35px 33px 35px;
border-image-slice: 51 38 20 132;
box-sizing: border-box;
color: #fff;
word-break: break-all;
transition: all 0.5s;
}
.dialog:empty{
/* display: none; */
height: 0;
border-width: 0;
}
</style>
<script>
class ToyarMomo {
constructor(size,{
mainColor='#cbe8d7',
secondColor='#02feff',
}) {
this.size=size
this.mainColor = mainColor
this.secondColor = secondColor
this.init()
}
init() {
this.appendStyles()
this.createMomo()
this.startEyeFollow()
}
createLeftEar(){
const leftEar = document.createElement('div')
leftEar.className = 'Momo-left_Ear ear-light'
this.leftEar =leftEar
return leftEar
}
createRightEar(){
const rightEar = document.createElement('div')
rightEar.className = 'Momo-right_Ear ear-light'
this.rightEar =rightEar
return rightEar
}
createLeftEye(){
const leftEye = document.createElement('div');
leftEye.className ='Momo-left_Eye'
this.leftEye = leftEye
return leftEye
}
createRightEye(){
const rightEye = document.createElement('div');
rightEye.className ='Momo-right_Eye'
this.rightEye = rightEye
return rightEye
}
createInner(){
const inner = document.createElement('div');
inner.className='inner'
this.inner = inner
const leftEye = this.createLeftEye()
const rightEye = this.createRightEye()
inner.append(leftEye)
inner.append(rightEye)
return inner
}
createBody(){
const body = document.createElement('div');
body.className = 'MomoBody'
this.body = body
const inner =this.createInner()
body.append(inner)
return body
}
createMomo() {
let main = document.createElement('main');
main.id='Momo'
main.className = 'ToyarMomo'
main.style.setProperty('--size',this.size+'px')
main.style.setProperty('--mainColor',this.mainColor)
main.style.setProperty('--secondColor',this.secondColor)
this.main = main
const body= this.createBody()
const leftEar= this.createLeftEar()
const rightEar= this.createRightEar()
main.append(body)
main.append(leftEar)
main.append(rightEar)
const open =document.createElement('div')
open.className='open'
main.append(open)
const leftVg =document.createElement('div')
leftVg.className='leftVg'
main.append(leftVg)
const rightVg =document.createElement('div')
rightVg.className='rightVg'
main.append(rightVg)
const dialog =document.createElement('div')
dialog.className='dialog'
this.dialog =dialog
main.append(dialog)
document.body.append(main)
this.loading()
}
appendStyles() {
let staticStyle = `
`
let style = document.createElement('style')
style.innerText = staticStyle
document.body.appendChild(style)
}
loading(){
const loading = document.createElement('div')
loading.className='loading'
loading.innerText='Loading...'
this.inner.innerHTML=''
this.inner.append(loading)
let left =0
this.main.classList.add('ball')
let timer = setInterval(()=>{
left-=5
if(left <=-this.size* 2/3 ){
left=this.size*2/3
}
loading.style.left= left +'px'
},100)
setTimeout(()=>{
clearInterval(timer)
this.main.classList.remove('ball')
this.say('主人,我回来咯!')
this.open()
},3000)
}
open(){
this.inner.innerHTML=''
this.inner.append(this.leftEye)
this.inner.append(this.rightEye)
this.startStatus()
}
mouseMove(e){
const multiple = 80;
const transformElement=(x, y)=> {
let box = this.rightEye.getBoundingClientRect();
let calcX = (y - box.y - (box.height / 2)) / multiple;
let calcY = (x - box.x - (box.width / 2)) / multiple;
this.rightEye.style.transform =
`translate(${calcY}px, ${calcX}px)`
this.leftEye.style.transform =
`translate(${calcY}px, ${calcX}px)`
}
window.requestAnimationFrame(function(){
transformElement(e.clientX, e.clientY);
});
}
startEyeFollow(){
document.getElementsByTagName("body")[0].addEventListener('mousemove', (e) => {
this.mouseMove(e)
});
}
startStatus() {
setInterval(() => {
let data =Math.random()
if (data > 0 && data < 0.4) {
this.blink()
}
if(data>0.1 && data < 0.6){
this.rotateEar()
}
if(data>0.6){
let info = "啦啦啦啦啦啦啦啦啦~"
if(data>0.7){
function pad(timeEl, total = 2, str = '0') {
return timeEl.toString().padStart(total, str)
}
function formaData(timer) {
const year = timer.getFullYear()
const month = timer.getMonth() + 1 // 由于月份从0开始,因此需加1
const day = timer.getDate()
const hour = timer.getHours()
const minute = timer.getMinutes()
const second = timer.getSeconds()
return `${pad(year, 4)}-${pad(month)}-${pad(day)} ${pad(hour)}:${pad(minute)}:${pad(second)}`
}
console.log(formaData(new Date()));
info = formaData(new Date())
}
this.say(info)
}
}, 1000)
}
say(info){
this.dialog.innerText=info
setTimeout(()=>{
this.dialog.innerHTML =''
},1000)
}
blink(){
this.leftEye.classList.toggle('momo-blink')
this.rightEye.classList.toggle('momo-blink')
}
rotateEar(){
this.leftEar.classList.toggle('momo-leftRotate')
this.rightEar.classList.toggle('momo-rightRotate')
}
error(){
if(this.main.style.getPropertyValue('--secondColor') === 'red'){
return this.main.style.setProperty('--secondColor',this.secondColor)
}
this.main.style.setProperty('--secondColor','red')
}
}
let momo = new ToyarMomo(150,{
// mainColor:'#cbe8d7',
// secondColor:'#02feff',
// mainColor:'red',
// secondColor:'blue'
})
</script>
</body>
</html>
完善桌宠
后面使用electron真正将这个demo做成了一个桌宠 当春节前不想写业务的前端会做什么(二) - 掘金 (juejin.cn)