Init
This commit is contained in:
250
07-Other/Node.js/Electron/Electron笔记.md
Normal file
250
07-Other/Node.js/Electron/Electron笔记.md
Normal file
@@ -0,0 +1,250 @@
|
||||
## Electron Quick Start
|
||||
```
|
||||
# 克隆这仓库
|
||||
$ git clone https://github.com/electron/electron-quick-start
|
||||
# 进入仓库
|
||||
$ cd electron-quick-start
|
||||
# 安装依赖库
|
||||
$ npm install
|
||||
# 运行应用
|
||||
$ npm start
|
||||
```
|
||||
|
||||
## 使用IPC进行GUI与原生APP进行通讯
|
||||
在main.js里添加下面的代码,从通道订阅消息:
|
||||
```
|
||||
var ipc = require('ipc');
|
||||
ipc.on('close-main-window', function () {
|
||||
app.quit();
|
||||
});
|
||||
```
|
||||
引入ipc模块后,通过通道订阅消息就变得很简单,on()方法设置订阅的通道名,定义回调函数。
|
||||
|
||||
渲染进程要通过通道发送消息,将下面代码加入index.js:
|
||||
```
|
||||
var ipc = require('ipc');
|
||||
var closeEl = document.querySelector('.close');
|
||||
closeEl.addEventListener('click', function () {
|
||||
ipc.send('close-main-window');
|
||||
});
|
||||
```
|
||||
同样,我们引入ipc模块,给关闭按钮的元素绑定一个click事件。当点击关闭按钮时,通过「close-main-window」通道的send()方法发送消息。
|
||||
|
||||
## 全局快捷键
|
||||
```
|
||||
var globalShortcut = require('global-shortcut');
|
||||
app.on('ready', function() {
|
||||
... // existing code from earlier
|
||||
globalShortcut.register('ctrl+shift+1', function () {
|
||||
mainWindow.webContents.send('global-shortcut', 0);
|
||||
});
|
||||
globalShortcut.register('ctrl+shift+2', function () {
|
||||
mainWindow.webContents.send('global-shortcut', 1);
|
||||
});
|
||||
});
|
||||
```
|
||||
```
|
||||
ipc.on('global-shortcut', function (arg) {
|
||||
var event = new MouseEvent('click');
|
||||
soundButtons[arg].dispatchEvent(event);
|
||||
});
|
||||
```
|
||||
## 保存用户配置
|
||||
使用nconf模块
|
||||
```
|
||||
npm install --save nconf
|
||||
```
|
||||
```
|
||||
|
||||
var nconf = require('nconf').file({file: getUserHome() + '/sound-machine-config.json'});
|
||||
|
||||
function saveSettings(settingKey, settingValue) {
|
||||
nconf.set(settingKey, settingValue);
|
||||
nconf.save();
|
||||
}
|
||||
|
||||
function readSettings(settingKey) {
|
||||
nconf.load();
|
||||
return nconf.get(settingKey);
|
||||
}
|
||||
|
||||
function getUserHome() {
|
||||
return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
saveSettings: saveSettings,
|
||||
readSettings: readSettings
|
||||
};
|
||||
```
|
||||
## 系统托盘
|
||||
```
|
||||
var remote = require('remote');
|
||||
var Tray = remote.require('tray');
|
||||
var Menu = remote.require('menu');
|
||||
var path = require('path');
|
||||
|
||||
var trayIcon = null;
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
trayIcon = new Tray(path.join(__dirname, 'img/tray-iconTemplate.png'));
|
||||
}
|
||||
else {
|
||||
trayIcon = new Tray(path.join(__dirname, 'img/tray-icon-alt.png'));
|
||||
}
|
||||
|
||||
var trayMenuTemplate = [
|
||||
{
|
||||
label: 'Sound machine',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
click: function () {
|
||||
ipc.send('open-settings-window');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
click: function () {
|
||||
ipc.send('close-main-window');
|
||||
}
|
||||
}
|
||||
];
|
||||
var trayMenu = Menu.buildFromTemplate(trayMenuTemplate);
|
||||
trayIcon.setContextMenu(trayMenu);
|
||||
```
|
||||
|
||||
## 打包应用
|
||||
>摘自https://www.jianshu.com/p/f134878af30f
|
||||
|
||||
安装electron-package
|
||||
```
|
||||
npm install electron-package --save-dev
|
||||
```
|
||||
添加scrip命令 ,用于打包electron app。
|
||||
```
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"build": "electron-packager . hello_electron --platform=darwin --arch=x64 --ignore=node_modules/electron-*",
|
||||
},
|
||||
```
|
||||
**electron-packager命令格式**
|
||||
```
|
||||
electron-packager 项目目录 app名称 --platform=平台 --arch=架构 --ignore=要忽略的目录或文件
|
||||
arch
|
||||
ia32 , x64 , armv7l , all
|
||||
|
||||
plateform
|
||||
linux , win32 , darwin , mas , all
|
||||
|
||||
OS X (also known as darwin)
|
||||
Mac App Store (also known as mas)
|
||||
```
|
||||
执行命令npm run build,将得到如下结果
|
||||
|
||||
### electron-builder与electron-packager的区别
|
||||
使用electron-builder打包应用是安装包方式,而不想electron-packager打包之后直接是一个可文件夹,交给所有的文件暴露出来。由electron-builder打出的包更为轻量,并且可以打包出不暴露源码的setup安装程序
|
||||
|
||||
## 压缩源码
|
||||
为避免源代码泄露,可对源码进行压缩。
|
||||
|
||||
**安装electron-asar**
|
||||
```
|
||||
npm install electron-asar --save-dev
|
||||
```
|
||||
**添加scrip命令 ,用于压缩源代码。**
|
||||
```
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"build": "electron-packager . hello_electron --platform=darwin --arch=x64 --ignore=node_modules/electron-*",
|
||||
"package":"asar pack hello_electron-darwin-x64/hello_electron.app/Contents/Resources/app hello_electron-darwin-x64/hello_electron.app/Contents/Resources/app.asar"
|
||||
},
|
||||
```
|
||||
**asar 命令格式**
|
||||
|
||||
asar pack <dir> <output>
|
||||
执行npm run package将得到app.asar文件,此时可将app文件删除。
|
||||
|
||||
## Electron启动node.js服务器
|
||||
1.直接在index.html中启动外部的node.js服务器
|
||||
2.将原生的node.js服务器代码使用module.exports = () => {}导出,之后在electron的main.js中直接导入
|
||||
```
|
||||
app.server = require(__dirname + '/app/app')();
|
||||
```
|
||||
|
||||
## 不迁移项目就可以打包双版本的可行方案
|
||||
作者并未提供web开发的支持,但是提供了非常好的web打包支持。
|
||||
只要写好逻辑我们可以不用迁移项目就可以打包桌面项目和web项目。
|
||||
|
||||
process.env.IS_WEB是暴露的一个全局变量,我们可以在渲染进程中获取,项目在electron环境下,返回false。否则为true。于此,我们可以通过设置她的值来达到web dev的效果,也可以处理不同环境的不同逻辑,一些示例:
|
||||

