原文地址:https://www.webxiu.com.cn/post/10005242
前言
[图片上传失败...(image-1988c9-1652432201196)]
上一章节《Electron+Vue3+TypeScript+Vite桌面应用程序项目初始化》完成后,我们的桌面应用程序如上图,这次我们先美化一下界面,形成初步的UI框架。
从这里开始需要书写css,我们选择SCSS工具,先安装:
npm install sass -save-dev
新建assets/scss/globalVariable.scss
// 这里书写全局的css样式,或者方法等
修改 vite.config.ts
...
css: {
//css预处理
preprocessorOptions: {
scss: {
/*
引入.scss全局预定义变量
*/
additionalData: '@import "./src/assets/scss/globalVariable.scss";@import "./src/assets/scss/iconfont.scss";'
}
}
}
窗口优化
由上图可以看到,默认的菜单栏、最小化最大化关闭按钮都不是很美观,所以我们来自定义一下。
掉标题栏和边框
修改electron-main/index.ts
...
mainWindow = new BrowserWindow({
...
frame: false, // 标题栏和边框一并隐藏
});
...
自定义标题栏
新建组件components/c-header.vue
,利用 flex布局
两端对齐,左侧程序名称,右侧最小化、最大化和关闭按钮
<template>
<div class="header flex">
<div class="header-title flex1 flex-align-center">Todo List</div>
<div class="header-btns" v-if="showBtn">
<component :is="components.get(compName)" type="min" title="最小化" content="icon-jianhao"></component>
<component :is="components.get(compName)" type="max" title="最大化" content="icon-fangxingweixuanzhong"></component>
<component :is="components.get(compName)" type="close" title="关闭" content="icon-guanbi1"></component>
</div>
</div>
</template>
<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue'
// 判断是node还是浏览器环境
// 浏览器环境就不用显示最小化、最大化、关闭按钮
// 根据环境动态加载组件
// 如果不这样处理,浏览器会报错 require undefault
let showBtn = typeof global!='undefined'
const components = ref(new Map<string, any>())
if(showBtn){
components.value.set(
'headerBtn',
defineAsyncComponent(() => import('./c-header-btn.vue'))
)
}
const compName = ref('headerBtn')
</script>
<style lang="scss" scoped>
.header{
-webkit-app-region: drag;
padding: 15px 15px;
&-title{
font-weight: 600;
}
&-btns{
&>div{
&:last-child{
padding-right: 0;
}
}
}
}
</style>
上面的 flex 默认选择器在全局的scss里面以书写
// assets/scss/globalVariable.scss
.flex {
display: flex;
.flex1{
flex: 1;
}
}
.flex-align-center {
@extend .flex;
align-items: center;
}
.flex-space {
@extend .flex;
justify-content: space-between;
}
.flex-space-center {
@extend .flex;
align-items: center;
justify-content: space-between;
}
.flex-center-center {
@extend .flex;
align-items: center;
justify-content: center;
}
.flex-row {
flex-direction: row;
}
.flex-col {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
}
新建components/c-header-btn.vue
<template>
<div
class="c-header-btn"
v-on:click="click">
<i class="iconfont" :class="content"></i>
</div>
</template>
<script lang="ts">
import electron from 'electron';
export default {
name: 'c-header-btn',
props: {
type: [String],
content: [String],
},
data(){
},
methods: {
click: function () {
if(this.type && typeof global!='undefined'){
// 向主进程发送异步消息,下面在electron-main/index.ts接收
electron.ipcRenderer.send(this.type);
}
}
}
}
</script>
<style lang="scss" scoped>
.c-header-btn {
position: relative;
padding-right: 15px;
-webkit-app-region: no-drag;
color: #2798f7;
cursor: pointer;
display: inline-block;
&:hover i{
color: #ED5A5A;
}
}
</style>
electron-main/index.ts
监听按钮事件
// electron-main/index.ts
import { ..., ipcMain } from 'electron';
...
let mainWindow : any;
const createWindow = () => {
mainWindow = new BrowserWindow({
...
});
}
// 监听自定义按钮事件,并作出相应动作
// 最小化应用程序
ipcMain.on('min', e => mainWindow.minimize())
// 最大化应用程序
ipcMain.on('max', e => {
if (mainWindow.isMaximized()) {
mainWindow.unmaximize()
} else {
mainWindow.maximize()
}
})
// 关闭应用程序
ipcMain.on('close', e => mainWindow.close())
App.vue
导入 c-header.vue
组件
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import cHeader from './components/c-header.vue'
</script>
<template>
<div class="layout flex flex-col">
<c-header/>
</div>
</template>
<style lang="scss" scoped>
.layout {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
height: 100%;
}
</style>
[图片上传失败...(image-84c3e6-1652432201196)]
todo list 事项面板UI
新建components/c-main.vue
<script setup lang="ts">
</script>
<template>
<div class="main">
<div class="group">待处理</div>
<div class="group">进行中</div>
<div class="group">待发布</div>
<div class="group">已发布</div>
<div class="group">已完成</div>
<div class="group">待观察</div>
</div>
</template>
<style lang="scss" scoped>
.main{
overflow-x: auto;
white-space: nowrap;
padding: 0 15px;
.group{
display: inline-block;
width: 200px;
height: 100%;
margin-right: 10px;
// 随机背景色,用来看清布局
@for $i from 1 through 30 {
&:nth-child(#{$i}) {
background: rgba(random(255), random(255), random(255), 0.8);
}
}
}
}
</style>
事项分组group可能有N个,所以这里css样式让group一直向右排列,overflow-x: auto; white-space: nowrap;
App.vue
导入 c-main.vue
组件
<script setup lang="ts">
...
import cMain from './components/c-main.vue'
</script>
<template>
<div class="layout flex flex-col">
<c-header/>
<c-main class="flex1"/>
</div>
</template>
[图片上传失败...(image-987bd8-1652432201196)]
结语
到这里,项目的UI框架基本结束,下一章节将集成 Vue.Draggable
拖拽任务。
本项目将持续更新,希望你也持续关注。
网友评论