• 创建一个electron桌面备忘录


     

     

    Sound Of Silence

    1.创建electron项目命令: npm create @quick-start/electron my-new-project

            2选择:√ Select a framework: » vue

            √ Add TypeScript? ... No

            √ Add Electron updater plugin? ... Yes

            √ Enable Electron download mirror proxy? ... Yes

            3.命令:cd my-new-project

            4.命令:yarn

            5.启动命令: yarn dev

            6.打包命令:yarn build:win

     主进程代码index.js:

    1. import { app, shell, BrowserWindow, ipcMain } from 'electron'
    2. import { join } from 'path'
    3. import { electronApp, optimizer, is } from '@electron-toolkit/utils'
    4. import icon from '../../resources/icon.png?asset'
    5. function createWindow() {
    6. // Create the browser window.创建浏览器窗口。
    7. const mainWindow = new BrowserWindow({
    8. width: 900,
    9. height: 670,
    10. // 设置窗口的尺寸是否包含窗口边框和标题栏
    11. useContentSize: true,
    12. // 在创建 Electron 主窗口时禁用窗口外框
    13. frame: false,
    14. // 控制是否显示的变量
    15. show: false,
    16. // 设置自动隐藏菜单栏为 true
    17. autoHideMenuBar: true,
    18. alwaysOnTop: true,
    19. ...(process.platform === 'linux' ? { icon } : {}),
    20. webPreferences: {
    21. preload: join(__dirname, '../preload/index.js'),
    22. sandbox: false
    23. }
    24. })
    25. mainWindow.on('ready-to-show', () => {
    26. mainWindow.show()
    27. })
    28. mainWindow.webContents.setWindowOpenHandler((details) => {
    29. shell.openExternal(details.url)
    30. return { action: 'deny' }
    31. })
    32. if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    33. mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
    34. } else {
    35. mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
    36. }
    37. }
    38. app.whenReady().then(() => {
    39. electronApp.setAppUserModelId('com.electron')
    40. app.on('browser-window-created', (_, window) => {
    41. optimizer.watchWindowShortcuts(window)
    42. })
    43. ipcMain.on('ping', () => console.log('pong'))
    44. createWindow()
    45. app.on('activate', function () {
    46. if (BrowserWindow.getAllWindows().length === 0) createWindow()
    47. })
    48. })
    49. app.on('window-all-closed', () => {
    50. if (process.platform !== 'darwin') {
    51. app.quit()
    52. }
    53. })

    preload预加载的代码index.js:

    1. import { contextBridge } from 'electron'
    2. import { electronAPI } from '@electron-toolkit/preload'
    3. // Custom APIs for renderer
    4. const api = {}
    5. // Use `contextBridge` APIs to expose Electron APIs to
    6. // renderer only if context isolation is enabled, otherwise
    7. // just add to the DOM global.
    8. if (process.contextIsolated) {
    9. try {
    10. contextBridge.exposeInMainWorld('electron', electronAPI)
    11. contextBridge.exposeInMainWorld('api', api)
    12. } catch (error) {
    13. console.error(error)
    14. }
    15. } else {
    16. window.electron = electronAPI
    17. window.api = api
    18. }

    渲染进程的代码main.js:

    1. import './assets/css/main.css'
    2. import { createApp } from 'vue'
    3. import App from './App.vue'
    4. createApp(App).mount('#app')

    index.html

     

    1. html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8" />
    5. <title>title>
    6. <meta http-equiv="Content-Security-Policy" />
    7. head>
    8. <body>
    9. <div id="app">div>
    10. <script type="module" src="/src/main.js">script>
    11. body>
    12. html>

     App.vue

    1. <template>
    2. <MyLogs />
    3. template>
    4. <script setup>
    5. import MyLogs from './components/MyLogs.vue'
    6. script>

     MyLogs.vue

    1. <template>
    2. <div>
    3. <div class="header">
    4. <a href="https://blog.csdn.net/lulei5153" title="与妖为邻CSDN博客" class="" target="_blank">
    5. <img src="../assets/img/kong.jpg" alt="与妖为邻" style="border-radius: 50%" />
    6. a>
    7. <button v-if="!formVisible" class="openForm" @click="openForm">编辑button>
    8. <button v-if="formVisible" @click="closeForm">取消编辑button>
    9. <NowTime />
    10. <iframe
    11. ref="weather"
    12. frameborder="0"
    13. width="150"
    14. height="36"
    15. scrolling="no"
    16. hspace="0"
    17. src="https://i.tianqi.com/?c=code&id=99"
    18. style="margin-left: 20px"
    19. >iframe>
    20. <span class="windowTool">
    21. <i class="minimize"><img src="../assets/img/最小化.svg" alt="最小化" />i>
    22. <i class="maximize"><img src="../assets/img/最大化.svg" alt="最大化" />i>
    23. <i class="close"><img src="../assets/img/关闭.svg" alt="关闭" />i>
    24. span>
    25. div>
    26. <form
    27. v-if="formVisible"
    28. class="draggable-form"
    29. :style="{ top: formPosition.y + 'px', left: formPosition.x + 'px' }"
    30. @submit.prevent="addMemo"
    31. >
    32. <div v-drag drag-min-top="50" class="form-title" @mousedown="startDrag">{{ formTitle }}div>
    33. <div class="form-content">
    34. <input type="reset" value="重置" />
    35. <textarea v-model="newItem" rows="10" placeholder="请输入备注内容">textarea>
    36. <button type="submit" class="addBtn">添加button>
    37. div>
    38. form>
    39. <div class="memo" @click="handleMemoAction">
    40. <div v-for="(memo, index) in memos" :key="index" class="item">
    41. <span class="item-number">{{ index + 1 }}.span>
    42. <button v-if="showActions && !memo.finished" @click="completeMemo(index)">完成button>
    43. <button v-if="showActions && memo.finished" @click="cancelMemo(index)">取消button>
    44. <span class="text-content" :class="{ content: true, finish: memo.finished }">
    45. {{ memo.name }}
    46. span>
    47. <button v-if="showActions && memo.finished" @click="reworkMemo(index)">修改button>
    48. <button
    49. v-if="showActions && memo.finished"
    50. v-show="noindex == index ? false : true"
    51. class="deleteBtn"
    52. @click="deleteMemo(index)"
    53. >
    54. 删除
    55. button>
    56. <span v-show="noindex == index ? true : false" class="alter">
    57. <textarea v-model="newItem" rows="10">textarea>
    58. <button @click="csu">提交button>
    59. span>
    60. div>
    61. div>
    62. div>
    63. template>
    64. <script setup>
    65. import NowTime from './NowTime.vue'
    66. import { ref } from 'vue'
    67. import '../assets/css/MyLogs.css'
    68. import Drag from '../assets/js/Drag.js'
    69. const { formTitle, formPosition, startDrag } = Drag()
    70. const formVisible = ref(false)
    71. const newItem = ref('')
    72. const memos = ref([])
    73. const showActions = ref(false)
    74. const noindex = ref(-1)
    75. const openForm = () => {
    76. formVisible.value = true
    77. showActions.value = true
    78. }
    79. const closeForm = () => {
    80. formVisible.value = false
    81. showActions.value = false
    82. }
    83. const reworkMemo = (index) => {
    84. if (newItem.value === '' || false) {
    85. newItem.value = memos.value[index].name
    86. noindex.value = index
    87. formVisible.value = false
    88. showActions.value = false
    89. } else {
    90. newItem.value = ''
    91. noindex.value = -1
    92. }
    93. }
    94. const csu = () => {
    95. if (noindex.value === -1) {
    96. return
    97. }
    98. memos.value[noindex.value].name = newItem.value
    99. // 取消备忘录的完成状态
    100. memos.value[noindex.value].finished = false
    101. noindex.value = -1
    102. newItem.value = ''
    103. saveTodo()
    104. }
    105. const addMemo = () => {
    106. if (newItem.value.trim() !== '') {
    107. memos.value.push({ name: newItem.value, finished: false })
    108. newItem.value = ''
    109. formVisible.value = false
    110. showActions.value = false
    111. saveTodo()
    112. }
    113. }
    114. const completeMemo = (index) => {
    115. memos.value[index].finished = true
    116. saveTodo()
    117. }
    118. const cancelMemo = (index) => {
    119. memos.value[index].finished = false
    120. saveTodo()
    121. }
    122. const deleteMemo = (index) => {
    123. memos.value.splice(index, 1)
    124. updateItemNumbers()
    125. formVisible.value = false
    126. showActions.value = false
    127. saveTodo()
    128. }
    129. const handleMemoAction = (event) => {
    130. const target = event.target
    131. if (target.innerHTML === '完成') {
    132. // handle complete action
    133. } else if (target.innerHTML === '取消') {
    134. // handle cancel action
    135. } else if (target.innerHTML === '删除') {
    136. // handle delete action
    137. }
    138. }
    139. const saveTodo = () => {
    140. localStorage.myLogs = JSON.stringify(memos.value)
    141. }
    142. const loadTodo = () => {
    143. const savedMemos = JSON.parse(localStorage.myLogs ?? '[]')
    144. memos.value = savedMemos
    145. updateItemNumbers()
    146. }
    147. const updateItemNumbers = () => {
    148. const itemNumbers = document.querySelectorAll('.item-number')
    149. itemNumbers.forEach((item, index) => {
    150. item.textContent = index + 1
    151. })
    152. }
    153. loadTodo()
    154. script>
    155. <style scoped>style>

    NowTime.vue

    1. <template>
    2. <div>
    3. <p>{{ dateTime }}p>
    4. <sub>{{ dayTime }}sub>
    5. <p>{{ currentTime }}p>
    6. div>
    7. template>
    8. <script setup>
    9. import { ref, onMounted } from 'vue'
    10. const dateTime = ref('')
    11. const dayTime = ref('')
    12. const currentTime = ref('')
    13. const updateTime = () => {
    14. const now = new Date()
    15. const year = now.getFullYear()
    16. let month = now.getMonth() + 1
    17. const day = now.getDate()
    18. let hour = now.getHours()
    19. let min = now.getMinutes()
    20. let second = now.getSeconds()
    21. const arrWork = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
    22. const week = arrWork[now.getDay()]
    23. month = month < 10 ? '0' + month : month
    24. hour = hour < 10 ? '0' + hour : hour
    25. min = min < 10 ? '0' + min : min
    26. second = second < 10 ? '0' + second : second
    27. dateTime.value = `${year}-${month}-${day}`
    28. dayTime.value = `${week}`
    29. currentTime.value = `${hour}:${min}:${second}`
    30. }
    31. onMounted(() => {
    32. window.setInterval(updateTime, 1000)
    33. updateTime()
    34. })
    35. script>
    36. <style scoped>
    37. div {
    38. display: flex;
    39. }
    40. p {
    41. font-size: 25px;
    42. background: -webkit-linear-gradient(315deg, #e1ff00 50%, #ff0000);
    43. }
    44. sub {
    45. margin: 15px 0 0 0;
    46. background: -webkit-linear-gradient(315deg, hsl(0, 0%, 100%) 50%, #fcf401);
    47. }
    48. p,
    49. sub {
    50. /*将背景剪切成文字的形状*/
    51. background-clip: text;
    52. -webkit-background-clip: text;
    53. /*文字颜色设为透明,使文字与背景融为一体*/
    54. -webkit-text-fill-color: transparent;
    55. /* 设置字体粗细 */
    56. font-weight: 900;
    57. text-shadow: 2px -1px 8px rgba(250, 80, 193, 0.323);
    58. }
    59. style>

    拖拽窗口的代码Drag.js

    1. /* eslint-disable prettier/prettier */
    2. /* 引入 */
    3. import { reactive, onMounted } from 'vue'
    4. export default function () {
    5. /*窗口移动事件*/
    6. const formTitle = '鼠标事件绑定标题栏实现拖动功能'
    7. const formPosition = reactive({ x: 0, y: 0 }) // 记录窗口位置的变量
    8. const startDrag = (event) => {
    9. event.preventDefault() // 阻止默认拖动行为
    10. const offsetX = event.clientX - formPosition.x
    11. const offsetY = event.clientY - formPosition.y
    12. const onDrag = (e) => {
    13. let newX = e.clientX - offsetX
    14. let newY = e.clientY - offsetY
    15. // 边界检查
    16. newX = Math.max(0, Math.min(newX, window.innerWidth - formPosition.x))
    17. newY = Math.max(50, Math.min(newY, window.innerHeight - formPosition.y))
    18. formPosition.x = newX
    19. formPosition.y = newY
    20. }
    21. const onStopDrag = () => {
    22. document.removeEventListener('mousemove', onDrag)
    23. document.removeEventListener('mouseup', onStopDrag)
    24. }
    25. document.addEventListener('mousemove', onDrag)
    26. document.addEventListener('mouseup', onStopDrag)
    27. }
    28. onMounted(() => {
    29. const initialX = window.innerWidth / 4 // 窗口水平
    30. const initialY = window.innerHeight / 4 // 窗口垂直
    31. formPosition.x = initialX
    32. formPosition.y = initialY
    33. })
    34. return {
    35. formTitle,
    36. formPosition,
    37. startDrag
    38. }
    39. }

    MyLogs.css

    1. button,
    2. input {
    3. cursor: pointer;
    4. border: none;
    5. color: #ffffff94;
    6. text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
    7. background-color: hsla(160, 100%, 37%, 0.247);
    8. &:hover {
    9. color: #f6f200;
    10. background-color: hsla(160, 100%, 37%, 0.995);
    11. box-shadow: 0 0 15px rgba(255, 254, 254, 0.5);
    12. }
    13. }
    14. /* 头部样式 */
    15. .header {
    16. width: 100%;
    17. height: 35px;
    18. position: relative;
    19. display: flex;
    20. align-items: center;
    21. justify-content: space-between;
    22. background-color: #ffffff9c;
    23. -webkit-app-region: drag;
    24. z-index: 99;
    25. img {
    26. width: 30px;
    27. height: 30px;
    28. /* border-radius: 50%; */
    29. margin: 8px 0 0px 5px;
    30. -webkit-app-region: no-drag;
    31. transition: transform 0.3s ease;
    32. &:hover {
    33. transform: scale(1.2);
    34. }
    35. }
    36. button {
    37. font-size: 1.5rem;
    38. -webkit-app-region: no-drag;
    39. background-color: hsla(160, 100%, 37%, 0);
    40. &:hover {
    41. background-color: hsla(160, 100%, 37%, 0.445);
    42. }
    43. }
    44. iframe {
    45. -webkit-app-region: no-drag;
    46. }
    47. span {
    48. min-width: 110px;
    49. i {
    50. cursor: pointer;
    51. img {
    52. width: 30px;
    53. height: 30px;
    54. &:hover {
    55. background-color: hsla(0, 100%, 50%, 0.489);
    56. }
    57. }
    58. }
    59. }
    60. }
    61. /* 拖动窗口的样式 */
    62. .draggable-form {
    63. position: absolute;
    64. /* 最小宽度 */
    65. min-width: 50%;
    66. border-radius: 8px;
    67. background-color: rgba(0, 0, 0, 0.443);
    68. z-index: 199;
    69. box-shadow: 0 0 10px rgba(255, 254, 254, 0.5);
    70. }
    71. .form-title {
    72. text-align: center;
    73. padding: 5px;
    74. color: hsla(160, 100%, 37%, 1);
    75. box-shadow: 0 0 3px rgba(255, 255, 255, 0.751);
    76. border-radius: 5px 5px 0 0;
    77. cursor: move;
    78. }
    79. .form-content {
    80. display: flex;
    81. margin: 2px 5px 5px 5px;
    82. box-shadow: 0 0 3px rgba(255, 255, 255, 0.751);
    83. border-radius: 0 0 5px 5px;
    84. input,
    85. button {
    86. font-size: 1.5rem;
    87. /* 文本竖排 */
    88. writing-mode: vertical-rl;
    89. /* 文字间距 */
    90. letter-spacing: 10px;
    91. }
    92. input {
    93. border-bottom-left-radius: 5px;
    94. }
    95. button {
    96. border-bottom-right-radius: 5px;
    97. }
    98. textarea {
    99. flex: 1;
    100. font-size: 1rem;
    101. background-color: rgba(0, 0, 0, 0.308);
    102. color: rgb(255, 255, 255);
    103. text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
    104. &::placeholder {
    105. text-align: center;
    106. }
    107. }
    108. }
    109. /* 文本显示区样式 */
    110. .memo {
    111. display: flex;
    112. align-content: flex-start;
    113. flex-wrap: wrap;
    114. margin: 0 20px;
    115. }
    116. .item {
    117. margin: 5px 10px;
    118. padding: 0 5px;
    119. border-radius: 10px;
    120. box-shadow: 0 0 10px rgba(255, 254, 254, 0.5);
    121. display: flex;
    122. align-items: center;
    123. &:hover {
    124. box-shadow: 0 0 15px rgba(255, 254, 254, 0.5);
    125. }
    126. .alter {
    127. position: absolute;
    128. min-width: 50%;
    129. display: flex;
    130. top: 100px;
    131. textarea {
    132. flex: 1;
    133. font-size: 1rem;
    134. color: #f85f5faf;
    135. text-shadow: 1px 1px 1px #030303;
    136. background-color: hsla(160, 96%, 18%, 0.952);
    137. box-shadow:
    138. inset -2px -2px 3px rgba(255, 255, 255, 0.6),
    139. inset 2px 2px 3px rgba(0, 0, 0, 0.6);
    140. border-radius: 10px 0 0 10px;
    141. }
    142. button {
    143. font-size: 1.5rem;
    144. /* 文本竖排 */
    145. writing-mode: vertical-rl;
    146. /* 文字间距 */
    147. letter-spacing: 10px;
    148. border-radius:0 5px 5px 0;
    149. }
    150. }
    151. }
    152. .item-number {
    153. /* 粗字体 */
    154. font-weight: bold;
    155. color: #fff;
    156. text-shadow: 1px 1px 1px #030303;
    157. /* 背景颜色 */
    158. background-color: #fbff06b6;
    159. border-radius: 20px;
    160. }
    161. .text-content {
    162. color: #1ded39a0;
    163. text-shadow: 1px 1px 1px #030303;
    164. background-color: #144756;
    165. border-radius: 10px;
    166. user-select: text;
    167. padding: 0 5px;
    168. &:hover {
    169. color: rgb(255, 250, 250);
    170. text-shadow: 1px 1px 1px #030303;
    171. background-color: rgb(191, 210, 255);
    172. }
    173. }
    174. /* 点击完成按钮显示.finish样式 */
    175. .finish {
    176. /* 文本-装饰:删除线 */
    177. text-decoration: line-through;
    178. color: #f85f5faf;
    179. background-color: hsla(160, 100%, 37%, 0.2);
    180. text-shadow: 1px 1px 1px #030303;
    181. box-shadow:
    182. inset -2px -2px 3px rgba(255, 255, 255, 0.6),
    183. inset 2px 2px 3px rgba(0, 0, 0, 0.6);
    184. border-radius: 10px;
    185. }
    186. /* 删除按钮样式 */
    187. .deleteBtn {
    188. color: #f3d303;
    189. text-shadow: 1px 1px 1px rgb(0, 0, 0);
    190. background: #ff0000;
    191. border-radius: 5px;
    192. border: none;
    193. margin: 5px;
    194. padding: 2px;
    195. /* 粗体 */
    196. font-weight: bold;
    197. &:hover {
    198. background-color: #f3d303;
    199. color: #ff0505;
    200. }
    201. }

     main.css

    1. @import './base.css';
    2. /* 全局样式 */
    3. * {
    4. margin: 0;
    5. padding: 0;
    6. box-sizing: border-box;
    7. user-select: none;
    8. }
    9. body {
    10. min-height: 100vh;
    11. color: var(--color-text);
    12. background: var(--color-background);
    13. background-image: url('../img/wavy-lines.svg');
    14. background-size: cover;
    15. line-height: 1.6;
    16. font-family:
    17. Inter,
    18. -apple-system,
    19. BlinkMacSystemFont,
    20. 'Segoe UI',
    21. Roboto,
    22. Oxygen,
    23. Ubuntu,
    24. Cantarell,
    25. 'Fira Sans',
    26. 'Droid Sans',
    27. 'Helvetica Neue',
    28. sans-serif;
    29. text-rendering: optimizeLegibility;
    30. -webkit-font-smoothing: antialiased;
    31. -moz-osx-font-smoothing: grayscale;
    32. }

    base.css

    1. :root {
    2. --ev-c-white: #ffffff;
    3. --ev-c-white-soft: #f8f8f8;
    4. --ev-c-white-mute: #f2f2f2;
    5. --ev-c-black: #1b1b1f;
    6. --ev-c-black-soft: #222222;
    7. --ev-c-black-mute: #282828;
    8. --ev-c-gray-1: #515c67;
    9. --ev-c-gray-2: #414853;
    10. --ev-c-gray-3: #32363f;
    11. --ev-c-text-1: rgba(255, 255, 245, 0.86);
    12. --ev-c-text-2: rgba(235, 235, 245, 0.6);
    13. --ev-c-text-3: rgba(235, 235, 245, 0.38);
    14. --ev-button-alt-border: transparent;
    15. --ev-button-alt-text: var(--ev-c-text-1);
    16. --ev-button-alt-bg: var(--ev-c-gray-3);
    17. --ev-button-alt-hover-border: transparent;
    18. --ev-button-alt-hover-text: var(--ev-c-text-1);
    19. --ev-button-alt-hover-bg: var(--ev-c-gray-2);
    20. --color-background: var(--ev-c-black);
    21. --color-background-soft: var(--ev-c-black-soft);
    22. --color-background-mute: var(--ev-c-black-mute);
    23. --color-text: var(--ev-c-text-1);
    24. }

  • 相关阅读:
    2022年在湖北考的建设厅七大员可以全国通用吗?甘建二
    Linux新特性之btrfs文件系统
    开机时出现Windows will now check the disk怎么办
    Slope compensation
    SimpleServletHandlerAdapter类简介说明
    Service Mesh之Istio部署bookinfo
    HDFS机架感知配置(block放置策略/NodeGroup分配策略配置)
    Linux中vim编译器
    vue2和vue3的区别
    【浅学Java】哈希桶的模拟实现以及HashMap原码分析
  • 原文地址:https://blog.csdn.net/lulei5153/article/details/139712581