从js文件更新表Electron

cedebl8k  于 5个月前  发布在  Electron
关注(0)|答案(1)|浏览(65)

我尝试用从纺织品读取的数据更新一个表格。文本文件被正确读取并插入到构造函数中。但是HTML中的表格没有更新。为什么会这样?我如何修复它?不是包含表格的html文件不是运行Electron应用时呈现的根视图。
有一个主页,我从主页导航到这个食谱页面。我不确定这是否是原因。但这就是为什么我添加了一个超时功能,以便在运行func之前给予时间导航到正确的视图。

const { app, BrowserWindow, ipcMain } = require('electron');
const fs = require('fs');

// Mark ALL Constructors
class Recipe {
  constructor() {
    this.instructions = [];
    this.image = 'path';
    this.ingredients = [];
    this.description = '';
    this.nutrition_facts = [];
    this.cuisine = '';
    this.favorite = false;
    this.restrictions = [];
    this.difficulty = 0;
    this.review = '';
  }
}

var recipeArray = []; // store all recipes

function read_file(filePath) {
  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
      console.error(err);
      return;
    }

    const lines = data.split('\n');
    const recipe = new Recipe();
    // I trim all of them to get rid of whitespaces around
    recipe.description = lines[0].trim();
    recipe.ingredients = lines[1].split(',').map(item => item.trim());
    recipe.image = lines[2].trim();
    recipe.nutrition_facts = lines[3].trim().split(',').map(item => item.trim());
    recipe.cuisine = lines[4].trim();
    recipe.favorite = lines[5].trim() === 'true'; // check to make sure type right and equal to true if not its auto gonna be false
    recipe.restrictions = lines[6].split(',').map(item => item.trim());
    recipe.difficulty = parseInt(lines[7].trim(), 10);
    recipe.review = lines[8].trim(); // should this be int like 8/10 or string?

    // instructions can be any length starting from the 9th line
    for (let i = 9; i < lines.length; i++) {
      recipe.instructions.push(lines[i].trim());
    }
    recipeArray.push(recipe);

    // Send the parsed recipe to the renderer process
    mainWindow.webContents.send('recipeData', recipe);
  });
}

function populateRecipies(fileName) {
  const filePath = __dirname + '/' + fileName;
  read_file(filePath);
}

let mainWindow;

const createWindow = () => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
  });

  mainWindow.loadFile('index.html');

  mainWindow.webContents.once('dom-ready', () => {
    // Access the document object after the DOM is ready
    setTimeout(() => {
      populateRecipies('testRecipe.txt');
    }, 10000);
  });
};

app.whenReady().then(() => {
  createWindow();
});

// Quit the app when all windows are closed (except on macOS)
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

// Create a new window when the app is activated (on macOS)
app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

个字符

更新

const createWindow = () => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false, // THIS FIXES THE ISSUES>
    },
  });

  mainWindow.loadFile('index.html');

  mainWindow.webContents.once('dom-ready', () => {
    setTimeout(() => {
      console.log("dd");
      populateRecipies('testRecipe.txt');
    }, 10000);
  });

  ipcMain.on('recipePageReady', () => {
    console.log("called");
    populateRecipies('testRecipe.txt');
  });
};

gupuwyp2

gupuwyp21#

首先,确保ipcRenderer正确导入到HTML文件中。您的HTML代码段没有显示ipcRenderer的导入。将这一行添加到HTML中的脚本标记中:

<script>
const { ipcRenderer } = require('electron');
// rest of your script
</script>

字符串
在脚本尝试操作DOM之前,请确保DOM已完全加载。这通常通过将脚本标记放置在主体的末尾或使用DOMContentLoaded event来完成。在updateTable函数中添加错误处理,以捕获更新DOM时可能发生的任何问题。
确保mainWindow是对HTML表所在窗口的正确引用。
更一般地说,考虑use of setTimeout is unreliable用于等待导航。最好在配方页面准备就绪时触发数据发送。考虑使用IPC消息来通知何时发送数据。
在你的主进程中,你可以设置一个IPC监听器来等待一个指示配方页面已经准备好的信号。在接收到这个信号后,你可以 * 然后 * 调用populateRecipies函数来发送配方数据到渲染器进程。
在主进程中更新createWindow函数,如下所示:

const createWindow = () => {
  // existing code to create mainWindow 

  ipcMain.on('recipePageReady', () => {
    populateRecipies('testRecipe.txt');
  });
};


在你的渲染器进程中(配方页面HTML/JavaScript),一旦页面准备好了,你就需要向主进程发送一个信号。这可以通过向主进程发送一个IPC消息来完成。

<script>
  // existing code 

  document.addEventListener('DOMContentLoaded', (event) => {
    ipcRenderer.send('recipePageReady');
  });
</script>


你会得到工作流程:

[ Electron Main Process ]
   |__ [ BrowserWindow ] -- Loads --> [ index.html ]
   |__ [ ipcMain.on('recipePageReady', ...) ] -- Waits for signal from renderer

[ Renderer Process (Recipe Page) ]
   |__ [ DOMContentLoaded ] -- Page is ready, Sends IPC --> [ 'recipePageReady' ]
   |__ [ ipcRenderer.on('recipeData', ...) ] -- Receives --> [ Recipe Data ]
   |__ [ updateTable() ] -- Updates --> [ HTML Table ]


正如the OP ahmed在评论中所指出的,集成Electron主进程和渲染器进程的关键,特别是在使用某些Electron API(如ipcRenderer)时,是BrowserWindow对象的webPreferences中的contextIsolation: false设置。

**context isolation**是Electron中的一个安全功能,它将主世界(您的JavaScript)与渲染器世界(内部Electron代码)隔离开来。

contextIsolationtrue时,它会阻止渲染器直接访问Electron的内部API。出于安全原因,建议这样做,但可能会使某些集成更加复杂。
contextIsolation: false禁用上下文隔离,这允许渲染器脚本直接访问Electron API(如ipcRenderer)。这可以简化代码,但它不太安全,因为它将Electron API和潜在的Node.js API暴露给渲染器进程。
更新后的createWindow函数,如OP所提供的,看起来像:

const createWindow = () => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false, // Disable context isolation
    },
  });

  mainWindow.loadFile('index.html');

  mainWindow.webContents.once('dom-ready', () => {
    setTimeout(() => {
      console.log("dd");
      populateRecipies('testRecipe.txt');
    }, 10000);
  });

  ipcMain.on('recipePageReady', () => {
    console.log("called");
    populateRecipies('testRecipe.txt');
  });
};


虽然设置contextIsolation: false解决了在主进程和渲染进程之间集成IPC通信的直接问题,但重要的是要意识到安全问题。在生产应用程序中,特别是加载远程内容的应用程序中,建议保持contextIsolation启用状态,并使用安全方法仅将主进程所需的内容公开给渲染进程。
此外,您可能需要评估是否应该启用nodeIntegration,因为这会将Node.js API暴露给渲染器进程,如果不小心处理,可能会带来安全风险。

相关问题