Skip to content

中文API文档

Xuanzi edited this page Feb 8, 2022 · 21 revisions

Visdom

Visdom 用来解析html文档节点树,并可对节点树采用jquery类似的api来进行操作。API基本和jquery保持一致,除了函数命名在rust中采用短横杠分割(snake-case)的方式,代替了jquery使用的驼峰(camel-case)方式,另外在jquery中参数支持多种格式的API,在visdom中采用了拆分成一组API的形式。

由于其api与jquery基本类似,所以对于习惯使用jquery的同学非常容易上手。但注意visdom并不提供也无法提供jquery中与渲染、事件等相关的API,因为这些属于浏览器的功能部分,visdom并不能提供这样的环境。

此外,visdom 针对文本节点实现了选取texts(0)、修改set_html()\set_text()方法,所以用它来做网页内容的筛选抓取或者更改节点防止被抓取也是十分方便的。

使用方式

Cargo.toml

main.rs

use visdom::Vis;
use visdom::types::BoxDynError;

fn main()-> Result<(), BoxDynError>{
  let html = r##"
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
      </head>
      <body>
        <nav id="header">
          <ul>
            <li>Hello,</li>
            <li>Vis</li>
            <li>Dom</li>
          </ul>
        </nav>
      </body>
    </html>
  "##;
  // load html
  let root = Vis::load(html)?;
  let lis = root.find("#header li");
  let lis_text = lis.text();
  println!("{}", lis_text);
  // 将输出 "Hello,VisDom"
  Ok(())
}

运行示例

Vis

静态方法:load(html: &str) -> Result<NodeList, BoxDynError>

加载html文档字符串为NodeList元素集合,如果后续对集合的选择器操作中有selector参数错误,错误将不会被捕获,要想捕获错误,请使用`load_catch`方法。

静态方法:load_catch(html: &str, handle: Box<dyn Fn(BoxDynError)>) -> NodeList

加载html文档字符串为NodeList元素集合,同时设置错误处理方法`handle`,如果你希望在html解析错误、选择器方法中selector书写不正确的情况下能统一被处理,可以使用该方式加载。

静态方法:dom(ele: &BoxDynNode) -> NodeList

将一个ele元素转换为NodeList元素集合,主要用于在API中带回调方法参数的方法中,ele元素上自带了INodeTrait实现的方法<在mesdoc中可查看>,如果不需要做一些复杂的查找操作等,你将不需要使用该方法,该方法会复制ele节点。

示例:

// 接以上示例
let texts = lis.map(|_index, ele|{
  let ele = Vis::dom(ele);
	return String::from(ele.text());
});
// 则texts为Vec<String>, ["Hello,", "Vis", "Dom"]
// 没有被包装的ele元素具备的方法可以查看mesdoc接口方法

运行示例

API

Trait对象方法

Trait Object Trait Inherit 文档
BoxDynNode INodeTrait None INodeTrait Document
BoxDynElement IElementTrait INodeTrait IElementTrait Document
BoxDynText ITextTrait INodeTrait ITextTrait Document
Box<dyn IDocumentTrait> IDocumentTrait None IDocumentTrait Document

集合类型 APIs

集合 文档
Elements Elements Document
Texts Texts Document

选择器操作

