DraftJS 触发焦点内容更改?
DraftJS triggers content change on focus?
我在页面上有一个编辑器和 save
按钮。我希望 save
按钮仅在有更改(自上次保存后)时出现。所以,当你保存时,我设置 this.setState({hasChanges: false})
并在 onChange
函数中我将 hasChanges
设置为 true
。
一切正常。问题是当编辑器获得焦点时,编辑器将触发 onChange
事件(但内容尚未更改)。而且,根据他们的 documentation
,这是预期的行为
The event listeners within the component will observe focus changes
and propagate them through onChange as expected, so state and DOM will
remain correctly in sync.
有什么方法可以知道 onChange
方法中的内容是否发生了变化,或者只是选择发生了变化?
我今天早些时候在 github 上发布了您问题的答案,但我也会将其添加到此处以供将来参考:
您说得对,每次 editorState
更改时都会调用 onChange。由于 editorState
同时包含 selectionState
和 contentState
,它会在内容编辑时和 selection/focus 更改时发生变化。
如果您想知道触发 onChange
方法的更改是在 contentState
中还是在 selectionState
中,您可以将它们与它们的旧值进行比较:
function onChange(newState) {
const currentContentState = this.state.editorState.getCurrentContent()
const newContentState = newState.getCurrentContent()
if (currentContentState !== newContentState) {
// There was a change in the content
} else {
// The change was triggered by a change in focus/selection
}
}
现在,如果您知道更改发生在 contentState
,您可以通过调用 newState.getLastChangeType(). It should return any of these values 获得更多信息(除非您或您添加的某些插件创建了新的改变类型)。
但是,有时只有条件 if (currentContentState !== newContentState)
不起作用,并且无法检测到当您使用 Entity.mergeData
和 forceSelection
一起修改内容状态时的情况,因为此更改是存储在实体内部,不在 contentState
.
中公开
所以你可以另外做类似的事情。
this.currentEntityMap = null;
function onChange(newEditorState) {
const currentContentState = editorState.getCurrentContent();
const newContentState = newEditorState.getCurrentContent();
const newContentStateRaw = convertToRaw(newContentState);
const newEntityMap = newContentStateRaw ? newContentStateRaw.entityMap : null;
//so if you have the two entity maps, you can to compare it, here an example function.
const isEntityMapChanged = this.isEntityMapChanged(newEntityMap);
this.currentEntityMap = newEntityMap;
}
isEntityMapChanged(newEntityMap) {
let isChanged = false;
if (this.currentEntityMap) {
loop1:
for (const index of Object.keys(newEntityMap)) {
if (this.currentEntityMap[index] && newEntityMap[index].type === this.currentEntityMap[index].type) {
loop2:
for (const prop of Object.keys(newEntityMap[index].data)) {
if (newEntityMap[index].data[prop] !== this.currentEntityMap[index].data[prop]) {
isChanged = true;
break loop1;
}
}
} else {
isChanged = true;
break loop1;
}
}
}
return isChanged;
}
然后使用标志 isEntityMapChanged
和第一个条件进行保存。
您应该使用以下代码:
const onChange = newState => {
if (
// when content change or line style change will change the state
!newState.getCurrentContent().equals(editorState.getCurrentContent()) ||
!newState
.getCurrentInlineStyle()
.equals(editorState.getCurrentInlineStyle())
) {
setEditorState(newState);
}
};
如果你只是使用content equal,那么线型改变不会生效
我在页面上有一个编辑器和 save
按钮。我希望 save
按钮仅在有更改(自上次保存后)时出现。所以,当你保存时,我设置 this.setState({hasChanges: false})
并在 onChange
函数中我将 hasChanges
设置为 true
。
一切正常。问题是当编辑器获得焦点时,编辑器将触发 onChange
事件(但内容尚未更改)。而且,根据他们的 documentation
The event listeners within the component will observe focus changes and propagate them through onChange as expected, so state and DOM will remain correctly in sync.
有什么方法可以知道 onChange
方法中的内容是否发生了变化,或者只是选择发生了变化?
我今天早些时候在 github 上发布了您问题的答案,但我也会将其添加到此处以供将来参考:
您说得对,每次 editorState
更改时都会调用 onChange。由于 editorState
同时包含 selectionState
和 contentState
,它会在内容编辑时和 selection/focus 更改时发生变化。
如果您想知道触发 onChange
方法的更改是在 contentState
中还是在 selectionState
中,您可以将它们与它们的旧值进行比较:
function onChange(newState) {
const currentContentState = this.state.editorState.getCurrentContent()
const newContentState = newState.getCurrentContent()
if (currentContentState !== newContentState) {
// There was a change in the content
} else {
// The change was triggered by a change in focus/selection
}
}
现在,如果您知道更改发生在 contentState
,您可以通过调用 newState.getLastChangeType(). It should return any of these values 获得更多信息(除非您或您添加的某些插件创建了新的改变类型)。
但是,有时只有条件 if (currentContentState !== newContentState)
不起作用,并且无法检测到当您使用 Entity.mergeData
和 forceSelection
一起修改内容状态时的情况,因为此更改是存储在实体内部,不在 contentState
.
所以你可以另外做类似的事情。
this.currentEntityMap = null;
function onChange(newEditorState) {
const currentContentState = editorState.getCurrentContent();
const newContentState = newEditorState.getCurrentContent();
const newContentStateRaw = convertToRaw(newContentState);
const newEntityMap = newContentStateRaw ? newContentStateRaw.entityMap : null;
//so if you have the two entity maps, you can to compare it, here an example function.
const isEntityMapChanged = this.isEntityMapChanged(newEntityMap);
this.currentEntityMap = newEntityMap;
}
isEntityMapChanged(newEntityMap) {
let isChanged = false;
if (this.currentEntityMap) {
loop1:
for (const index of Object.keys(newEntityMap)) {
if (this.currentEntityMap[index] && newEntityMap[index].type === this.currentEntityMap[index].type) {
loop2:
for (const prop of Object.keys(newEntityMap[index].data)) {
if (newEntityMap[index].data[prop] !== this.currentEntityMap[index].data[prop]) {
isChanged = true;
break loop1;
}
}
} else {
isChanged = true;
break loop1;
}
}
}
return isChanged;
}
然后使用标志 isEntityMapChanged
和第一个条件进行保存。
您应该使用以下代码:
const onChange = newState => {
if (
// when content change or line style change will change the state
!newState.getCurrentContent().equals(editorState.getCurrentContent()) ||
!newState
.getCurrentInlineStyle()
.equals(editorState.getCurrentInlineStyle())
) {
setEditorState(newState);
}
};
如果你只是使用content equal,那么线型改变不会生效