|
||||

|
||||

|
||||
|
||||
## 打开新窗口的“最佳”做法
|
||||
1.使用webview, allowpopups变量控制是否拦截新弹出的窗口
|
||||
|
||||
下面的例子,是webview允许.open/.showModalDialog/.showModelessDialog的例子:
|
||||
|
||||
electron的index.html:(重点是参数allowpopups)
|
||||
```
|
||||
<webview id="foo" src="https://newsn.net/test.html" allowpopups style="width:100%; height:360px;"></webview>
|
||||
```
|
||||
原文:https://newsn.net/say/electron-webview-window-open.html
|
||||
|
||||
2.因为是webpack配置,入口只有index.html ,所以打开新窗口,一般会再配置一个入口。其实还有一种更佳的做法。
|
||||
```
|
||||
>>> 主进程 定义好监听事件
|
||||
ipc.on('newPage', function(e) {
|
||||
const modalPath = process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:9080/#/newPage'
|
||||
: `file://${__dirname}/index.html#newPage`
|
||||
let win = new BrowserWindow({
|
||||
width: 1024,
|
||||
height: 724,
|
||||
webPreferences: {
|
||||
webSecurity: false
|
||||
}
|
||||
})
|
||||
win.on('close', function() {
|
||||
win = null
|
||||
})
|
||||
win.loadURL(modalPath)
|
||||
|
||||
})
|
||||
|
||||
>>> router/index.js 定义路由
|
||||
// import 你的新页面 .vue 文件
|
||||
{
|
||||
path: '/newPage',
|
||||
name: 'newPage',
|
||||
component: newPage,
|
||||
}
|
||||
|
||||
》》》配置完成 任意进程调用ipc.send('newPage') 完美解决
|
||||
```
|
||||
3.
|
||||
```
|
||||
document.getElementById("youtube").onclick = function(){
|
||||
|
||||
youtubeWindow = new BrowserWindow ({width: 1000, height:800})
|
||||
|
||||
youtubeWindow.loadURL("https://youtube.com/");
|
||||
|
||||
youtubeWindow.on("close", function(){
|
||||
youtubeWindow = null;
|
||||
})
|
||||
}
|
||||
|
||||
document.getElementById("local-list").onclick = function(){
|
||||
|
||||
localListWindow = new BrowserWindow ({width: 1000, height:800})
|
||||
|
||||
localListWindow.loadURL(`file://${__dirname}/local-list.html`);
|
||||
|
||||
localListWindow.on("close", function(){
|
||||
localListWindow = null;
|
||||
})
|
||||
}
|
||||
```
|
112
07-Other/Node.js/Electron/Vue-cli项目移植Electron-vue的相关经验.md
Normal file
112
07-Other/Node.js/Electron/Vue-cli项目移植Electron-vue的相关经验.md
Normal file
@@ -0,0 +1,112 @@
|
||||
## 移植经验
|
||||
1. 使用npm下载所有在vue-cli项目所使用的模块,比如element-ui、NProgress之类的。
|
||||
2. 将vue-cli项目中src目录下所有文件复制到electron-vue中对应目录。(不要直接覆盖main.js,因为electron-vue中有一些写法不同了,对于这个文件需要自己仔细移植,比如 Vue.use(require('vue-electron'))就与vue-cli不同)
|
||||
3. 运行npm run dev,解决报错问题。(主要是因为路径失效造成的问题)
|
||||
|
||||
## this.$router.push()报错then() undefined
|
||||
这有可能是因为你使用了动态加载路由,也就是在vue-router中使用了vuex,同时夹杂了Electron-vue模板里的东西。在electron-vue模板使用的store/index.js文件中调用了vuex-electron插件,而这些插件貌似会与结构起冲突,把这些东西删除了就好了。
|
||||
```
|
||||
// import { createPersistedState, createSharedMutations } from 'vuex-electron'
|
||||
|
||||
// plugins: [
|
||||
// createPersistedState(),
|
||||
// createSharedMutations()
|
||||
// ],
|
||||
```
|
||||
我使用的动态路由是修改自
|
||||
[PanJiaChen/vue-admin-template](https://note.youdao.com/)。该作者也做了个Electron的项目,同样是用Electron-vue模板,所以相当值得参考。
|
||||
|
||||
## 跨域问题
|
||||
我一开始也很疑惑,为啥electron-vue中为啥没有proxytable。后来发现的确没有必要。如果有,只可能是因为你的需求有问题。
|
||||
|
||||
vue-cli项目是将打包好的js、html等文件一起放到服务端中,之后通过浏览器来浏览。服务端和前端文件是放在一起的。所以为了解决前后端分离的问题,才使用跨域转发的方式来解决(开发模式需要跨,而生成模式就不需要)。而Electron开发与生成都需要跨,毕竟前端和服务端不在一起。所以也就不存在跨域问题,也就不需要ProxyTable了。
|
||||
|
||||
我的解决方法是这样:
|
||||
设置一个config.js作为全局设置文件。在里面设置一个变量用于存储本地服务器ip,之后在使用axios编写get与post接口的文件,将服务器ip变量加到接口地址前就可以了。例如
|
||||
```
|
||||
export const requestLogin = params => {return axios.post(`/login`,params).then(res => res.data); };
|
||||
```
|
||||
=>
|
||||
```
|
||||
//在config.js中,base为127.0.0.1:3000
|
||||
import {base} from '../config';
|
||||
export const requestLogin = params => {return axios.post(`${base}/login`,params).then(res => res.data); };
|
||||
```
|
||||
如果需要导出web版本,则可以使用process.env.IS_WEB来判断是否为web模式。
|
||||
|
||||
## 静态文件与启动本地服务问题
|
||||
之前曾想过在electron里直接导入服务端代码来运行服务器,但后来发现不行。github上代码都是通过electron(Node.js)的child_process来启动外部服务器的。
|
||||
|
||||
这里我使用pm2来启动,这样就不需要在程序关闭时关闭服务器了。(child_process 老是无法关闭服务器进程,不知道为什么)
|
||||
```
|
||||
let exec = require('child_process').exec;
|
||||
let server = exec("pm2 start ./bin/www", {cwd: process.cwd()+'/server'});
|
||||
```
|
||||
静态文件可以放再electron目录下的static文件夹中(之后会打包成asar文件),不过因为本人写的app需要定时更新文件,且文件类型较杂,所以使用本地服务端来管理静态文件。
|
||||
|
||||
于是对于项目中的需要显示图片或者其他文件链接就需要加入本地服务器ip地址,就像上一节那样。
|
||||
|
||||
## 打包后静态文件失效问题
|
||||
__dirname是Electron-vue中在webpack中配置的变量,对应开发模式与
|
||||
产品模式时的electron静态文件目录。但如果你使用了一些webpack中没有设置的文件(比如字体)会出一些问题,请参考这个blog
|
||||
https://blog.csdn.net/aa661020/article/details/79757859
|
||||
|
||||
## 关于自定义协议
|
||||
本人写的app使用了类似QQ的自定义协议来启动自己写的外部程序并传参,在electron中,为了安全的问题,默认把这个功能屏蔽了。electron中应该可以使用protocol来定义协议来解决问题,不过我找到了另一种方法,那就是直接使用child_process的exec,直接用命令行的方式来启动程序。
|
||||
|
||||
直接在渲染进程中(xxx.vue文件)
|
||||
```
|
||||
<script>
|
||||
const exec = require('child_process').exec;
|
||||
export default {
|
||||
methods: {
|
||||
exec(row){
|
||||
//s为自定义协议的字符串
|
||||
let s='xxxxxx';
|
||||
let url="test://"+ s;
|
||||
|
||||
//test为程序名,注意后面有空格,第二个参数中提供程序的运行位置,具体的可以参考node.js文档。
|
||||
exec("test "+url, {cwd: process.cwd()+'/XXXX'});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
不过需要注意,在中文windows系统(没有修改过默认字符集的),浏览器里通过自定义协议来启动程序默认传的是gbk的字符集。而不同系统(win10,win7)字符集是不同的。所以就需要对启动程序进行修改。
|
||||
|
||||
## 关于多条命令启动
|
||||
因为本人写的App需要更新数据库(mysql数据库),所以本人使用mysql的命令进行恢复数据。
|
||||
奇怪的是child_process的exec竟然不支持多条语句。所以这里我就使用了child_process的spawn。
|
||||
|
||||
多条命令之间使用&&间隔,具体的请参照cmd指南(还有别的间隔符,比如| &)
|
||||
|
||||
```
|
||||
let cmd='cd /d C:/Program Files/MySQL/MySQL Server 5.7/bin && mysql -uXXXXX -pXXXXX abcde </managersystem_user.sql && mysql -uXXXXX -pXXXXX abcde </abcde_xxxx.sql';
|
||||
|
||||
cmd+=" && mysql -uXXXXX -pXXXXX abcde < /abcde_routines.sql";
|
||||
|
||||
let child = spawn(cmd, {
|
||||
shell: true
|
||||
});
|
||||
//这里还可以输入新的命令与显示cmd返回内容,具体的请参考node.js文档
|
||||
child.on('exit', ()=> {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
## 关于启动参数
|
||||
```
|
||||
//在主进程中
|
||||
global.sharedObject = {prop1: process.argv}
|
||||
```
|
||||
```
|
||||
//渲染进程中
|
||||
var remote = require('electron').remote,
|
||||
arguments = remote.getGlobal('sharedObject').prop1;
|
||||
|
||||
console.log(arguments);
|
||||
```
|
||||
|
||||
## 最后推荐一下苏南大叔的blog
|
||||
里面有关electron的文章很不错
|
||||
https://newsn.net
|
@@ -0,0 +1,61 @@
|
||||
## 修改electron-packager代码
|
||||
首先确认electron-packager安装位置(全局或者局部),之后进入`node_modules\electron-packager\`路径。使用VSCode搜索`packageForPlatformAndArch`。代码如下:
|
||||
```c#
|
||||
packageForPlatformAndArch (downloadOpts) {
|
||||
return download.downloadElectronZip(downloadOpts)
|
||||
.then(zipPath => {
|
||||
// Create delegated options object with specific platform and arch, for output directory naming
|
||||
const comboOpts = Object.assign({}, this.opts, {
|
||||
arch: downloadOpts.arch,
|
||||
platform: downloadOpts.platform,
|
||||
electronVersion: downloadOpts.version
|
||||
})
|
||||
|
||||
if (!this.useTempDir) {
|
||||
return this.createApp(comboOpts, zipPath)
|
||||
}
|
||||
|
||||
if (common.isPlatformMac(comboOpts.platform)) {
|
||||
/* istanbul ignore else */
|
||||
if (this.canCreateSymlinks === undefined) {
|
||||
return this.testSymlink(comboOpts, zipPath)
|
||||
} else if (!this.canCreateSymlinks) {
|
||||
return this.skipHostPlatformSansSymlinkSupport(comboOpts)
|
||||
}
|
||||
}
|
||||
|
||||
return this.checkOverwrite(comboOpts, zipPath)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
添加逻辑:
|
||||
```
|
||||
let zipFile="electron-v11.2.1-win32-x64.zip";
|
||||
console.log(__dirname);
|
||||
let HasFile=fs.existsSync(zipFile);
|
||||
if(HasFile)
|
||||
{
|
||||
const comboOpts = Object.assign({}, this.opts, {
|
||||
arch: downloadOpts.arch,
|
||||
platform: downloadOpts.platform,
|
||||
electronVersion: downloadOpts.version
|
||||
})
|
||||
|
||||
if (!this.useTempDir) {
|
||||
return this.createApp(comboOpts, zipFile)
|
||||
}
|
||||
|
||||
if (common.isPlatformMac(comboOpts.platform)) {
|
||||
/* istanbul ignore else */
|
||||
if (this.canCreateSymlinks === undefined) {
|
||||
return this.testSymlink(comboOpts, zipFile)
|
||||
} else if (!this.canCreateSymlinks) {
|
||||
return this.skipHostPlatformSansSymlinkSupport(comboOpts)
|
||||
}
|
||||
}
|
||||
|
||||
return this.checkOverwrite(comboOpts, zipFile)
|
||||
}
|
||||
```
|
||||
其中执行路径即为项目根目录,直接将zip放在项目目录中即可。
|
18
07-Other/Node.js/H5 PPT与Node.js生成pptx方案.md
Normal file
18
07-Other/Node.js/H5 PPT与Node.js生成pptx方案.md
Normal file
@@ -0,0 +1,18 @@
|
||||
## H5 PPT
|
||||
https://revealjs.com/
|
||||
http://imakewebthings.com/deck.js/
|
||||
https://github.com/briancavalier/slides?spm=a2c6h.12873639.0.0.2c404409ftv46I
|
||||
https://github.com/LeaVerou/inspire.js?spm=a2c6h.12873639.0.0.2c404409ftv46I
|
||||
https://github.com/impress/impress.js/
|
||||
|
||||
VUE PPT插件
|
||||
https://github.com/faveeo/eagle.js
|
||||
|
||||
感觉revealjs的功能较多,但好像无法直接移植进入VUE。impressJS适合做商业演示,inspireJS适合比较简单的演示。
|
||||
|
||||
## Node.js生成pptx
|
||||
https://www.npmjs.com/package/ppt-template
|
||||
https://www.npmjs.com/package/nodejs-pptx
|
||||
https://www.npmjs.com/package/pptxgenjs
|
||||
|
||||
pptxgenjs用的人最多。
|
11
07-Other/Node.js/Node.js实现word文档生成以及word模板浏览器端实现下载文件.md
Normal file
11
07-Other/Node.js/Node.js实现word文档生成以及word模板浏览器端实现下载文件.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## word文档生成可以使用
|
||||
- docx:https://www.npmjs.com/package/docx
|
||||
|
||||
## word模板替换
|
||||
- generate-docx:https://github.com/telemark/generate-docx
|
||||
- carbone:https://github.com/carboneio/carbone
|
||||
- docxtemplater:https://www.npmjs.com/package/docxtemplater
|
||||
- docxtemplater-image-module-free:https://www.npmjs.com/package/docxtemplater-image-module-free
|
||||
|
||||
## 库
|
||||
FileSaver使用案例:https://jsfiddle.net/dolanmiu/onadx1gu/
|
168
07-Other/Node.js/Node.js的Mysql模块中的转义字符.md
Normal file
168
07-Other/Node.js/Node.js的Mysql模块中的转义字符.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# 以下摘自官方文档
|
||||
## Escaping query values
|
||||
**Caution** These methods of escaping values only works when the
|
||||
[NO_BACKSLASH_ESCAPES](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_backslash_escapes)
|
||||
SQL mode is disabled (which is the default state for MySQL servers).
|
||||
|
||||
In order to avoid SQL Injection attacks, you should always escape any user
|
||||
provided data before using it inside a SQL query. You can do so using the
|
||||
`mysql.escape()`, `connection.escape()` or `pool.escape()` methods:
|
||||
|
||||
```js
|
||||
var userId = 'some user provided value';
|
||||
var sql = 'SELECT * FROM users WHERE id = ' + connection.escape(userId);
|
||||
connection.query(sql, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Alternatively, you can use `?` characters as placeholders for values you would
|
||||
like to have escaped like this:
|
||||
|
||||
```js
|
||||
connection.query('SELECT * FROM users WHERE id = ?', [userId], function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Multiple placeholders are mapped to values in the same order as passed. For example,
|
||||
in the following query `foo` equals `a`, `bar` equals `b`, `baz` equals `c`, and
|
||||
`id` will be `userId`:
|
||||
|
||||
```js
|
||||
connection.query('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?', ['a', 'b', 'c', userId], function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
This looks similar to prepared statements in MySQL, however it really just uses
|
||||
the same `connection.escape()` method internally.
|
||||
|
||||
**Caution** This also differs from prepared statements in that all `?` are
|
||||
replaced, even those contained in comments and strings.
|
||||
|
||||
Different value types are escaped differently, here is how:
|
||||
|
||||
* Numbers are left untouched
|
||||
* Booleans are converted to `true` / `false`
|
||||
* Date objects are converted to `'YYYY-mm-dd HH:ii:ss'` strings
|
||||
* Buffers are converted to hex strings, e.g. `X'0fa5'`
|
||||
* Strings are safely escaped
|
||||
* Arrays are turned into list, e.g. `['a', 'b']` turns into `'a', 'b'`
|
||||
* Nested arrays are turned into grouped lists (for bulk inserts), e.g. `[['a',
|
||||
'b'], ['c', 'd']]` turns into `('a', 'b'), ('c', 'd')`
|
||||
* Objects that have a `toSqlString` method will have `.toSqlString()` called
|
||||
and the returned value is used as the raw SQL.
|
||||
* Objects are turned into `key = 'val'` pairs for each enumerable property on
|
||||
the object. If the property's value is a function, it is skipped; if the
|
||||
property's value is an object, toString() is called on it and the returned
|
||||
value is used.
|
||||
* `undefined` / `null` are converted to `NULL`
|
||||
* `NaN` / `Infinity` are left as-is. MySQL does not support these, and trying
|
||||
to insert them as values will trigger MySQL errors until they implement
|
||||
support.
|
||||
|
||||
This escaping allows you to do neat things like this:
|
||||
|
||||
```js
|
||||
var post = {id: 1, title: 'Hello MySQL'};
|
||||
var query = connection.query('INSERT INTO posts SET ?', post, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
// Neat!
|
||||
});
|
||||
console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
|
||||
```
|
||||
|
||||
And the `toSqlString` method allows you to form complex queries with functions:
|
||||
|
||||
```js
|
||||
var CURRENT_TIMESTAMP = { toSqlString: function() { return 'CURRENT_TIMESTAMP()'; } };
|
||||
var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
|
||||
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
|
||||
```
|
||||
|
||||
To generate objects with a `toSqlString` method, the `mysql.raw()` method can
|
||||
be used. This creates an object that will be left un-touched when using in a `?`
|
||||
placeholder, useful for using functions as dynamic values:
|
||||
|
||||
**Caution** The string provided to `mysql.raw()` will skip all escaping
|
||||
functions when used, so be careful when passing in unvalidated input.
|
||||
|
||||
```js
|
||||
var CURRENT_TIMESTAMP = mysql.raw('CURRENT_TIMESTAMP()');
|
||||
var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
|
||||
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
|
||||
```
|
||||
|
||||
If you feel the need to escape queries by yourself, you can also use the escaping
|
||||
function directly:
|
||||
|
||||
```js
|
||||
var query = "SELECT * FROM posts WHERE title=" + mysql.escape("Hello MySQL");
|
||||
|
||||
console.log(query); // SELECT * FROM posts WHERE title='Hello MySQL'
|
||||
```
|
||||
|
||||
## Escaping query identifiers
|
||||
|
||||
If you can't trust an SQL identifier (database / table / column name) because it is
|
||||
provided by a user, you should escape it with `mysql.escapeId(identifier)`,
|
||||
`connection.escapeId(identifier)` or `pool.escapeId(identifier)` like this:
|
||||
|
||||
```js
|
||||
var sorter = 'date';
|
||||
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter);
|
||||
connection.query(sql, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
It also supports adding qualified identifiers. It will escape both parts.
|
||||
|
||||
```js
|
||||
var sorter = 'date';
|
||||
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId('posts.' + sorter);
|
||||
// -> SELECT * FROM posts ORDER BY `posts`.`date`
|
||||
```
|
||||
|
||||
If you do not want to treat `.` as qualified identifiers, you can set the second
|
||||
argument to `true` in order to keep the string as a literal identifier:
|
||||
|
||||
```js
|
||||
var sorter = 'date.2';
|
||||
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter, true);
|
||||
// -> SELECT * FROM posts ORDER BY `date.2`
|
||||
```
|
||||
|
||||
Alternatively, you can use `??` characters as placeholders for identifiers you would
|
||||
like to have escaped like this:
|
||||
|
||||
```js
|
||||
var userId = 1;
|
||||
var columns = ['username', 'email'];
|
||||
var query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId], function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
// ...
|
||||
});
|
||||
|
||||
console.log(query.sql); // SELECT `username`, `email` FROM `users` WHERE id = 1
|
||||
```
|
||||
**Please note that this last character sequence is experimental and syntax might change**
|
||||
|
||||
When you pass an Object to `.escape()` or `.query()`, `.escapeId()` is used to avoid SQL injection in object keys.
|
||||
|
||||
### Preparing Queries
|
||||
|
||||
You can use mysql.format to prepare a query with multiple insertion points, utilizing the proper escaping for ids and values. A simple example of this follows:
|
||||
|
||||
```js
|
||||
var sql = "SELECT * FROM ?? WHERE ?? = ?";
|
||||
var inserts = ['users', 'id', userId];
|
||||
sql = mysql.format(sql, inserts);
|
||||
```
|
||||
|
||||
Following this you then have a valid, escaped query that you can then send to the database safely. This is useful if you are looking to prepare the query before actually sending it to the database. As mysql.format is exposed from SqlString.format you also have the option (but are not required) to pass in stringifyObject and timezone, allowing you provide a custom means of turning objects into strings, as well as a location-specific/timezone-aware Date.
|
105
07-Other/Node.js/VUE、Electron升级笔记.md
Normal file
105
07-Other/Node.js/VUE、Electron升级笔记.md
Normal file
@@ -0,0 +1,105 @@
|
||||
## 前言
|
||||
最近因为某些原因,最近决定升级VUE前端以及Electron APP工程中版本,其中Node.js版本从9.9.0升级到12.19.1。因为涉及较多东西,所以写此笔记。
|
||||
|
||||
推荐:
|
||||
- 使用nvm,为了保证不会耽误旧版本项目,可以使用nvm对node.js版本进行管理。你只需要使用nvm use 版本号,即可切换对应版本。
|
||||
- 使用版本管理,使得每一步升级都可以回滚。
|
||||
|
||||
## vue前端
|
||||
### vue
|
||||
项目用的是vue-cli生成。vue版本号需要与vue-template-compiler版本号一致。本人值从高版本一个一个往下试错,最后用了个可以跑通的版本。(因为用的是npm)
|
||||
|
||||
### node-sass
|
||||
如果直接使用npm install -s node-sass可能会引发node-gyp编译而造成的错误。推荐先npm uninstall node-sass将node-sass卸载干净,之后再安装。这个时候就会直接下载编译好的node-sass,而不是尝试编译。
|
||||
|
||||
**node-sass与node.js版本也有关系**,需要注意:
|
||||
|
||||
NodeJS | Supported node-sass version | Node Module
|
||||
---|---|---
|
||||
Node 15 | 5.0+ | 88
|
||||
Node 14 | 4.14+ | 83
|
||||
Node 13 | 4.13+, <5.0 |79
|
||||
Node 12 |4.12+ | 72
|
||||
Node 11 |4.10+, <5.0 | 67
|
||||
Node 10 |4.9+ | 64
|
||||
Node 8 |4.5.3+, <5.0 | 57
|
||||
Node <8 |<5.0 | <57
|
||||
|
||||
### Element-ui
|
||||
当低于**2.7.0**版本的Element-ui升级时需要注意要添加对**jsx**语法的支持,否则会报一下错误:
|
||||
|
||||
```
|
||||
error in ./~/.2.11.1@element-ui/packages/form/src/label-wrap.vue
|
||||
Syntax Error: Unexpected token (23:14)
|
||||
21 | }
|
||||
22 | }
|
||||
> 23 | return (<div class="el-form-item__label-wrap" style={style}>
|
||||
| ^
|
||||
24 | { slots }
|
||||
25 | </div>);
|
||||
26 | } else {
|
||||
@ ./~/.2.11.1@element-ui/packages/form/src/label-wrap.vue 4:2-108
|
||||
```
|
||||
解决:
|
||||
```npm
|
||||
npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props babel-preset-env --save-dev
|
||||
```
|
||||
在项目目录的.babelrc中添加对jsx插件的配置
|
||||
```json
|
||||
{
|
||||
"plugins": ["transform-vue-jsx", ...]
|
||||
}
|
||||
```
|
||||
|
||||
## Electron
|
||||
对于Electron-vue项目,还是推荐创建一个Electron-vue新项目。之后再将代码移植过去比较好。
|
||||
|
||||
### require/process/module is not define
|
||||
因为新版本Electron中默认没有集成node。
|
||||
解决:修改src/main/index.js,在webPreferences中加入nodeIntegration: true。
|
||||
```
|
||||
mainWindow = new BrowserWindow({
|
||||
height: 563,
|
||||
useContentSize: true,
|
||||
width: 1000,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### can't read property 'app' of
|
||||
是因为electron10后remote模块默认是关闭的,解决:修改src/main/index.js,在webPreferences中加入enableRemoteModule: true。
|
||||
|
||||
### Element-ui的el-table不显示
|
||||
解决:在.electron-vue/webpack.renderer.config.js中的
|
||||
```
|
||||
let whiteListedModules = ['vue']
|
||||
```
|
||||
加入elementui:
|
||||
```
|
||||
let whiteListedModules = ['vue', 'element-ui']
|
||||
```
|
||||
## Node.js后端sqlite3模块
|
||||
这里会需要使用node-gyp进行编译。这个需要安装visual studio2017,因为最高版本就支持到2017,不支持2019着实蛋疼。即使你给2019安装了2017 版本的构建套件、win10sdk与c++ ATL库,node-gyp都检测到了依然还会说版本不匹配(即使指定了版本为2019)。
|
||||
|
||||
如果你安装完2017还是不能正常编译,就可以手动指定vs版本了。执行
|
||||
```
|
||||
npm config set msvs_version 2017
|
||||
```
|
||||
node-gyp的具体安装步骤可以参考:https://github.com/nodejs/node-gyp#on-windows
|
||||
|
||||
## 清除注释
|
||||
### js 双斜杠
|
||||
```
|
||||
//(?!.*\..*\.).*\n
|
||||
```
|
||||
### js 多行
|
||||
```
|
||||
/\*(.|\r\n|\n)*?\*/
|
||||
```
|
||||
|
||||
### HTML
|
||||
```
|
||||
<!--(.|[\r\n])*?-->
|
||||
```
|
54
07-Other/Node.js/在Node.js中使用ffi调用dll.md
Normal file
54
07-Other/Node.js/在Node.js中使用ffi调用dll.md
Normal file
@@ -0,0 +1,54 @@
|
||||
> 类似的文章还是比较多的,但或多或少有一些问题没有解决,在此我将其整合并分享给大家:
|
||||
|
||||
## 测试环境:
|
||||
- Node.js 9.9.0
|
||||
- VisualStudio 2015
|
||||
- "ffi": "gavignus/node-ffi#torycl/forceset-fix",
|
||||
- "ref": "1.3.5"
|
||||
- "ref-array": "1.2.0"
|
||||
- "ref-struct": "1.1.0"
|
||||
- "ffi-napi": "^2.4.3"
|
||||
|
||||
## 编译失败:
|
||||
当前情况下编译ffi会失败,所以有两种解决方法:
|
||||
1. 使用新的ffi-napi(api是一样的,同时支持node.js新的napi)
|
||||
2. 使用第三方修改过的ffi,在package.json中,将ffi后面的版本号改成
|
||||
> "ffi": "gavignus/node-ffi#torycl/forceset-fix"
|
||||
## 使用:
|
||||
```
|
||||
var ffi = require('ffi');
|
||||
|
||||
//第一个形参为dll所在位置(dll文件可以不用加.dll),第二个为函数信息
|
||||
var libm = ffi.Library(__dirname + 'dllFile', {
|
||||
//函数名
|
||||
'fun': ['int', ['string', 'string']]
|
||||
});
|
||||
|
||||
//调用
|
||||
var str1="a";
|
||||
var str2="b";
|
||||
libm.fun(str1, str2);
|
||||
```
|
||||
## 使用c++里的类型
|
||||
ref、ref-struct、ref-array、ref-union、ref-wchar
|
||||
在npm查看使用方法,在此不做赘述。
|
||||
|
||||
## 运行时遇到的错误
|
||||
1. c++代码是可以用的,但是需要把代码写在extern "C"{}里,不过这个我没有亲自试过。
|
||||
2. dll文件需要放到node.js 执行目录,也就是
|
||||
```
|
||||
//即x:\xxxxx\xx
|
||||
cd /d x:\xxxxx\xx;
|
||||
node xxx.js;
|
||||
```
|
||||
3. dll如果有互相依赖的必须放全。不然只会出现错误126,而不会像一般程序那样提示缺少xxx.dll。所以报错了可以用depends看一下,dll全了没。
|
||||
4. dll的需要与node.js的平台相对应,比如你的node.js是64位版本的,那你的dll也需要使用64位编译。
|
||||
|
||||
错误126:检查上述1、2、3步。
|
||||
|
||||
## 参考:
|
||||
- wiki:
|
||||
- https://github.com/node-ffi/node-ffi/wiki/Node-FFI-Tutorial<br>
|
||||
|
||||
- https://www.jianshu.com/p/914103283ea0
|
||||
- https://blog.csdn.net/zhulin2609/article/details/51474676
|
Reference in New Issue
Block a user