选择器方法 说明 备注
is_开头的方法,以下方法返回值也为Elements元素集合
find(selector: &str) 查找匹配选择器的子孙元素
filter(selector: &str) 筛选出匹配选择器的元素
filter_by(|index: usize, ele: &BoxDynNode| -> bool) 根据闭包方法返回的值,true则包含,false将被排除 对应filter方法参数为函数的形式
filter_in(node_list: &NodeList) 在node_list中的元素将被包含,否则被排除 对应filter方法参数为集合的形式
not(selector: &str) 排除匹配选择器的元素
not_by(|index: usize, ele: &BoxDynNode| -> bool) 根据闭包方法返回的值,true则被排除,false则包含 对应not方法参数为函数的形式
not_in(node_list: &NodeList) 在node_list中的元素将被排除,否则包含 对应not方法参数为集合的形式
is(selector: &str)->bool 判断是否有一个元素匹配选择器
is_by(|index: usize, ele: &BoxDynNode| -> bool)->bool 根据闭包方法返回的值,有任意一个为true则返回true 对应is方法参数为函数的形式
is_in(node_list: &NodeList)->bool 有任意一个元素包含在node_list中,则返回true 对应is方法参数为集合的形式
is_all(selector: &str)->bool 判断是否所有元素都匹配选择器 库额外提供方法
is_all_by(|index: usize, ele: &BoxDynNode| -> bool)->bool 根据闭包方法返回的值,全部为true则返回true,否则false is_all方法参数为函数的形式
is_all_in(node_list: &NodeList)->bool 所有元素都包含在node_list中,则返回true,否则为false is_all方法参数为集合的形式
has(selector: &str) 筛选出子级元素中包含匹配选择器的元素
has_in(node_list: &NodeList) 筛选出有子级元素包含在node_list中的元素
children(selector: &str) 从子元素开始,查找匹配选择器的元素
parent(selector: &str) 从父元素开始,查找匹配选择器的元素
parents(selector: &str) 从父元素及祖先元素开始,查找匹配选择器的元素
parents_until(selector: &str, filter: &str, contains: bool) 从父元素向祖先元素一步步往上查找,遇到匹配到selector的父元素或祖先元素时停止查找,当contains为true时,匹配到的元素也包含在查找到的元素集合内;当filter参数不为空时,会使用filter对所有查找到的元素进行筛选。
closest(selector: &str) 从自身开始向父元素及祖先元素一步步向上查找,当找到匹配到的元素即停止查找,返回匹配到的第一个元素。
siblings(selector: &str) 从兄弟元素开始,查找匹配选择器的元素
next(selector: &str) 从后一个紧挨兄弟元素开始,查找匹配选择器的元素
next_all(selector: &str) 从后面所有兄弟元素开始,查找匹配选择器的元素
next_until(selector: &str, filter: &str, contains: bool) 从后面兄弟元素向后开始查找,遇到匹配selector时停止查找,当contains为true时,匹配到的元素也包含在查找到的元素集合内;当filter参数不为空时,会使用filter对所有查找到的元素进行筛选。
prev(selector: &str) 从前一个紧挨兄弟元素开始,查找匹配选择器的元素
prev_all(selector: &str) 从前面所有兄弟元素开始,查找匹配选择器的元素
prev_until(selector: &str, filter: &str, contains: bool) 从前面兄弟元素向前开始查找,遇到匹配selector时停止查找,当contains为true时,匹配到的元素也包含在查找到的元素集合内;当filter参数不为空时,会使用filter对所有查找到的元素进行筛选。
eq(index: usize) 获取元素列表中第 index 个
first() 获取元素集合的第一个元素,是eq(0)的等价形式
last() 获取元素集合的最后一个元素,是eq(length-1)的等价形式
slice<T: RangeBounds>(range: T) 获取某段范围内元素 如:slice(..3),表示前三个元素,slice(1..)表示第一个以后的所有元素
add(eles: Elements) 将当前Self集合中包含的元素和eles参数集合中的元素合并出一个新的元素集合,注意它不会改变Self自身,同时会获取eles参数的所有权,eles不能再被使用

辅助方法

辅助方法 说明 备注
length()->usize 返回元素集合长度
is_empty()->bool 判断元素集合是否为空
for_each(|index: usize, ele: &mut BoxDynNode| -> bool) 对每个元素进行遍历,当返回值为false时停止遍历 如果你喜欢简短写法,使用 each 也是一样的
map<T>(|index: usize, ele: &BoxDynNode| -> Vec<T>) 对每个元素进行遍历,返回回调方法返回值的集合
document() 当元素集合不为空集的时候,可以用来快速获取document文档节点,通常在执行Vis::load后执行该操作

selector参数支持的选择器

