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';
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 (
<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 styles from './VTree.less';
import Arrow from '../svgs/Arrow';
import { createRegExp } from './../utils';
export interface IData {
id: string;
@ -16,6 +17,7 @@ type IItem = {
onClick: (id: string) => void,
isCollapsed: boolean,
isSelect: boolean,
highlightValue: string,
} & IData
// TODO: 计算可以展示的最多数量,并且监听显示器高度变化修改数值
@ -35,6 +37,7 @@ function Item(props: IItem) {
indentation,
onClick,
isSelect,
highlightValue,
} = props;
const isShowKey = userKey !== '';
const showIcon = hasChild ? <Arrow director={isCollapsed ? 'right' : 'down'} /> : '';
@ -49,13 +52,30 @@ function Item(props: IItem) {
itemAttr.tabIndex = 0;
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 (
<div {...itemAttr}>
<div style={{ marginLeft: indentation * indentationLength }} className={styles.treeIcon} onClick={handleClickCollapse} >
{showIcon}
</div>
<span className={styles.componentName} >
{name}
{showName}
</span>
{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 [collapseNode, setCollapseNode] = useState(new Set<string>());
const [selectItem, setSelectItem] = useState();
@ -124,6 +144,7 @@ function VTree({ data }: { data: IData[] }) {
onClick={handleClickItem}
isCollapsed={isCollapsed}
isSelect={id === selectItem}
highlightValue={highlightValue}
{...item} />
)
}

View File

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