前些天,写了探索Rust编写基于web_sys的WebAssembly编辑器:挑战输入光标定位的实践,经过后续的开发检验,我发现了一个问题,就是光标消失了。为了继续输入,用户需要再次使用鼠标点击。现在我已经弄清楚了导致这个问题的原因,即需要找到text node来设置光标。
先上代码
let oninput = use_callback(
move |e: InputEvent, content1_ref1| {
if let Some((selected_str, selection, parent_element)) = get_selection_items() {
if let Some(modified_text) = parse(&selected_str) {
parent_element.set_inner_html(&modified_text); // 更新解析后的输入
selection.remove_all_ranges().unwrap(); // 移除焦点
let div = content1_ref1.cast::<HtmlDivElement>().unwrap();
div.focus();
let first_child = parent_element.first_child().unwrap().first_child().unwrap(); // 这一行是关键
let new_range = Range::new().unwrap();
new_range.set_start(&first_child, 3); // 将光标设置到第3个字符的位置
new_range.collapse();
selection.add_range(&new_range);
}
}
},
(content1_ref.clone()),
);
在上面的源代码中,我已经用注释标记了first_child
,这里是关键,因为这里获取到的就是text node。为什么一定要text node呢?原因在于range.set_start的第一个参数,参考mozilla的文档:
即如果输入的参数是text node,那么上面的那个参数3
就代表从开始到第3个字符的位置;如果是其它类型的node,就表示从开头到第3个字节点的位置。
那什么是text node呢?在web_sys中,它的类型引入就是web_sys::Text
。可以用is_instance_of::<Text>()
来判断:
if first_child.is_instance_of::<Text>() { ... }
在mozilla中,关于Text的解释如下:
现在,我们清楚了,导致问题的原因是没有使用text node,以及在set_start方法中,如果node type不是text node,光标将如何定位。其实关于set_start的这段解释,我很早就看见了,但是由于对text node无感,就直接给忽略了。因此,才绕了这么大的一个圈子。
好了,这个小结就到这里,欢迎交流,可以想像,后面的路会更难走。