// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// No Node.js APIs are available in this process because
// `nodeIntegration` is turned off. Use `preload.js` to
// selectively enable features needed in the rendering
// process.
const jQuery = (window.jQuery = require('jquery'));
require('@popperjs/core');
require('bootstrap');
const Vue = require('vue/dist/vue');
const electron = require('electron');
const fs = require('fs');
const SCREEN_WIDTH = 3072;
const SCREEN_HEIGHT = 1920;
const PlayerCanvas = require('./PlayerCanvas');
new Vue({
el: '#vueapp',
data: {
recording: false,
mounted() {
this._playerCanvas = new PlayerCanvas(SCREEN_WIDTH, SCREEN_HEIGHT);
methods: {
// 开始录制
async btnStartRecordClicked(e) {
this._stream = new MediaStream();
await this.attachAudioStream();
// 摄像头 stream
this._cameraStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: false,
this._playerCanvas.setCameraVideo(
this.createVideoElementWithStream(this._cameraStream)
// 屏幕 stream
this._screenStream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
minWidth: SCREEN_WIDTH,
maxWidth: SCREEN_WIDTH,
minHeight: SCREEN_HEIGHT,
maxHeight: SCREEN_HEIGHT,
this._playerCanvas.setScreenVideo(
this.createVideoElementWithStream(this._screenStream)
this._audioStream
.getAudioTracks()
.forEach((value) => this._stream.addTrack(value));
let playerCanvasStream = this._playerCanvas.canvas.captureStream();
playerCanvasStream.getTracks().forEach((t) => this._stream.addTrack(t));
this.$refs.preview.srcObject = playerCanvasStream;
this.startRecord();
// 附加音频流
async attachAudioStream() {
// 获取麦克风流
this._audioStream = await navigator.mediaDevices.getUserMedia({
video: false,
audio: true,
// 将麦克风的流,附加到主流上
this._audioStream
.getAudioTracks()
.forEach((value) => this._stream.addTrack(value));
// 停止录制
btnStopRecordClicked(e) {
this.recording = false;
this._recorder.stop();
// 创建一个 HTMLVideoElement
createVideoElementWithStream(stream) {
let video = document.createElement('video');
video.autoplay = true;
video.srcObject = stream;
return video;
// 开始录制
startRecord() {
this._recorder = new MediaRecorder(this._stream, {
mimeType: 'video/webm;codes=h264',
this._recorder.ondataavailable = async (e) => {
let path = electron.remote.dialog.showSaveDialogSync(
electron.remote.getCurrentWindow(),
title: '保存文件',
defaultPath: 'ScreenData.webm',
let dataArrayBuffer = await e.data.arrayBuffer();
fs.writeFileSync(path, Buffer.from(dataArrayBuffer));
// fs.writeFileSync(path, new Uint8Array(dataArrayBuffer));
this._recorder.start();
this.recording = true;
const jQuery = (window.jQuery = require('jquery'));
require('@popperjs/core');
require('bootstrap');
const Vue = require('vue/dist/vue');
const electron = require('electron');
const fs = require('fs');
new Vue({
el: '#vueapp',
data: {
recording: false,
methods: {
async btnStartRecordClicked(e) {
this._stream = await navigator.mediaDevices.getUserMedia({
video: false,
audio: true,
let screenStream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
minWidth: 3072,
maxWidth: 3072,
minHeight: 1920,
maxHeight: 1920,
screenStream
.getVideoTracks()
.forEach((value) => this._stream.addTrack(value));
this.$refs.preview.srcObject = screenStream;
this._recorder = new MediaRecorder(this._stream, {
mimeType: 'video/webm;codes=h264',
this._recorder.ondataavailable = async (e) => {
let path = electron.remote.dialog.showSaveDialogSync(
electron.remote.getCurrentWindow(),
title: '保存文件',
defaultPath: 'ScreenData.webm',
let dataArrayBuffer = await e.data.arrayBuffer();
fs.writeFileSync(path, Buffer.from(dataArrayBuffer));
// fs.writeFileSync(path, new Uint8Array(dataArrayBuffer));
this._recorder.start();
this.recording = true;
btnStopRecordClicked(e) {
this.recording = false;
this._recorder.stop();
源码下载:
分类: Web Web 前端标签 Electron, Web, 屏幕录制
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true, // 这行代码必须加进去,不然渲染进程无法访问 nodejs,electron 的资源
然后在 package.json 文件中加入配置
-
"main":"./src/electron/main.js"
其中的路径为你的 main.js 路径配置。 "homepage": "./"
表示请求资源用相对路径,否则打包之后请求不到js,css资源
继续:引入 electron-is-dev 包
npm install electron-is-dev --save
这个包用于判断当前运行环境是开发环境还是生产环境,在 main.js 中,我们这里加一个判断:
继续:引入 concurrently 包
npm install concurrently --save
这个包用于同时启动多个服务用
继续:引入 wait-on 包
npm install wait-on --save
用于启动等待命令
const isDev = require('electron-is-dev')
const path = require('path')
if (isDev) {
win.loadURL('http://localhost:3000')
} else {
win.loadFile(path.join(__dirname, '../build/index.html'))
路劲为 main.js
相对 build
文件夹(React打出来的包文件夹)的路径。
可选配置(没有也没关系):
修改package.json,添加一个electron-dev脚本命令:
"scripts": {
"dev": "concurrently \"BROWSER=none react-scripts start\" \"wait-on http://localhost:3000 && electron .\"",
这样就可以直接 npm run dev 开启调试模式,不用单独再运行 React 和 Electron。
以上,即可:npm run dev
运行程序
分类: Web 前端标签 Electron, React
<title>vest</title>
<% if (htmlWebpackPlugin.options.nodeModules) { %>
<!-- Add `node_modules/` to global paths so `require` works properly in development -->
<script>
require('module').globalPaths.push('<%= htmlWebpackPlugin.options.nodeModules.replace(/\\/g, '\\\\') %>')
</script>
<% } %>
</head>
<div id="app"></div>
<!-- Set `__static` path to static files in production -->
<% if (!require('process').browser) { %>
<script>
if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
</script>
<% } %>
<!-- webpack builds are automatically injected -->
</body>
</html>
以上代码,覆盖到 index.ejs
文件即可。
分类: Web 前端标签 Electron, Vue