Open SunXinFei opened 4 years ago
我们使用electron-devtools-installer 这个插件,
electron.app.on('ready', () => {
installExtension(installExtension.VUEJS_DEVTOOLS)
.then(() => {})
.catch(err => {
console.log('Unable to install `vue-devtools`: \n', err)
})
//添加Redux_DevTools
installExtension(installExtension.REDUX_DEVTOOLS)
.then(() => {})
.catch(err => {
console.log('Unable to install `redux-devtools`: \n', err)
})
})
其中store的js文件中我们需要配置添加composeWithDevTools
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import FileManageStore from './test/reducer';
import { combineReducers } from 'redux-immutable';
import thunk from 'redux-thunk';
import Immutable from 'immutable';
let store = createStore(
combineReducers({ FileManageStore }),
Immutable.Map({}),
composeWithDevTools(applyMiddleware(thunk))
);
export default store;
即可见Redux插件变化
stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
解决方案类似js截流,200ms之内如果双击则cleartimeOut
let timer = 0;
let delay = 200;
let prevent = false;
doClickAction() {
console.log(' click');
}
doDoubleClickAction() {
console.log('Double Click')
}
handleClick() {
let me = this;
timer = setTimeout(function() {
if (!prevent) {
me.doClickAction();
}
prevent = false;
}, delay);
}
handleDoubleClick(){
clearTimeout(timer);
prevent = true;
this.doDoubleClickAction();
}
< button onClick={this.handleClick.bind(this)}
onDoubleClick = {this.handleDoubleClick.bind(this)} > click me </button>
参考: onClick works but onDoubleClick is ignored on React component https://stackoverflow.com/questions/25777826/onclick-works-but-ondoubleclick-is-ignored-on-react-component
e.target : 触发事件的元素,谁触发就是谁,用来区分事件委托和冒泡 e.currentTarget :绑定事件的元素,不管是不是触发的对象中子元素,依旧是绑定的元素,用来直接获取父元素的一些状态
使用空元素填充,来实现
为了防止css-loader编译这个属性,需要这么写
/* autoprefixer: off */
-webkit-box-orient: vertical;
/* autoprefixer: on */
babel 6.x
npm install babel-plugin-transform-decorators-legacy
.babelrc中"plugins"添加"transform-decorators-legacy"
如果是babel 7.x+
npm install @babel/plugin-proposal-decorators --save-dev
{
“plugins”: [
["@babel/plugin-proposal-decorators", { “legacy”: true }]
]
}
实现方式有三种:
问题:我们在实际的组件拆分中,我们经常会遇到相同的一些业务逻辑,比如aaa触发了,都需要发送ajax请求,我们这里是文件路径保存给redux之前都需要判断路径是否存在,而且判断路径是一个异步操作。在这里我们介绍下Redux-thunk。 Redux-thunk是一个Redux是中间件,如下入所示,他位于 Action与 Strore中间,简单的说,他就是对store.dispatch进行了一次升级,他通过改造store.dispatch,可以使得store.dispatch可以接受函数作为参数。 actions.js代码前后变化:
//旧的代码
// 选择文件夹路径在边栏
export const setFolderPathActiveInSider = (data) => {
return {
type: actionType.SETFOLDERPATHACTIVEINSIDER,
data
};
}
//新的代码
// 选择文件夹路径在边栏
export const setFolderPathActiveInSider = (data) => {
return {
type: actionType.SETFOLDERPATHACTIVEINSIDER,
data
};
}
// 选择文件夹路径在边栏
export const setFolderPathActiveInSiderAsync = (data) => {
return async (dispatch) => {
const exists = await fsExtra.pathExists(data);
if (!exists) {
message.error('路径未找到;该路径已被删除或移动');
return false;
}
dispatch(setFolderPathActiveInSider(data));
return true;
}
}
所以在新的代码中,我们利用dispatch来人为的控制Redux中的action的触发,dispatch我们可以写在异步或者回调函数之中都可以,这样我们就可以利用action做一些统一的处理比如ajax请求等等
参考: Redux-thunk https://www.jianshu.com/p/159919acb4d0 redux-thunk - redux的中间件 https://www.jianshu.com/p/b1a039feac26 Redux中间件之redux-thunk使用详解 https://www.jianshu.com/p/a27ab19d3657
webpack中的别名配置
resolve: {
alias: {
'@filemanage': path.join(__dirname, '../src/renderer/views/filemanage2')
},
extensions: ['.js', '.jsx', '.vue', '.json', '.css', '.node']
},
//js中的文件路径以及图片路径
import { setFolderPathActiveInSiderAsync } from '@filemanage/store/action';
const CardImage = ({ type, extension }) => {
let imgSrc = require(`@filemanage/assets/icon_file/file.png`);
return (
<img src={imgSrc} alt="File-icon" />
)
}
//less中的文件路径
@import "~@filemanage/style/variables.less";
.filemanage-content-option{
padding: 2px 10px;
width: 100%;
height: @filemanageContentOptionHeight;
border-bottom: 1px solid #e8e8e8;
}
参考: 从 loading 的 9 种写法谈 React 业务开发 https://www.yuque.com/es2049/blog/xel32z React Hooks 深入不浅出 https://www.yuque.com/es2049/blog/durwgr
react中实现类似vue中的scoped
这里使用css-loader的配置,就可以实现scoped的效果,会将className进行hash处理,相当于vue语法中的scoped;如果不想hash处理就是global化,相当于vue中去掉scoped
参考: CSS Modules 用法教程 http://www.ruanyifeng.com/blog/2016/06/css_modules.html
React中Mixin的有害性
npm install asar -g
,全局安装asar;asar e app.asar app
,表示将asar文件解压到app的文件夹中错误信息如下:
The module '/node_modules/better-sqlite3/build/better_sqlite3.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 57. This version of Node.js requires
NODE_MODULE_VERSION 64. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or `npm install`).
解决方法:
npm install --save-dev electron-rebuild
node_modules/.bin/electron-rebuild -f -w better-sqlite3
参考:https://github.com/JoshuaWise/better-sqlite3/issues/126
在开发时,会生成.db文件,为了方便我们查看数据,我们使用sqlitebrowser来可视化查看。
在Electron中常用到操作用户的本地路径
(electron.app || electron.remote.app).getPath('home'); // 获取用户根目录
(electron.app || electron.remote.app).getPath('userData'); // 用于存储 app 用户数据目录
(electron.app || electron.remote.app).getPath('appData'); // 用于存储 app 数据的目录,升级会被福噶
(electron.app || electron.remote.app).getPath('desktop'); // 桌面目录
(electron.app || electron.remote.app).getAppPath();//当前应用程序所在目录
在 main process 中通过 electron.app 调用,在renderer process中,通过 remote 模块调用。 参考:
https://electronjs.org/docs/api/app https://github.com/whxaxes/blog/issues/8
path.join()
该方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径(只是拼接各个path片段)
path.resolve()
该方法会把一个路径或路径片段的序列解析为一个绝对路径。(除了拼接各个字段还拼接了工作目录的路径)
如果想获取某路径的上一层路径,则使用../
进行拼接
__dirname 表示当前执行代码的文件所在的目录的绝对路径
__filename 表示当前执行代码的文件的绝对路径
module.filename ==== __filename 等价
process.cwd() 返回运行当前脚本的工作目录的路径
目录结构如下
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { combineReducers } from 'redux-immutable';
import thunk from 'redux-thunk';
import Immutable from 'immutable';
const modules = {}
const context = require.context('./reducers', false, /\.js$/) // carrega reducers de todos os componentes
context.keys().forEach((filename) => {
const key = filename.replace(/(\.\/|\.js)/g, '')
const ctx = context(filename)
if (ctx.default) {
modules[key] = ctx.default
}
})
let store = createStore(
combineReducers(modules),
Immutable.Map({}),
composeWithDevTools(applyMiddleware(thunk))
);
window.$store = store;
export default store;
以上代码是redux中自动加载reducer,在vuex中同样适用 参考:
https://github.com/agalwood/Motrix/blob/master/src/renderer/store/modules/index.js
需求背景:文件管理页面常见的框选需要在容器层面给body绑定mouse事件,同时获取文件card的位置来判断是否在框选范围内。
//渲染子组件Card
getCardList(files) {
let cardList = []
this.cardObjList = []
files.map((file, index) => {
cardList.push(
<Card getRef={elm => ( this.cardObjList.push(elm.getBoundingClientRect()) )} key={index} index={index} file={file} />
)
})
return cardList
}
//父组件
render() {
const { isContentLoading, isShowContextMenu, files } = this.props;
const { selectEle } = this.state;
return (
<div onClick={this.cancelSelectCard}
onMouseDown={this.down}
onMouseMove={this.move}
onMouseUp={this.up}>
{
this.getCardList(files)
}
</div>
);
}
//卡片子组件
render() {
const { index, file, connectDragSource } = this.props;
return (
<div
ref={elm => {
connectDragSource(elm)
if (!elm) return;
this.props.getRef(elm);
}}
className={isSelectCard ? "filemanage-content-main-card selected" : "filemanage-content-main-card"}
key={index}
style={{ width: '110px' }}
onClick={(e) => { this.handleClick(e) }}
onDoubleClick={(e) => { this.handleDoubleClick(e, type, path, name, extension) }}>
<div className="card-prew">
<CardImage type={type} extension={extension}></CardImage>
</div>
<div className="card-filename">
{name}
</div>
</div>
);
}
核心代码为子组件中调用父组件的getRef方法并把当前dom传入进去;
ref={elm => {
connectDragSource(elm)
if (!elm) return;
this.props.getRef(elm);
}}
父组件中列表清空以及getRef的回调push
this.cardObjList = [] //渲染之前列表清空
files.map((file, index) => {
cardList.push(
<Card getRef={elm => ( this.cardObjList.push(elm.getBoundingClientRect()) )} key={index} index={index} file={file} />
)
技术栈 electron + react + sqlite + immutable + redux
npm包功能总结
<select>
框的混合体。它基于jQuery,具有自动完成功能和本机感觉的键盘导航;用于标记,联系人列表等 //// 使用react-select