@imohuan/selector
v1.0.3
Published
支持简单的字符串选择器
Downloads
3
Readme
Css选择器
声明 interface
export interface QueryChar {
/** 获取 `querySelectorAll` (默认: `@`) */
all: string;
/** 获取 `document.documentElement.querySelector` (默认: `!`)*/
root: string;
/** 获取 循环根部 (默认: `_`)*/
current: string;
/** 模板替换变量 (默认: `/\{([_a-zA-Z0-9]+)}/g`)*/
var: RegExp;
/** 不进行获取, 直接返回 * 后面的内容 (默认: `*`)*/
no: string;
}
export interface QueryOption<T> {
/* class选择器 */
cls: string | string[];
/* 获取json数据的时候使用 */
value: string | string[];
/* 自定义字符 */
char: QueryChar;
/* 类似后处理,这里提供了快捷方便的预制函数,提供有 int(转为整数),float(转为小数),trim(去除首位空格),url(补全URL),filterEmpty(过滤空数组),json(JSON化数据); */
rules: RuleItem[];
/* 父节点 class 或者 ParseDom(为内部获取节点的一个类, 类似 dom) */
parent: string | ParseDom;
/* 对获取的数据进行处理 data(获取class的内容) option(内置的一些配置和参数) */
processing: (data: any, option: ProcessingOption<T>) => any;
/* 替换class可以自己将常用的class简便化 */
replaces: QueryReplace[];
}
:::
预先配置
预制代码
import { resolve } from "path";
import { getSelector } from "@imohuan/selector";
const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div class="head">
<span>经济xxx</span>
</div>
<ul>
<li id="xxx">
<div class="title"> 标题1 </div>
<div class="description">描述1</div>
<div class="tags"><span class="tag">1</span> <span class="tag">2</span></div>
</li>
<li>
<div class="title">标题2 </div>
<div class="description">描述2</div>
<div class="tags"><span class="tag">1</span><span class="tag">2</span></div>
</li>
<li>
<div class="title">标题3</div>
<div class="description">描述3</div>
<div class="tags"><span class="tag">1</span><span class="tag">2</span></div>
</li>
</ul>
</body>
</html>
`;
const parser = getSelector(html, { name: "@imohuan/imohuan", age: 100 });
console.log(parser.query({ cls: ".head::text", rules: ["trim"] }));
console.log(parser.query({ cls: ".what::text|.dddd::text|.head::text", rules: ["trim"] }));
输出
经济xxx
经济xxx
选择器解析
*
不进行处理
const cls = "*Hello";
// 注意: 只能选择器首位
// 输出: "hello"
{name}
使用变量
const cls = "*{testVar}";
// 注意: 使用变量之后依然会进行解析,如果不需要进行解析的话,可以在开头添加*
// 输出: "测试变量"
@
获取所有匹配选择器的元素
const cls = "@a::attr(href)";
// 注意: 只能选择器首位
// 输出: ["https://1....", "https://2....",...]
!
从根节点获取选择器 (同:document.documentElement.querySelector
)
/** 伪代码 html 表述需要解析的数据 */
const html = `
<html>
<title>标题</title>
<body>
<ul>
<li><span class="title">1</span></li>
<li><span class="title">2</span></li>
</ul>
</body>
</html>
`;
/** 替换 parsers 参数 */
const parsers = [
{
name: "list",
parent: "ul li",
children: [
{ name: "title", cls: ".title::text" },
{ name: "title2", cls: "title::text" },
{ name: "rootTitle", cls: "!title::text" }
]
}
];
// 注意: 只能选择器首位
// 输出: [{ title: "1", title2: null, rootTitle: "标题" }, { title: "2", title2: null, rootTitle: "标题" }]
_
在children
中获取循环部位的根节点
/** 伪代码 html 表述需要解析的数据 */
const html = `
<html>
<title>标题</title>
<body>
<ul>
<li title="1"></li>
<li title="2"></li>
</ul>
</body>
</html>
`;
/** 替换 parsers 参数 */
const parsers = [
{
name: "list",
parent: "ul li",
children: [{ name: "title", cls: "_::attr(title)" }]
}
];
// 注意: 只能选择器首位
// 输出: [{ title: "1" }, { title: "2" }]
|
多个选择器从前往后匹配有内容的数据
/** 伪代码 html 表述需要解析的数据 */
const html = `<span class="hello">你好</span>`;
const cls = ".n::text|.what::text|.hello::text";
// 注意: 只能选择器首位
// 输出: "你好"
::text
获取元素的内容::html
获取元素的HTML
内容::attr(name)
获取元素属性,name
表示属性名称
自定义替换
默认配置 (无需配置)
export const defaultReplaces: QueryReplace[] = [
[
/:eq\(([0-9n\-+]+)\)/g,
(_value: any, numStr: string) => {
if (numStr.indexOf("n") !== -1) return `:nth-of-type(${numStr})`;
const num = parseInt(numStr);
if (num < 0) return `:nth-last-of-type(${Math.abs(num)})`;
return `:nth-of-type(${num})`;
},
"eq 转换为 nth-of-type"
],
[
/:ed\(([0-9n\-+]+)\)/g,
(_value: any, numStr: string) => {
if (numStr.indexOf("n") !== -1) return `:nth-child(${numStr})`;
const num = parseInt(numStr);
if (num < 0) return `:nth-last-child(${Math.abs(num)})`;
return `:nth-child(${num})`;
},
"ed 转换为 nth-child"
]
];
使用配置
console.log(parser.query({ cls: "ul li:eq(2)::text", rules: ["trim"], replaces: defaultReplaces }));
// cls将会被解析为: ul li:nth-of-type(2)::text
JSON 配置
::: tip 提醒 无需了解下列代码含义
只需要查看parent
和value
字段即可(因为它同cls
含义一样)
:::
const jsonData = {
page: 1,
size: 10,
list: [
{ title: "title1", url: "https://22222", tag: [1, 2, 3, 4, 5] },
{ title: "title2", url: "https://33333", tag: [11, 22, 33, 44, 55] }
]
};
const json = { global: jsonData, current: jsonData };
expect(queryJson(json, { value: "page" }, {})).toBe(1);
expect(queryJson(json, { value: "size" }, {})).toBe(10);
expect(queryJson(json, { value: "list[0].title" }, {})).toBe("title1");
expect(queryJson(json, { parent: "list", value: "title" }, {})).toEqual(["title1", "title2"]);
expect(queryJson(json, { parent: "list", value: "tag" }, {})).toEqual([
[1, 2, 3, 4, 5],
[11, 22, 33, 44, 55]
]);
expect(queryJson(json, { parent: "list", value: "!page" }, {})).toEqual([1, 1]);
expect(queryJson(json, { parent: "list", value: "!size" }, {})).toEqual([10, 10]);
expect(queryJson(json, { value: "{pageFor}" }, data)).toBe(1);
expect(queryJson(json, { value: "*123", rules: ["trim"] }, {})).toEqual("123");
expect(queryJson(json, { value: "*456", rules: ["trim"] }, {})).toEqual("456");
expect(queryJson(json, { value: "*{count}", rules: ["trim"] }, data)).toEqual("3");
expect(queryJson(json, { value: "*{hello}", rules: ["trim"] }, data)).toEqual("world");
expect(queryJson(json, { value: "*{hello}_{count}", rules: ["trim"] }, data)).toEqual("world_3");
expect(queryJson(json, { value: "*{arr}", rules: ["trim"] }, data)).toEqual("1,2,3");
案例
import { getSelector } from "im-selector";
// const { getSelector } = require("im-selector"); // 也可以
const html = `<a href="#1">1</a>
<a href="#2">2</a>
<a href="#3">3</a>
<a href="#4">4</a>
<a href="#5">5</a>
<a href="#6">6</a>
<a href="#7">7</a>
<a href="#8">8</a>
<a href="#9">9</a>
<a href="#10">10</a>`;
const parser = Selector.getSelector(html, { name: "im-selector" });
console.log("使用变量", parser.query({ cls: "*{name}" }));
console.log("多个Class找到存在的值", parser.query({ cls: ".xxx::text|a::text", rules: ["trim"] }));
console.log("全选", parser.query({ cls: "@a::text", rules: ["trim"] }));
选择器
常用选择器
id 选择
#app
class 选择
.app
标签选择
span
后代
div span
子代
div > span
邻接兄弟
span + div
通用兄弟
span ~ div
属性选择
存在属性
span[attr] => a[title]
属性相等
span[attr=value] => a[href="https://example.com"]
包含(空格分开)
[attr~=value] => li[class~="a"]
开头等于或则已 zh-开头
[attr|=value] => div[lang|="zh"]
开头包含
[attr^=value] => a[src^="https"]
结尾包含
[attr$=value] => a[src$=".vue"]
包含
[attr*=value] => a[src*="hello"]
伪类
:eq(1)
->:last-of-type(1)
:eq(-1)
->:nth-last-of-type(1)
:ed(1)
->:last-child(1)
:ed(-1)
->:nth-last-child(1)
:nth-child(2n+1)
->span:nth-child(-n+3)
选择父级下面第几个元素:last-of-type
选择同级同元素的最后一个:last-child
选择父元素下最后一个元素:nth-of-type
选择父级下面同类型的第几个元素:nth-last-child
:nth-last-of-type
CSS 伪类首先找到所有当前元素的兄弟元素,然后按照位置先后顺序从 1 开始排序,选择的结果为 CSS 伪类*
:nth-child
括号中表达式(an+b
)匹配到的元素集合(n=0,1,2,3...
)
:not(选择器)
匹配作为值传入自身的选择器未匹配的物件:only-child
选择没有兄弟的元素:only-of-type
选择同级没有相同元素的元素