- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在这个应用程序中,我有一个搜索引擎,它应该在文件树内部查找所需的内容。目的是,当搜索某些内容并单击搜索按钮时,文件树将过滤并显示您要查找的内容。
现在,我有一个 console.log()
(检查 onSubmitSearch(e)
内 <SearchEngine/>
)告诉我当我单击“搜索”按钮时要求搜索哪些内容。唯一缺少的是实际在文件树内部查找的搜索。我该怎么做?
请检查附加的工作片段。
谢谢!
/**** TEXT BOX COMPONENT ****/
class TextBox extends React.Component {
constructor(props) {
super(props);
this.state = { content: "Select A Node To See Its Data Structure Here..." };
this.changeContent = this.changeContent.bind(this);
}
changeContent(newContent) {
this.setState({ content: newContent });
}
componentWillReceiveProps(nextProps) {
this.setState({
content: nextProps.content
});
}
render() {
return (
<div className="padd_top">
<div className="content_box">
{this.state.content}
</div>
</div>
);
}
}
/**** SEARCH COMPONENT ****/
class SearchEngine extends React.Component {
constructor(props) {
super(props);
this.state = { value: "" };
this.onInputChange = this.onInputChange.bind(this);
this.onSubmitSearch = this.onSubmitSearch.bind(this);
}
onInputChange(e) {
const content = e.target.value;
this.setState({value: content});
console.log(content);
}
onSubmitSearch(e) { // CONSOLE LOG IS HERE
e.preventDefault();
console.log('A node was submitted: ' + this.state.value);
}
render() {
return (
<div>
<form onSubmit={this.onSubmitSearch}>
<input
className="form-control"
value={this.state.value}
type="text"
onChange={this.onInputChange}
/>
<p>{this.state.value}</p>
<SearchButton />
</form>
</div>
);
}
}
/**** SEARCH BUTTON ****/
class SearchButton extends React.Component {
render() {
return (
<button
type="submit"
value="submit"
bsStyle="danger"> Search
</button>
);
}
}
/**** FILE TREE COMPONENT ****/
let data = [
{
type: "directory",
name: ".",
contents: [
{
type: "directory",
name: "./bin",
contents: [{ type: "file", name: "./bin/greet" }]
},
{
type: "directory",
name: "./lib",
contents: [{ type: "file", name: "./lib/greeting.rb" }]
},
{
type: "directory",
name: "./spec",
contents: [
{ type: "file", name: "./spec/01_greeting_spec.rb" },
{ type: "file", name: "./spec/02_cli_spec.rb" },
{ type: "file", name: "./spec/spec_helper.rb" }
]
},
{ type: "file", name: "./CONTRIBUTING.md" },
{ type: "file", name: "./Gemfile" },
{ type: "file", name: "./Gemfile.lock" },
{ type: "file", name: "./LICENSE.md" },
{ type: "file", name: "./README.md" }
]
}
];
// Icon file image for 'FileTree'
const FileIcon = () => {
return (
<div className="svg-icon">
<svg
id="icon-file-text2"
className="icon"
viewBox="0 0 32 32"
fill="currentColor"
width="1em"
height="1em"
>
<path d="M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z" />
<path d="M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z" />
<path d="M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z" />
<path d="M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z" />
</svg>
</div>
);
};
// Icon folder image for 'FileTree'
const FolderIcon = () => {
return (
<div className="svg-icon">
<svg
id="icon-folder"
className="icon"
viewBox="0 0 32 32"
fill="currentColor"
height="1em"
width="1em"
>
<path d="M14 4l4 4h14v22h-32v-26z" />
</svg>
</div>
);
};
// Icon arrow image for 'FileTree'
const TriangleDown = () => {
return (
<div className="svg-icon">
<svg
id="svg__icon--triangle-down"
viewBox="0 0 9 4.5"
fill="currentColor"
height="1em"
width="1em"
>
<path d="M0,0,4.5,4.5,9,0Z" />
</svg>
</div>
);
};
// Filters file 'name' and adds '/'
const formatName = name => {
return name.substr(name.lastIndexOf("/") + 1);
};
// Dummy data set
var root = data[0];
// Construction of FileTree
class FileTree extends React.Component {
constructor(props) {
super(props);
this.state = {
activeNode: null
};
this.setActiveNode = this.setActiveNode.bind(this);
}
setActiveNode(name) {
this.setState({ activeNode: name });
this.props.liftStateUp(name);
}
componentWillReceiveProps({ searchTerm }) {
this.setState({ searchTerm });
}
render() {
return (
<div className="padd_top">
{renderTree(
this.props.root || root,
this.setActiveNode,
this.state.activeNode,
null,
this.state.searchTerm
)}
</div>
);
}
}
/**** DIRECTORY ****/
class Directory extends React.Component {
constructor(props) {
super(props);
this.state = { expanded: true };
this.toggleDirectory = this.toggleDirectory.bind(this);
}
toggleDirectory() {
this.setState({ expanded: !this.state.expanded });
}
hasMatchingNodes() {
const searchTerm = this.props.searchTerm.toLowerCase();
const matchNode = node =>
node.contents
? node.contents.filter(matchNode).length !== 0
: node.name.toLowerCase().indexOf(searchTerm) !== -1;
return matchNode(this.props.node);
}
render() {
let node = this.props.node;
const rotate = this.state;
if (this.props.searchTerm && !this.hasMatchingNodes()) return null;
return (
<div className="directory-container">
<div className="directory">
<div
className={`directory__toggle ${
this.state.expanded ? "expanded" : ""
}`}
>
<div onClick={this.toggleDirectory}>
<TriangleDown onClick={() => this.setState({ rotate: true })}
className={rotate ? "rotate" : ""} />
</div>
</div>
<div className="directory__icon" onClick={this.toggleDirectory}>
<FolderIcon />
</div>
<div className="directory__name" onClick={this.toggleDirectory}>
<div>{formatName(node.name)}</div>
</div>
</div>
{this.state.expanded
? node.contents.map((content, index) =>
renderTree(
content,
this.props.setActiveNode,
this.props.activeNode,
index,
this.props.searchTerm
)
)
: ""}
</div>
);
}
}
// Set class Active to selected file
const File = ({ name, setActiveNode, activeNode, searchTerm }) => {
if (searchTerm && name.toLowerCase().indexOf(searchTerm.toLowerCase()) < 0)
return null;
let isActive = activeNode === name;
let className = isActive ? "active" : "";
return (
<div className={className + " file"} onClick={() => setActiveNode(name)}>
<div className="file__icon">
<FileIcon />
</div>
<div className="file__name">{formatName(name)}</div>
{isActive && <div className="file__options">...</div>}
</div>
);
};
var renderTree = (node, setActiveNode, activeNode, index, searchTerm) => {
if (node.type === "file") {
return (
<File
key={index}
name={node.name}
setActiveNode={setActiveNode}
activeNode={activeNode}
searchTerm={searchTerm}
/>
);
} else if (node.type === "directory") {
return (
<Directory
key={index}
node={node}
setActiveNode={setActiveNode}
activeNode={activeNode}
searchTerm={searchTerm}
/>
);
} else {
return null;
}
};
/**** APP ****/
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
activeNode: ""
};
this.onChange = this.onChange.bind(this);
}
liftStateUp = (data) => {
this.setState({ activeNode: data });
};
onChange(data) {
this.setState({ searchTerm: data });
}
render() {
return (
<div>
<div className="col-md-12">
<SearchEngine className="form-control" onChange={this.onChange} />
</div>
<div className="col-md-6">
<FileTree
liftStateUp={this.liftStateUp}
searchTerm={this.state.searchTerm}
/>
</div>
<div className="col-md-6">
<TextBox content={this.state.activeNode}/>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
* {
font-family: Helvetica;
color: #333333 !important;
}
/** DIRECTORY CSS **/
.directory {
padding-left: 10px;
padding-top: 1px;
padding-bottom: 1px;
display: flex;
flex-direction: row;
align-items: center;
}
.directory__toggle {
padding-left: 10px;
transform: rotate(-90deg)
}
.directory__icon {
padding-left: 10px;
}
.directory__icon {
padding-left: 10px;
}
.directory__name {
padding-left: 10px;
}
.directory-container {
padding-left: 10px;
}
/** FILE CSS **/
.file {
padding-left: 50px;
padding-top: 1px;
padding-bottom: 1px;
display: flex;
}
.file__icon {
padding-left: 10px;
}
.file__name {
padding-left: 10px;
}
.file__options {
align-self: flex-end;
}
.icon {
display: inline-block;
width: 1em;
height: 1em;
stroke-width: 0;
stroke: currentColor;
fill: currentColor;
}
.svg-icon {
width: 1em;
height: 1em;
}
.expanded {
transform: rotate(0deg)
}
/** CONTENT BOX **/
.padd_top {
padding-top: 20px;
}
.btn-danger {
color: #fff !important;
}
.content_box {
font-size: 12px;
white-space: pre-wrap;
border: solid 1px black;
padding: 20px;
color: #9da5ab;
min-height: 250px;
width: 100%;
}
.text_color {
color: #21252b !important;
}
/** arrow animation **/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
最佳答案
您的问题是数据传播。您将数据提供给 FileTree 组件,并且您的搜索引擎与 FileTree 组件处于同一级别,并且它无法访问必须过滤的数据。我将数据提升到应用程序组件(SearchEngine 和 FileTree 组件的父级),并将数据传播到 FileTree。我没有将数据传播到 SearchEngine,而是将 onSubmitSearch 事件处理程序提升到 App 组件并将其传播到 SearchEngine,因为即使我将数据提供给 SearcEngine,我也无法在 FileTree 组件上更新它(因为单向数据流)。
// Dummy data set
var root = data[0];
/**** APP ****/
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
activeNode: "",
root: root
};
this.onChange = this.onChange.bind(this);
}
liftStateUp = data => {
this.setState({ activeNode: data });
};
onSubmitSearch = (e, search) => {
let tree = JSON.stringify(root); // always search full data tree
tree = JSON.parse(tree); // JSON.stringify and then JSON.parse are
if (!search || search === "") {
// if search is undefined, null or empty, set root to full data tree
this.setState({ root: tree }); // state.root is filtered tree passed to the FileTree component
return;
}
/*uncoment if you need to filter already filtered tree*/
// tree = JSON.stringify(this.state.root);
// tree = JSON.parse(tree);
/**/
// else filter tree
this.setState({
root: this.filterTree(tree, search.toLowerCase())
});
};
filterTree = (data, search) => {
let children = data.contents;
if (!children || !children.length) {
if (!data.name.toLowerCase().includes(search)) {
data.remove = true;
}
} else {
for (let i = children.length - 1; i >= 0; i--) {
this.filterTree(children[i], search);
if (children[i].remove) {
children.splice(i, 1);
}
}
if (!children.length) {
data.remove = true;
}
}
return data;
};
onChange(data) {
this.setState({ searchTerm: data });
}
render() {
return (
<div>
<div className="col-md-12">
<SearchEngine
className="form-control"
onChange={this.onChange}
onSubmitSearch={this.onSubmitSearch}
/>
</div>
<div className="col-md-6">
<FileTree
root={this.state.root}
liftStateUp={this.liftStateUp}
searchTerm={this.state.searchTerm}
/>
</div>
<div className="col-md-6">
<TextBox content={this.state.activeNode} />
</div>
</div>
);
}
}
请注意,App 现在具有 onSubmitSearch 函数,该函数随后会传播到 SearchEngine,并在搜索引擎中使用搜索输入值调用该函数:
/**** SEARCH COMPONENT ****/
class SearchEngine extends React.Component {
constructor(props) {
super(props);
this.state = { value: "" };
this.onInputChange = this.onInputChange.bind(this);
}
onInputChange(e) {
const content = e.target.value;
this.setState({ value: content });
}
render() {
const { onSubmitSearch } = this.props;
const { value } = this.state;
return (
<div>
<form onSubmit={e => onSubmitSearch(e, value)}>
<input
className="form-control"
value={this.state.value}
type="text"
onChange={this.onInputChange}
/>
<p>{this.state.value}</p>
<SearchButton />
</form>
</div>
);
}
}
FileTree 组件现在获取过滤数据(通过搜索输入值/搜索引擎)并仅负责渲染 FileTree 组件。
在此处查看使用提交按钮过滤树结构的工作示例:https://codesandbox.io/s/3rnvv0kln6
关于javascript - 实现搜索栏按钮和文件树组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50860099/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!