【全栈React】第10天: 交互性
今天,我们将介绍如何添加交互性到我们的应用,使其具有吸引力和交互性。 通过这一点,我们构建了少数几个组件,而没有添加用户交互。 今天我们将要改变它。 用户交互浏览器是事件驱动的应用程序。 用户在浏览器中进行的一切都会触发一个事件,从点击按钮,甚至只是移动鼠标。 在简单的JavaScript中,我们可以监听这些事件并附加一个JavaScript函数与它们进行交互。 例如,我们可以使用JS附加一个函数到 export const go = () => { const ele = document.getElementById('mousemove'); ele.innerHTML = 'Move your mouse to see the demo'; ele.addEventListener('mousemove',function(evt) { const { screenX,screenY } = evt; ele.innerHTML = '<div>Mouse is at: X: ' + screenX + ',Y: ' + screenY + '</div>'; }) } 这导致以下行为: 将鼠标移到该文本上 然而,在React中,我们不必在原始JavaScript中与浏览器的事件循环进行交互,因为React为我们使用 例如,要从React上面的(相当不起眼的)演示中收听 <div onMouseMove={(evt) => console.log(evt)}> Move the mouse </div> React提供了很多 要看看其中的一些在行动中,以下是一些小的演示,一些 我们将在我们的应用中使用 我们_想要_的交互是在用户点击搜索图标时显示搜索。 回想一下,我们的 class Header extends React.Component { constructor(props) { super(props); this.state = { searchVisible: false } } // toggle visibility when run on the state showSearch() { this.setState({ searchVisible: !this.state.searchVisible }) } render() { // Classes to add to the <input /> element let searchInputClasses = ["searchInput"]; // Update the class array if the state is visible if (this.state.searchVisible) { searchInputClasses.push("active"); } return ( <div className="header"> <div className="menuIcon"> <div className="dashTop"></div> <div className="dashBottom"></div> <div className="circle"></div> </div> <span className="title"> {this.props.title} </span> <input type="text" className={searchInputClasses.join(' ')} placeholder="Search ..." /> {/* Adding an onClick handler to call the showSearch button */} <div onClick={this.showSearch.bind(this)} className="fa fa-search searchIcon"></div> </div> ) } } 当用户点击 我们让这个组件有状态(它需要跟踪搜索字段是否应该显示)。 我们可以使用 class Header extends React.Component { constructor(props) { super(props); this.state = { searchVisible: false } } // ... }
当用户点击按钮时,我们将要更新状态来表示 我们创建这个方法来绑定我们的点击事件: class Header extends React.Component { // ... showSearch() { this.setState({ searchVisible: !this.state.searchVisible }) } // ... } 最后,我们可以在icon元素上附加一个点击处理程序(使用 class Header extends React.Component { constructor(props) { super(props); this.state = { searchVisible: false } } // toggle visibility when run on the state showSearch() { this.setState({ searchVisible: !this.state.searchVisible }) } render() { // Classes to add to the <input /> element let searchInputClasses = ["searchInput"]; // Update the class array if the state is visible if (this.state.searchVisible) { searchInputClasses.push("active"); } return ( <div className="header"> <div className="fa fa-more"></div> <span className="title"> {this.props.title} </span> <input type="text" className={searchInputClasses.join(' ')} placeholder="Search ..." /> {/* Adding an onClick handler to call the showSearch button */} <div onClick={this.showSearch.bind(this)} className="fa fa-search searchIcon"></div> </div> ) } } 尝试点击搜索图标并观看输入字段出现并消失(动画效果由CSS动画处理)。 输入事件无论何时在React中构建表单,我们将使用React提供的输入事件。最值得注意的是,我们最常使用 我们更新我们的搜索框演示,以便在更新时捕获搜索字段内的文本。每当一个 使用这个属性,我们可以捕捉到我们这个字段的价值。 让我们创建一个新的子组件来包含一个 我们创建一个我们称之为 class SearchForm extends React.Component { // ... constructor(props) { super(props); this.state = { searchText: '' } } // ... } 现在,我们已经在 class SearchForm extends React.Component { // ... render() { const { searchVisible } = this.state; let searchClasses = ['searchInput'] if (searchVisible) { searchClasses.push('active') } return ( <form className='header'> <input type="search" className={searchClasses.join(' ')} onChange={this.updateSearchInput.bind(this)} placeholder="Search ..." /> <div onClick={this.showSearch.bind(this)} className="fa fa-search searchIcon"></div> </form> ); } } 请注意,我们在我们的 我们定义 class SearchForm extends React.Component { static propTypes = { onSubmit: React.PropTypes.func.isRequired,searchVisible: React.PropTypes.bool } // ... } 现在我们在 class SearchForm extends React.Component { // ... updateSearchInput(e) { const val = e.target.value; this.setState({ searchText: val }); } // ... render() { const { searchVisible } = this.state; let searchClasses = ['searchInput'] if (searchVisible) { searchClasses.push('active') } return ( <form className='header'> <input type="search" className={searchClasses.join(' ')} onChange={this.updateSearchInput.bind(this)} placeholder="Search ..." /> <div onClick={this.showSearch.bind(this)} className="fa fa-search searchIcon"></div> </form> ); } } 当我们键入字段时,将会调用
class SearchForm extends React.Component { // ... updateSearchInput(e) { const val = e.target.value; this.setState({ searchText: val }); } // ... }
到目前为止,我们无法真正提交表单,所以我们的用户无法真正搜索。 我们来改变一下 我们需要将 我们来更新 class SearchForm extends React.Component { // ... submitForm(e) { e.preventDefault(); const {searchText} = this.state; this.props.onSubmit(searchText); } // ... render() { const { searchVisible } = this.props; let searchClasses = ['searchInput'] if (searchVisible) { searchClasses.push('active') } return ( <form onSubmit={this.submitForm.bind(this)}> <input type="search" className={searchClasses.join(' ')} onChange={this.updateSearchInput.bind(this)} placeholder="Search ..." /> </form> ); } }
现在当我们键入 那么好的,我们可以提交表单和内容,但是什么时候我们实际上进行搜索?为了演示目的,我们将把搜索文本传递给父子组件链,以便
为了将搜索功能传递给链,我们的“SearchForm”将需要接受在提交表单时调用的函数。我们来定义一个我们称之为 class SearchForm extends React.Component { static propTypes = { onSubmit: React.PropTypes.func.isRequired,searchVisible: React.PropTypes.bool } // ... static defaultProps = { onSubmit: () => {},searchVisible: false } // ... } 当表单提交时,我们可以直接从 class SearchForm extends React.Component { // ... submitForm(event) { // prevent the form from reloading the entire page event.preventDefault(); // call the callback with the search value this.props.onSubmit(this.state.searchText); } } 现在,当用户按下enter时,我们可以通过我们的 我们可以在我们的 import React from 'react'; import SearchForm from './SearchFormWithSubmit' class Header extends React.Component { constructor(props) { super(props); this.state = { searchVisible: false } } // toggle visibility when run on the state showSearch() { this.setState({ searchVisible: !this.state.searchVisible }) } render() { // Classes to add to the <input /> element let searchInputClasses = ["searchInput"]; // Update the class array if the state is visible if (this.state.searchVisible) { searchInputClasses.push("active"); } return ( <div className="header"> <div className="menuIcon"> <div className="dashTop"></div> <div className="dashBottom"></div> <div className="circle"></div> </div> <span className="title"> {this.props.title} </span> <SearchForm searchVisible={this.state.searchVisible} onSubmit={this.props.onSubmit} /> {/* Adding an onClick handler to call the showSearch button */} <div onClick={this.showSearch.bind(this)} className="fa fa-search searchIcon"></div> </div> ) } } export default Header 现在我们有一个搜索表单组件,可以在我们的应用中使用和重用。 当然,我们还没有搜索任何东西。 我们来解决这个问题,实现搜索。 [](#implementing-search)实现搜索要在我们的组件中实现搜索,我们希望将搜索责任从我们的 首先,让我们实现一个从 在 class Header extends React.Component { // ... } Header.propTypes = { onSearch: React.PropTypes.func } 在 class Header extends React.Component { // ... submitForm(val) { this.props.onSearch(val); } // ... } Header.propTypes = { onSearch: React.PropTypes.func }
回到我们在第7天构建的 由于 无论如何,我们的 class Panel extends React.Component { constructor(props) { super(props); this.state = { loading: false,// <~ set loading to false activities: data,filtered: data,} } componentDidMount() {this.updateData();} componentWillReceiveProps(nextProps) { // Check to see if the requestRefresh prop has changed if (nextProps.requestRefresh !== this.props.requestRefresh) { this.setState({loading: true},this.updateData); } } handleSearch = txt => { if (txt === '') { this.setState({ filtered: this.state.activities }) } else { const { activities } = this.state const filtered = activities.filter(a => a.actor && a.actor.login.match(txt)) this.setState({ filtered }) } } // Call out to github and refresh directory updateData() { this.setState({ loading: false,activities: data },this.props.onComponentRefresh); } render() { const {loading,filtered} = this.state; return ( <div> <Header onSubmit={this.handleSearch} title="Github activity" /> <div className="content"> <div className="line"></div> {/* Show loading message if loading */} {loading && <div>Loading</div>} {/* Timeline item */} {filtered.map((activity) => ( <ActivityItem key={activity.id} activity={activity} /> ))} </div> </div> ) } } 我们更新我们的状态以包括一个 class Panel extends React.Component { constructor(props) { super(props); this.state = { loading: false,searchFilter: '',activities: [] } } } 为了实际处理搜索,我们需要将 class Panel extends React.Component { // ... // after the content has refreshed,we want to // reset the loading variable onComponentRefresh() {this.setState({loading: false});} handleSearch(val) { // handle search here } render() { const {loading} = this.state; return ( <div> <Header onSearch={this.handleSearch.bind(this)} title="Github activity" /> <Content requestRefresh={loading} onComponentRefresh={this.onComponentRefresh.bind(this)} fetchData={this.updateData.bind(this)} /> </div> ) } } 我们在这里所做的就是添加一个 为了_实现_搜索,我们需要跟踪这个字符串,并更新我们的 class Panel extends React.Component { // ... handleSearch(val) { this.setState({ searchFilter: val,loading: true }); } // ... } 最后,我们更新我们的 class SearchableContent extends React.Component { // ... this.setState({loading: true},this.updateData); // ... } 虽然这可能看起来很复杂,但它实际上几乎与我们现有的 所有的 随着 尝试搜索 现在我们有一个3层应用组件来处理嵌套子组件的搜索。我们通过这个post从初级阶段跳到了中级阶段。靠着自己。这是一些重大的材料。确保你明白这一点,因为我们会经常使用我们今天介绍的这些概念。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |