普通视图

发现新文章,点击刷新页面。
昨天 — 2025年1月17日首页

Electron发送数据到后端(15)

作者 关山月
2025年1月17日 21:18

Electron应用程序有前端进程(称为“renderer”)和后端进程(称为“main”)。在这两者之间还有一些桥接代码(“preload”),可以访问后端API。

到目前为止,我们完全忽略了后端进程,在前端和预加载中完成了所有工作。

让我们看看后端和前端如何通信。

启动新应用程序

让我们做点什么。创建一个新的项目:

$ npm init -y
$ npm install --save-dev electron

index.html

让我们从一个简单的index.html开始。

<!DOCTYPE html>
<html>
  <body>
    <style>
      body {
        background-color: #444;
        color: #ccc;
        font-family: monospace;
        font-size: 24px;
      }
      form {
        display: flex;
      }
      input {
        background-color: inherit;
        color: inherit;
        font-family: inherit;
        border: none;
        font-size: inherit;
        flex: 1;
      }
    </style>
    <h1>Print to terminal</h1>
    <form>
      <input type="text" autofocus />
    </form>
    <div id="responses"></div>
    <script src="app.js"></script>
  </body>
</html>

后端代码index.js

我们可以像以前一样。稍后我们将在这个文件中添加一个额外的东西。现在,让我们打开index.html并赋予它完全的权限:

let { app, BrowserWindow } = require("electron")

function createWindow() {
  let win = new BrowserWindow({
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
    }
  })
  win.loadFile("index.html")
}

app.on("ready", createWindow)

app.on("window-all-closed", () => {
  app.quit()
})

前端代码app.js

在前端,我们需要一个事件处理程序。我们获取提交的数据,将其发送到后端,获取其响应,并将其附加到#responses

let form = document.querySelector("form")
let input = document.querySelector("input")
let responses = document.querySelector("#responses")

form.addEventListener("submit", async (e) => {
  e.preventDefault()
  let line = input.value
  input.value = ""
  let responseText = // what do we do here?
  let response = document.createElement("div")
  response.textContent = responseText
  responses.appendChild(response)
})

我们如何将数据发送到后端?具体操作如下:

let { ipcRenderer } = require("electron")

let form = document.querySelector("form")
let input = document.querySelector("input")
let responses = document.querySelector("#responses")

form.addEventListener("submit", async (e) => {
  e.preventDefault()
  let line = input.value
  input.value = ""
  let responseText = await ipcRenderer.invoke("console", line)
  let response = document.createElement("div")
  response.textContent = responseText
  responses.appendChild(response)
})

IPC是“进程间通信”,或者说是不同进程之间进行通信的一种方式。

后端处理程序

let { ipcMain } = require("electron")

ipcMain.handle("console", (event, line) => {
  console.log(`Received from frontend: ${line}`)
  return `Backend confirms it received: ${line}`
})

结果

运行:

npx electron .  

代码:github.com/fengjutian/…

原文:dev.to/taw/electro…

使用 Tailwind CSS 和 JavaScript 构建延迟加载图片

作者 关山月
2025年1月16日 19:14

什么是延迟加载?

延迟加载是一种性能优化技术,图像在进入(或即将进入)视口时加载。

延迟加载图像的用例

延迟加载在以下情况下特别有用:

  • 图像库:显示大量图像时,延迟加载确保仅加载视图中的图像,从而防止加载时间过长并节省带宽。
  • 长页面:在内容较多的页面上,延迟加载通过在用户滚动时加载图像来帮助缩短页面加载时间。
  • 移动优化:对于使用较慢网络或移动设备的用户,延迟加载可确保他们只下载必要的内容,从而保留数据并改善浏览体验。
  • 渐进式 Web 应用程序 (PWA): 延迟加载有助于提高 PWA 的性能。

编写标记

<div
   id="gallery"
   class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
   <!-- Images will be dynamically inserted here -->
</div>

编写 JavaScript

创建图像元素

我们将使用 createImageElement 函数动态创建图像元素。

const gallery = document.getElementById("gallery");
const imageUrls = [
   "https://images.unsplash.com/photo-1543610892-0b1f7e6d8ac1?q=80&w=1856&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1516914943479-89db7d9ae7f2?q=80&w=2732&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1531384698654-7f6e477ca221?q=80&w=2800&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1531901599143-df5010ab9438?q=80&w=2787&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1524255684952-d7185b509571?q=80&w=2787&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1588175996685-a40693ee1087?q=80&w=2864&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1624561172888-ac93c696e10c?q=80&w=2592&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1489424731084-a5d8b219a5bb?q=80&w=2787&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
];

createImageElement 函数

此函数采用两个参数:图像的 URL 和数组中图像的索引。它返回一个包含图像的新 div 元素。

function createImageElement(url, index) {
  const div = document.createElement("div");
  div.className = "relative overflow-hidden   aspect-w-16 aspect-h-9";
  const img = document.createElement("img");
  img.className =
    "lazy-image w-full h-full object-cover transition-opacity duration-300 opacity-0";
  img.dataset.src = url;
  img.alt = `Image ${index + 1}`;
  const placeholder = document.createElement("div");
  placeholder.className = "absolute inset-0 bg-base-200 animate-pulse w-full h-full";
  div.appendChild(placeholder);
  div.appendChild(img);
  return div;
}

lazyLoad 函数

该函数使用 IntersectionObserver API 来观察类为 lazy-imageimg 元素。当类为 lazy-image 的元素与视口相交时,该元素的 src 属性会设置为 dataset.src 属性的值,并触发 onload 事件。

function lazyLoad() {
   const images = document.querySelectorAll("img.lazy-image");
   const options = {
      root: null,
      rootMargin: "0px",
      threshold: 0.1,
   };
   const imageObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach((entry) => {
         if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            img.onload = () => {
               img.classList.remove("opacity-0");
               img.previousElementSibling.remove(); // Remove placeholder
            };
            observer.unobserve(img);
         }
      });
   }, options);
   images.forEach((img) => imageObserver.observe(img));
}

创建和追加图像元素

我们将使用 createImageElement 函数创建图像元素并将其附加到库中。我们还将通过调用 lazyLoad 函数来初始化延迟加载。

// Create and append image elements
imageUrls.forEach((url, index) => {
   const imageElement = createImageElement(url, index);
   gallery.appendChild(imageElement);
});
// Initialize lazy loading
lazyLoad();

全部代码

const gallery = document.getElementById("gallery");
const imageUrls = [
   "https://images.unsplash.com/photo-1543610892-0b1f7e6d8ac1?q=80&w=1856&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1516914943479-89db7d9ae7f2?q=80&w=2732&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1531384698654-7f6e477ca221?q=80&w=2800&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1531901599143-df5010ab9438?q=80&w=2787&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1524255684952-d7185b509571?q=80&w=2787&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1588175996685-a40693ee1087?q=80&w=2864&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1624561172888-ac93c696e10c?q=80&w=2592&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
   "https://images.unsplash.com/photo-1489424731084-a5d8b219a5bb?q=80&w=2787&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
];

function createImageElement(url, index) {
   const div = document.createElement("div");
   div.className = "relative overflow-hidden   aspect-w-16 aspect-h-9";
   const img = document.createElement("img");
   img.className =
      "lazy-image w-full h-full object-cover transition-opacity duration-300 opacity-0";
   img.dataset.src = url;
   img.alt = `Image ${index + 1}`;
   const placeholder = document.createElement("div");
   placeholder.className = "absolute inset-0 bg-base-200 animate-pulse w-full h-full";
   div.appendChild(placeholder);
   div.appendChild(img);
   return div;
}

function lazyLoad() {
   const images = document.querySelectorAll("img.lazy-image");
   const options = {
      root: null,
      rootMargin: "0px",
      threshold: 0.1,
   };
   const imageObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach((entry) => {
         if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            img.onload = () => {
               img.classList.remove("opacity-0");
               img.previousElementSibling.remove(); // Remove placeholder
            };
            observer.unobserve(img);
         }
      });
   }, options);
   images.forEach((img) => imageObserver.observe(img));
}
// Create and append image elements
imageUrls.forEach((url, index) => {
   const imageElement = createImageElement(url, index);
   gallery.appendChild(imageElement);
});
// Initialize lazy loading
lazyLoad();

原文:lexingtonthemes.com/tutorials/h…

❌
❌