prosemirror 学习记录(四)decoration

编程入门 行业动态 更新时间:2024-10-26 06:25:43

<a href=https://www.elefans.com/category/jswz/34/1656554.html style=prosemirror 学习记录(四)decoration"/>

prosemirror 学习记录(四)decoration

使用 decorations

使用 props - decorations() 添加 decorations

写一个简单的插件:高亮所有 apple 节点

export const MyHighlightApplesPlugin = new Plugin({props: {// view 每次变化都会执行 decorations 方法decorations(state) {let arrs = [];state.doc.descendants((node, pos) => {if (node.type.name === "apple") {const deco = Decoration.inline(pos, pos + 1, { class: "highlight" });arrs.push(deco);}});return DecorationSet.create(state.doc, arrs);	// 返回 DecorationSet},},
});

css

span[custom-node-type="apple"].highlight::before {background: yellow;color: red;
}

效果:

用 Plugin - state 存储数据

Plugin 中的 state 字段可以存储数据

  • init: (config, state) => T
  • apply: (tr, value:T, oldState, newState) => T

plugin.getState(state) 可以获取这个数据

将 DecorationSet 存在 state 中,改写上面的插件:

export const MyHighlightApplesPlugin = new Plugin({state: {init(_, state) {return createAppleDecos(state.doc);},apply(tr) {return createAppleDecos(tr.doc);},},props: {decorations(state) {const set = MyHighlightApplesPlugin.getState(state);return set;},},
});function createAppleDecos(doc) {let arrs = [];doc.descendants((node, pos) => {if (node.type.name === "apple") {const deco = Decoration.inline(pos, pos + 1, { class: "highlight" });arrs.push(deco);}});return DecorationSet.create(doc, arrs); // 返回 DecorationSet
}

setMeta

给高亮效果添加开关,点击按钮随时切换是否高亮

plugin 中存储 enable 字段(以前只存储 set,现在是 {enable,set}

export const MyHighlightApplesPlugin = new Plugin({state: {init(_, state) {return {enable: true,set: createAppleDecos(state.doc),};},apply(tr, value) {const { enable } = value;let set;if (enable) {set = createAppleDecos(tr.doc);} else {set = DecorationSet.empty;}return { enable, set };},},props: {decorations(state) {const { set } = MyHighlightApplesPlugin.getState(state);return set;},},
});

enable 字段添加上了,接下来要在点击按钮时修改它的值


function toggleHighlightApples() {// 通过 getState 获取数据const state = MyHighlightApplesPlugin.getState(editorView.value.state);// 直接修改!state.enable = !state.enable;// 然后 dispatch 一个 trconst tr = editorView.value.state.tr;editorView.value.dispatch(tr);
}

上面的代码在插件外部直接修改 state.enable ,能实现效果,但是不好。
正确的做法是发一个信号,让 plugin 内部自己修改。

tr.setMeta 发信号:

function toggleHighlightApples() {const state = MyHighlightApplesPlugin.getState(editorView.value.state);const tr = editorView.value.state.tr;tr.setMeta(MyHighlightApplesPlugin, !state.enable);editorView.value.dispatch(tr);
}

applygetMeta 接收信号

    apply(tr, value) {let { enable } = value;const meta = tr.getMeta(MyHighlightApplesPlugin);if (meta !== undefined) {enable = meta;}let set;if (enable) {set = createAppleDecos(tr.doc);} else {set = DecorationSet.empty;}return { enable, set };},

效果

set.map(tr.mapping, tr.doc) 的作用

官网示例 image placeholder example 中用到 set.map(tr.mapping, tr.doc) ,作用看不懂,写代码测试一下

写一个简单的插件:给粗体文字自动添加红色背景

export const TestPlugin = new Plugin({state: {init(_, state) {return addRedBg(state.doc);},apply(tr, set) {return set;},},props: {decorations(state) {const set = TestPlugin.getState(state);return set;},},
});function addRedBg(doc) {let arrs = [];doc.descendants((node, pos) => {if (node.marks.find((mark) => mark.type.name === "strong")) {const deco = Decoration.inline(pos, pos + node.nodeSize, { style: "background:red" });arrs.push(deco);}});return DecorationSet.create(doc, arrs);
}

文档初始内容为:

<p>你好,今天天气不错。<strong>中午</strong>吃什么</p>

效果:

因为只在 init 中设置 deco,在 apply 中什么都没做。所以插件不会响应后续视图变化

新增 bold 文本,不会变红:

移除 bold,不会消失:

修改文档内容,致使bold文字位置变动,红色不跟着挪位置:


这些都是意料之中的效果。现在在 apply 中添加上这一句:

    apply(tr, set) {set = set.map(tr.mapping, tr.doc);	// 新增return set;},

新增 bold 文本、移除 bold 的效果不变,不放图了。

修改文档内容,致使bold文字位置变动,效果和之前不同了:

transform Guide 中讲到了 Mapping 的用法

let tr = new Transform(myDoc)
tr.split(10)    // split a node, +2 tokens at 10
tr.delete(2, 5) // -3 tokens at 2
console.log(tr.mapping.map(15)) // → 14
console.log(tr.mapping.map(6))  // → 3
console.log(tr.mapping.map(10)) // → 9

结合 DecorationSet.map 的说明:

set.map(tr.mapping, tr.doc) 的含义就明白了 —— 所有 deco 都应用 tr.mapping 找到新位置。

但是对于新增的 bold 文本(需要新增 deco),或者已经有的 bold 文本去掉 bold 效果(需要移除 deco),set.map(tr.mapping, tr.doc) 就无能为力了(剪切、复制、拖拽等同样处理不了)

更多推荐

prosemirror 学习记录(四)decoration

本文发布于:2023-12-03 10:17:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1654225.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:prosemirror   decoration

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!