[2023.09.22]:探索Rust编写基于web_sys的WebAssembly编辑器:挑战输入光标定位的实践

昨天,我对过去两周的工作进行了总结并上传了源代码。而今天,我又踏入了一个对我来说既熟悉又陌生的领域:编辑器。

我对编辑器的熟悉来自于多年来使用他人开发的编辑器的经验,但对于自己开发编辑器这件事情,我感到陌生。

重新设计一个编辑器基于以下两个目的:

  1. 我想在笔记数据中插入一些元数据,以供后期对笔记数据的分析和整理使用。这需要我能够完全控制这个编辑器的数据输出格式;
  2. 我也很想体验基于Rust开发出来的WebAssembly,它性能到底会有多高;

想自己开发一个编辑器,我的感受,就一个字"难",但我很享受这个挑战。这也让我反思了一下,这些年来,我到底写了多少有价值的代码呢?

步骤

今天主要解决输入光标的位置获取以及再次定位。期间遇到的困难就不分享了,这里只把步骤列出来。

1. 设置contenteditable设置

contenteditable是一个属性,它可以应用于任何HTML元素,并且允许用户编辑元素的内容。当将contenteditable属性设置为true时,可以像Input或者TextArea一样,让用户编辑其中的内容。重点是,它的innerHtml是可编辑的,因此这让我们有了实现丰富编辑功能的潜在可能性。

html 复制代码
<div class="content" contenteditable="true" {oninput} ref={content1_ref}>
</div>

2. 获取当前window对象

在web_sys中,window对象是,是除了事件对象之外,我们获取一切对象的入口。比如,我们后面要获取当前的光标位置,就要从window对象开始。

rust 复制代码
let window = web_sys::window().expect("get window object err");

3. 获取当前的Selection

Selection对象代表当前用户选择的范围,它其中就包含我们需要的光标位置。Selection这个概念中也包含两个名词需要说明一下,这对后面控制光标的位置有帮助。一个是anchor,一个是focus。anchor(锚点)是用户选择开始的位置,focus(焦点)是用户选择结束。

rust 复制代码
let selection = window.get_selection().expect("get selection result err").expect("get selection option err");

4. 记录当前光标位置

光标的位置,从上面取到的selection对象得到。当然,下面的代码比较简单,实际的应用可能会更复杂一些。后面我再更新。因为我们是在输入事件中捕获光标的位置,所以就直接使用range.start_offset()的返回值。变量pos记录了当前光标的位置。

rust 复制代码
let range: Range = selection.get_range_at(0).expect("get range err");
let pos = range.start_offset().unwrap();

5. 设置当前的光标位置

当我们对输入的数据进行格式化之后,光标会自动跳到行首,这个时候需要再次设置光标的位置。这里,我们分别调用了range.set_start()range.set_end

rust 复制代码
selection.remove_all_ranges().unwrap();
selection.add_range(&range);
let div = get_div_element(&e).expect("get div");
range.set_start(&div.first_child().expect("get first child"), pos);
range.set_end(&div.first_child().expect("get first child"), pos);

6. 从新设置焦点

上面,我们只是设置了Selection,还需要最后一行代码来将输入光标显示出来。

rust 复制代码
div.focus();

总结

这个过程我们涉及到的对象有window, Selection, Range, HtmlDivElement。获取输入光标的路径是window -> Selection -> Range。

好了今天就到这里,大家周末愉快。欢迎大家留言交流。

相关推荐
IT_陈寒4 分钟前
Redis 性能翻倍的 7 个冷门技巧,第 5 个大多数人都不知道!
前端·人工智能·后端
mCell7 小时前
GSAP ScrollTrigger 详解
前端·javascript·动效
gnip7 小时前
Node.js 子进程:child_process
前端·javascript
excel10 小时前
为什么在 Three.js 中平面能产生“起伏效果”?
前端
excel11 小时前
Node.js 断言与测试框架示例对比
前端
天蓝色的鱼鱼13 小时前
前端开发者的组件设计之痛:为什么我的组件总是难以维护?
前端·react.js
codingandsleeping13 小时前
使用orval自动拉取swagger文档并生成ts接口
前端·javascript
石金龙14 小时前
[译] Composition in CSS
前端·css
白水清风14 小时前
微前端学习记录(qiankun、wujie、micro-app)
前端·javascript·前端工程化
Ticnix14 小时前
函数封装实现Echarts多表渲染/叠加渲染
前端·echarts