当春节前不想写业务的前端会做什么(二)

背景

今天已经初六了,想必各位大佬跟我一样也即将踏上工作的路途了。小弟在这里祝愿各位大佬在新的一年,技术进步,事业有成,财源滚滚。


书接上文,过年前在公司由于不想写业务而做了一个小demo(不了解的大佬可以看一下上次都做了什么当春节前不想写业务的前端会做什么 - 掘金 (juejin.cn)),但是上次完成的仅仅是个小玩具甚至他都不怎么好玩,这次我们来继续深入完成更多有意思的功能。 以下是Momo的简单介绍:

  • 名称: Momo
  • 性别: 不详
  • 情绪: 默认/生气
  • 状态: Loading/working
  • 自述: 大家好我是Momo,诞生于2024年,我是一名智能桌面助手哦。

Momo生活照

完善页面

添加阴影

由于2d的桌宠看起来像一张图片没那么多立体感,这里决定加一个阴影。

html 复制代码
<style>
.toyarMomo {
    ...
    box-shadow: 9px 6px 16px 3px rgba(0, 0, 0, 0.2);
    ...
}
</style>

增加耳朵亮闪闪效果

html 复制代码
<style>
    .momo-left_Ear::before,
    .momo-right_Ear::before {
      content: "";
      position: absolute;
      inset: 0;
      background: url('./src/star.awebp');
      border-radius: 44% 49% 22% 65% / 100% 100% 0% 0%;
      /* mix-blend-mode: color-dodge; */
      /* mix-blend-mode: hard-light; */
      /* mix-blend-mode: multiply; */
      mix-blend-mode: difference;
    }
</style>

效果: 解释一下 这里使用了一张gif动图就是下面这个星星闪闪的图片,并且作为耳朵的伪元素背景,最后使用css,mix-blend-mode: difference;

这个css的意思是该元素的内容应该与元素的直系父元素的内容和元素的背景如何混合。不了解的可以查看这个链接学习mix-blend-mode - CSS:层叠样式表 | MDN (mozilla.org)

ps:我倒是没觉得很好看,不过炫酷就完了

脸部反射光

上面也提到过我觉得2d不够立体,这里再加一个面部灯光反射

html 复制代码
<style>
    .momoBody::after {
      content: "";
      position: absolute;
      inset: 0;
      border-radius: 55% 45% 77% 23% / 54% 22% 78% 46%;
      background: linear-gradient(90deg,
          transparent 0%,
          rgba(255, 255, 255, 0.05) var(--per),
          rgba(255, 255, 255, 0.1) var(--per),
          rgba(255, 255, 255, 0.3) calc(var(--per) + 15%),
          rgba(255, 255, 255, .1) calc(var(--per) + 30%),
          rgba(255, 255, 255, 0.05) var(--per),

          transparent 100%);
      mix-blend-mode: color-dodge;
      z-index: 999;
    }
</style>
<script>
setInterval(() => {
  if (flag) {
    data += 1
  } else {
    data -= 1
  }
  if (data === 30 || data === -50) {
    flag = !flag
  }
  this.body.style.setProperty('--per', data + '%')
}, 30)
</script>

效果:

解释一下,这里使用了一个线性渐变背景作为伪元素的背景,然后线性渐变是一个透明到白色再到透明的效果,然后定时器修改css属性改变这里渐变的位置

为什么不用animation?,当时想着做别的东西来着,后来写完了懒得改了,不过这个也挺机械的感觉不太好(后面优化吧)

使用Electron

介绍

众所周知,htmlcssjs 通常只能运行再浏览器中,但是作为一个桌宠只能运行在浏览器中是不是有点说不太过去,所以这里使用Electron。

安装

  1. 首先得有node环境这里不演示了

  2. 初始化package.json npm init -y

  3. 安装electron

    npm install electron --save-dev

    注意这里npm安装electron 可能会失败,大概是镜像原因,解决方案 npm安装Electron 项目失败报错问题和解决办法_npm install electron报错-CSDN博客

  4. 安装forge npm install --save-dev @electron-forge/cli

    执行 npx electron-forge import

    安装后的项目结构

创建窗口与加载页面

  1. 创建main.js 并修改package.json中入口js名称
  2. 创建一个html文件
  3. 在main.js中创建窗口文件

运行 npm run start 查看代码是否生效 看到窗口证明可以了

最后将写的html 代码移植过来然后在npm run start 看一下,可以看到这里也运行起来了

窗口配置

前面虽然能运行但是白色的边框根本不像桌宠而且这里鼠标事件也不能穿透,这里需要一些配置

可以看到这里已经十分接近桌宠了,但是有个致命问题,就是要么鼠标事件穿透不过去,要么就是能穿透但是点击不了桌宠了,这样也没法交互了

效果

使用ipc通信解决鼠标事件问题

解释一下,这里当鼠标移入桌宠时候则开始鼠标事件监听触发,当鼠标移出桌宠时候则关闭鼠标事件监听触发。

ipc通信这里就不解释了

桌宠的交互功能(1)

