Match-id-aaa8982a24dc5c6e6acb2ddf6410625f0628b112

This commit is contained in:
* 2022-03-30 17:03:00 +08:00 committed by *
parent 13e08a8d1b
commit 0475c8f8c0
4 changed files with 60 additions and 6 deletions

View File

@ -1,7 +1,19 @@
import styles from './Search.less'; import styles from './Search.less';
export default function Search() { interface SearchProps {
onChange: (event: any) => void,
}
export default function Search(props: SearchProps) {
const { onChange } = props;
const handleChange = (event) => {
onChange(event.target.value);
}
return ( return (
<input className={styles.search} placeholder={'Search (text or /regex/)'}/> <input
onChange={handleChange}
className={styles.search}
placeholder={'Search (text or /regex/)'}
/>
) )
} }

View File

@ -1,6 +1,7 @@
import { useState } from 'horizon'; import { useState } from 'horizon';
import styles from './VTree.less'; import styles from './VTree.less';
import Arrow from '../svgs/Arrow'; import Arrow from '../svgs/Arrow';
import { createRegExp } from './../utils';
export interface IData { export interface IData {
id: string; id: string;
@ -16,6 +17,7 @@ type IItem = {
onClick: (id: string) => void, onClick: (id: string) => void,
isCollapsed: boolean, isCollapsed: boolean,
isSelect: boolean, isSelect: boolean,
highlightValue: string,
} & IData } & IData
// TODO: 计算可以展示的最多数量,并且监听显示器高度变化修改数值 // TODO: 计算可以展示的最多数量,并且监听显示器高度变化修改数值
@ -35,6 +37,7 @@ function Item(props: IItem) {
indentation, indentation,
onClick, onClick,
isSelect, isSelect,
highlightValue,
} = props; } = props;
const isShowKey = userKey !== ''; const isShowKey = userKey !== '';
const showIcon = hasChild ? <Arrow director={isCollapsed ? 'right' : 'down'} /> : ''; const showIcon = hasChild ? <Arrow director={isCollapsed ? 'right' : 'down'} /> : '';
@ -49,13 +52,30 @@ function Item(props: IItem) {
itemAttr.tabIndex = 0; itemAttr.tabIndex = 0;
itemAttr.className = styles.treeItem + ' ' + styles.select itemAttr.className = styles.treeItem + ' ' + styles.select
} }
const reg = createRegExp(highlightValue);
const heightCharacters = name.match(reg);
let showName;
if (heightCharacters) {
let cutName = name;
showName = [];
// 高亮第一次匹配即可
const char = heightCharacters[0];
let index = name.search(char);
const notHighlightStr = cutName.slice(0, index);
showName.push(notHighlightStr);
showName.push(<mark>{char}</mark>);
cutName = cutName.slice(index + char.length);
showName.push(cutName);
} else {
showName = name;
}
return ( return (
<div {...itemAttr}> <div {...itemAttr}>
<div style={{ marginLeft: indentation * indentationLength }} className={styles.treeIcon} onClick={handleClickCollapse} > <div style={{ marginLeft: indentation * indentationLength }} className={styles.treeIcon} onClick={handleClickCollapse} >
{showIcon} {showIcon}
</div> </div>
<span className={styles.componentName} > <span className={styles.componentName} >
{name} {showName}
</span> </span>
{isShowKey && ( {isShowKey && (
<> <>
@ -73,7 +93,7 @@ function Item(props: IItem) {
) )
} }
function VTree({ data }: { data: IData[] }) { function VTree({ data, highlightValue }: { data: IData[], highlightValue: string }) {
const [scrollTop, setScrollTop] = useState(0); const [scrollTop, setScrollTop] = useState(0);
const [collapseNode, setCollapseNode] = useState(new Set<string>()); const [collapseNode, setCollapseNode] = useState(new Set<string>());
const [selectItem, setSelectItem] = useState(); const [selectItem, setSelectItem] = useState();
@ -124,6 +144,7 @@ function VTree({ data }: { data: IData[] }) {
onClick={handleClickItem} onClick={handleClickItem}
isCollapsed={isCollapsed} isCollapsed={isCollapsed}
isSelect={id === selectItem} isSelect={id === selectItem}
highlightValue={highlightValue}
{...item} /> {...item} />
) )
} }

View File

@ -9,6 +9,7 @@ import { mockParsedVNodeData, parsedMockState } from '../devtools/mock';
function App() { function App() {
const [parsedVNodeData, setParsedVNodeData] = useState([]); const [parsedVNodeData, setParsedVNodeData] = useState([]);
const [componentInfo, setComponentInfo] = useState({name: null, attrs: {}}); const [componentInfo, setComponentInfo] = useState({name: null, attrs: {}});
const [filterValue, setFilterValue] = useState('');
useEffect(() => { useEffect(() => {
if (isDev) { if (isDev) {
setParsedVNodeData(mockParsedVNodeData); setParsedVNodeData(mockParsedVNodeData);
@ -42,6 +43,11 @@ function App() {
}; };
data.push(item); data.push(item);
} }
const handleSearchChange = (str: string) => {
setFilterValue(str);
}
return ( return (
<div className={styles.app}> <div className={styles.app}>
<div className={styles.left}> <div className={styles.left}>
@ -51,11 +57,11 @@ function App() {
</div> </div>
<div className={styles.divider} /> <div className={styles.divider} />
<div className={styles.search}> <div className={styles.search}>
<Search /> <Search onChange={handleSearchChange}/>
</div> </div>
</div> </div>
<div className={styles.left_bottom}> <div className={styles.left_bottom}>
<VTree data={data} /> <VTree data={data} highlightValue={filterValue}/>
</div> </div>
</div> </div>
<div className={styles.right}> <div className={styles.right}>

View File

@ -0,0 +1,15 @@
export function createRegExp(expression: string){
let str = expression;
if (str[0] === '/') {
str = str.slice(1);
}
if (str[str.length - 1] === '/') {
str = str.slice(0, str.length - 1);
}
try {
return new RegExp(str, 'i');
}catch(err) {
return null;
}
}