@HD Superman 大大快帮帮我~
请问是如何修改prosemirror的光标颜色的?
reactjs
120 views
@HD Superman 大大快帮帮我~
自己写一个光标插件,实现光标的动画:
/**
* @description 自定义光标插件
* @author zhd
* */
import { EditorState, Plugin, PluginKey } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import UAParser from 'ua-parser-js';
const uaParser = new UAParser();
const browserName = (uaParser.getBrowser().name || '').toLowerCase();
class Cursor {
prevFocused: boolean;
cursor: HTMLDivElement;
constructor(view: EditorView) {
this.prevFocused = false;
this.cursor = document.createElement('div');
view.dom.parentNode!.appendChild(this.cursor);
this.update(view, null);
}
update(view: EditorView, prevState: EditorState | null) {
// 判断编辑器是否重新聚焦,页面位置可能已经改变,需要重新计算光标位置
let refocus = false;
if (view.hasFocus() && !this.prevFocused) {
refocus = true;
}
this.prevFocused = view.hasFocus();
const { state } = view;
const { selection } = state;
// 选择状态不显示
if (!selection.empty) {
this.cursor.style.display = 'none';
return;
}
// fixed: safari 下 代码块不显示
if (
browserName.includes('safari') &&
(selection.$from.parent.type.name === 'code_block' ||
selection.$from.parent.type.name === 'math_block')
) {
this.cursor.style.display = 'none';
return;
}
// 文档和选区没有变化时不处理, 除非编辑器重新聚焦,才需要重新计算位置
if (
prevState &&
prevState.doc.eq(state.doc) &&
prevState.selection.eq(state.selection) &&
!refocus
)
return;
this.cursor.style.display = '';
// fixed: 响应式布局父节点 display-none 导致 offsetParent 为 null 的 bug
if (!this.cursor.offsetParent) return;
const box = this.cursor.offsetParent.getBoundingClientRect();
const { from } = selection;
const pos = view.coordsAtPos(from);
// 实现光标闪烁动画重新播放,避免光标移动时刚好动画出于隐藏阶段导致不显示
this.cursor.className = this.cursor.className.includes('play')
? 'editor-cursor editor-cursor-restart'
: 'editor-cursor editor-cursor-play';
this.cursor.style.height = `${pos.bottom - pos.top + 2}px`;
this.cursor.style.width = '2px';
this.cursor.style.left = `${pos.left - box.left}px`;
this.cursor.style.top = `${pos.top - box.top - 1}px`;
}
destroy() {
this.cursor.remove();
}
}
const key = new PluginKey('focus');
/**
* focus 逻辑:在聚焦的时候触发 Cursor.update 重新计算光标位置
* @see https://discuss.prosemirror.net/t/handling-focus-in-plugins/1981/5
* */
export const cursorPlugin = new Plugin({
key,
state: {
init() {
return false;
},
apply(transaction, prevFocused) {
const focused = transaction.getMeta(key);
if (typeof focused === 'boolean') {
return focused;
}
return prevFocused;
},
},
props: {
handleDOMEvents: {
blur: (view) => {
view.dispatch(view.state.tr.setMeta(key, false));
return false;
},
focus: (view) => {
view.dispatch(view.state.tr.setMeta(key, true));
return false;
},
},
},
view(editorView) {
return new Cursor(editorView);
},
});
上面是一个实现,hackertalk 还没开源,后面开源可以看到全部编辑器代码。