html 复制代码
<style>
    .controller {
      position: absolute;
      top: 50%;
      left: 50%;
      width: calc(var(--size) * 8/15);
      height: calc(var(--size) * 8/15);
      transform: translate(-50%, -50%);
      z-index: -10;
      transition: all 2s;
    }

    .ctlItem {
      position: absolute;
      width: calc(var(--size) * 8/15);
      height: calc(var(--size) * 8/15);
      z-index: 1;
      transition: transform 2s;
      border-radius: 8px;
      overflow: hidden;
      box-shadow: 0 0 6px rgba(255, 255, 255, 0.2);
      background-color: rgba(255, 255, 255, 0.4);
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .ctlItem>.empty {
      background-image: url('./src/asstes/add.svg');
      background-size: 100% 100%;
    }
    .ctlItem>.ctlItem_close{
      width: calc(var(--size) * 2/15);
      height: calc(var(--size) * 2/15);
      position: absolute;
      /* right: calc(var(--size) * -1/15);
      top: calc(var(--size) * -1/15); */
      top: calc(var(--size) * 1/15);
      right: calc(var(--size) * 1/15);
      background-image: url('./src/asstes/close.svg');

      background-size: 100% 100% !important;
    }
    .ctlItem>.ctlItem_close:hover{
      background-image: url('./src/asstes/closeHover.svg');
    }

    .controller.active>.ctlItem {
      transform: rotate(calc(var(--ctlItem) + 0deg)) translate(0px, calc(var(--size) * -5/3));
    }

    .controller.active>.ctlItem>div {
      transform: rotate(calc(var(--ctlItem) * -1deg));
    }

    .ctlItem>div {
      width: calc(var(--size) * 5/15);
      height: calc(var(--size) * 5/15);
      background-size: 100% 100% !important;
    }

    .ctlItem:hover {
      box-shadow: 0 0 6px rgba(255, 255, 255, 0.2);
      background-color: rgba(255, 255, 255, 0.7);
      cursor: pointer;
    }
</style>
<script>
 class toyarMomo {
     ...
     createBtn(item, i) {
        const ctlItem = document.createElement('div');
        const head = 'momo_'
        ctlItem.className = 'ctlItem'
        ctlItem.style.setProperty('--ctlItem', item + 'deg')


        const {path,imgURL} = JSON.parse(localStorage.getItem(head + i)) ||{
          path:'',
          imgURL:""
        }
        const src = path || 'empty'
        if (src === 'empty') {
          ctlItem.innerHTML = `<div class="empty" > </div>`
          ctlItem.setAttribute('fileUrl', '')
        } else {
          ctlItem.innerHTML = `
            <div style="background:url(${imgURL})"> </div>
            `
            this.createCloseBtn(ctlItem,i)
            // <div class="ctlItem_close" onClick="closectlItem(${i})"></div>
          ctlItem.setAttribute('fileUrl', src)
        }
        ctlItem.addEventListener('click', async () => {

          if (window.versions) {
            if (ctlItem.getAttribute('fileUrl')) {
              window.versions.ctlItemClick({
                type: ctlItem.getAttribute('fileUrl'),
                index: i
              })
              return
            }

            let {path,imgURL} = await window.versions.ctlItemClick({
              type: 'empty',
              index: i
            })
            localStorage.setItem(head + i, JSON.stringify({
              path,
              imgURL
            }))
            ctlItem.setAttribute('fileUrl', path)
            ctlItem.innerHTML = `
                <div 
                  style="
                    background:url(${imgURL})"
                  >
                </div>
                `
            this.createCloseBtn(ctlItem,i)
                // <div class="ctlItem_close">x</div>
          }
        })
        return ctlItem
      }
     createController(max = 8) {
        const controller = document.createElement('div');
        this.controller = controller
        controller.className = 'controller'

        let route = 360 / max
        for (let i = 0; i < max; i++) {
          controller.append(this.createBtn(i * route, i))
        }
        return controller
      }
     createRoot() {
         ...
         main.addEventListener('dblclick', () => {
          this.controller.classList.toggle('active')
        })
        const controller = this.createController()
        main.append(controller)
         ...
     }

 }
</script>
html 复制代码
<script>
    //主进程
 ipcMain.handle('ctlItemClick',async (event,{type,index})=>{
    if(type === 'empty'){
      const {filePaths} = await dialog.showOpenDialog({
        properties: ['openFile'],
        buttonLabel:'选择',
        title:'快捷方式',
        filters:[
          {'name':'应用',extensions:['exe']},
          {'name':'图片文件',extensions:['ico','png','jpg','jpeg','svg']},
          // {'name':'媒体文件',extensions:['avi','mp4','mp3']},
        ]
    })
    const fileIcon = await  app.getFileIcon(filePaths[0]);
    let imgURL= fileIcon.toDataURL()
    console.log(imgURL);
    return {imgURL,path:filePaths}
    }else{
      shell.openPath(type)
    }
  })
</script>

双击效果

添加删除与启动应用效果

相关推荐
天天向上102410 分钟前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y26 分钟前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁33 分钟前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry33 分钟前
Fetch 笔记
前端·javascript
拾光拾趣录34 分钟前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟35 分钟前
vue3,你看setup设计详解,也是个人才
前端
Lefan39 分钟前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson44 分钟前
青苔漫染待客迟
前端·设计模式·架构
vvilkim1 小时前
Nuxt.js 全面测试指南:从单元测试到E2E测试
开发语言·javascript·ecmascript
写不出来就跑路1 小时前
基于 Vue 3 的智能聊天界面实现:从 UI 到流式响应全解析
前端·vue.js·ui