选择器 说明 备注
* 所有元素 元素选择器可参见 MDN css 选择器文档
#id id 选择器
.class 类选择器
p 标签名选择器
[attr] 含有{attr}的元素
[attr=value] {attr}值为{value}的元素
[attr*=value] {attr}包含{value}值的元素
[attr|=value] {attr}包含{value}值或者{value}-的元素
[attr~=value] {attr}包含{value}值,且值是以空格作为分隔的元素
[attr^=value] {attr}以{value}值开头的元素
[attr$=value] {attr}以{value}值结尾的元素
[attr!=value] 包含{attr},且值不为{value}的元素
span > a 子元素选择器 匹配父元素为 span 的 a 元素
span a 子孙元素选择器 匹配 span 元素下的所有子孙 a 元素
span + a 相邻元素选择器 匹配 span 后面紧邻的兄弟 a 元素
span ~ a 后面兄弟元素选择器 匹配 span 后面所有的兄弟 a 元素
span.a 多条件筛选选择器 匹配 span 且 class 名包含 a 的元素
:empty 没有子元素的元素
:root 返回文档的html根元素 以下都为伪类选择器
:first-child 第一个子元素
:last-child 最后一个子元素
:only-child 唯一子元素
:nth-child(nth) nth 表示为 a'n + b',a'和 b'为整数<零及正负>,n 从 0 开始计数,和为 1 则表示第一个子元素,最终将获取所有符合该数列值的子元素 nth 形式的选择器都支持 odd 和 even 关键字
:nth-last-child(nth) 同上,但从最后一个子元素开始计数算作第一个子元素
:first-of-type 子元素中第一个出现的标签元素<按标签名>
:last-of-type 子元素中最后一个出现的标签元素<按标签名>
:only-of-type 子元素中只出现一次的标签元素<按标签名>
:nth-of-type(nth) 子元素中标签<按标签名>出现顺序符合数列值的元素
:nth-last-of-type(nth) 同上,但出现顺序从最后一个元素往前数
:not(selector) 匹配不符合 selector 选择器的元素
:checked 表单选中元素,针对select内的option 及 input[type="radio"],input[type="checkbox"]元素
:header 所有标题元素,h1,h2,h3,h4,h5,h6 的别名
:input 所有表单元素,input,select,textarea,button 的别名
:submit 表单提交按钮,input[type="submit"],button[type="submit"] 的别名

属性操作

属性方法 说明 备注
没有标明返回值的,均返回Elements元素集合自身,可以进一步链式调用
attr(attr_name: &str) -> Option<IAttrValue> 获取属性 值为 Option<IAttrValue> 枚举类型,IAttrValue 自身具备is_true(),is_str(&str)to_list()等方法
set_attr(attr_name: &str, value: Option<&str>) 设置属性值,当 value 为 None 时,表示设置布尔 true,没有字符串属性值
has_attr(attr_name: &str, value: Option<&str>) 判断节点上是否包含某个属性名为attr_name的属性
remove_attr(attr_name: &str) 删除属性
has_class(class_name: &str) -> bool 判断元素中是否至少有一个元素包含 class 类名,多个 class 用空格隔开
add_class(class_name: &str) 增加 class 类名,多个 class 用空格隔开
remove_class(class_name: &str) 删除 class 类名
toggle_class(class_name: &str) 切换 class 类名,存在则删除,不存在则添加

文本操作

文本方法 说明 备注
text()->&str 获取所有元素的文本内容,实体将会自动 decode
set_text(content: &str) 设置元素的内容为 content 文本<自动 encode 实体>
val()->IFormValue 获取select选中option,option,input,textarea等的值
html()->&str 获取第一个元素的 html 文档内容
set_html(content: &str) 设置元素的子节点为 content 解析后的子节点
outer_html()->&str 获取第一个元素的 html 文档内容,包含节点本身
texts(limit_depth: u32)-> Texts 获取元素的文本内容,limit_depth设置允许递归层次,0为不限制

节点操作

dom 节点操作方法 说明 备注
append(nodes: &mut NodeList) 将所有节点插入节点子元素最后
append_to(nodes: &mut NodeList) 同上,但交换参数与调用者
prepend(nodes: &mut NodeList) 将所有节点插入节点子元素开始
prepend_to(nodes: &mut NodeList) 同上,但交换参数与调用者
insert_after(nodes: &mut NodeList) 将所有节点插入该元素之后
after(nodes: &mut NodeList) 同上,但交换参数与调用者
insert_before(nodes: &mut NodeList) 将所有节点插入该元素之前
before(nodes: &mut NodeList) 同上,但交换参数与调用者
remove() 删除节点,删除后持有的变量将不能再使用
empty() 清空节点内所有子元素

示例代码

let html = r##"
  <div class="second-child"></div>
  <div id="container">
    <div class="first-child"></div>
  </div>
"##;
let root = Vis::load(html)?;
let mut container = root.find("#container");
let mut second_child = root.find(".second_child");
// 将child元素插入到container子元素最后
container.append(&mut second_child);
// 代码将变成
/*
<div id="container">
  <div class="first-child"></div>
  <div class="second-child"></div>
</div>
*/
let mut third_child = Vis::load(r##"<div class="third-child"></div>"##)?;
container.append(&mut third_child);
// 代码将变成
/*
<div id="container">
  <div class="first-child"></div>
  <div class="second-child"></div>
  <div class="third-child"></div>
</div>
*/

运行示例

依赖

问题 & 意见 & Bugs?

如果您有好的意见、想法、或者使用中遇到bug问题等,欢迎提 Issue 给我们.

License

MIT License.