为了账号安全,请及时绑定邮箱和手机立即绑定

【React.js模仿大众点评webapp】实战教程(9)开发搜索结果页

搜索页面的开发 - part1

源代码地址
购买实战课程后,在播放视频页面右侧可查看到章节源代码。

part1 && part2
  • part1 主要介绍一些正式进入页面开发前的准备工作,但是也都非常重要(否则不会单独拿出来)
  • part2 正式开发搜索页面,详解页面每一部分的开发过程
两个入口

从首页进入搜索结果页的场景有以下两种:

  • 通过输入框输入关键字搜索
  • 通过轮播图的类型搜索

输入框进入搜索页面的的实现方式,我们最后再介绍,到时候会引入约束性和非约束性组件的概念,内容比较多。

轮播图进入搜索页面的方式比较简单,就是通过<Link>组件设置一个路由就好了

<Link to="/search/jingdian"><li className="float-left jingdian">景点</li></Link>
<Link to="/search/ktv"><li className="float-left ktv">KTV</li></Link>

演示过程中需要注意的是,这两种方式跳转到搜索结果页时路由是怎样的。

路由配置

找到配置路由的文件./app/router/routeMap.jsx,找到搜索结果页的代码

<Router history={this.props.history}>
    <Route path='/' component={App}>
        ......
        <Route path='/search/:category(/:keyword)' component={Search}/>
        ......
    </Route>
</Router>

路由定位的页面在./app/containers/Search中,再次强调,它也有一个App的父组件。

注意看路由的配置规则/search/:category(/:keyword),在之前讲react-router基础知识的时候,都已经介绍过了。这里再重申一遍,其中/search是路径,/:category是必填参数,(/:keyword)是选填参数。

上文让大家注意两种跳转到搜索结果页的方式的路由,可以和这里的规则对应一下。

代码中如何得到这些参数呢?可以通过以下的方式得到:

componentDidMount() {
    const params = this.props.params
    console.log('category param: ' + params.category)
    console.log('key param:' + params.keyword)
}
约束性和非约束性组件

非约束性

针对<input>输入框这种类型,你可以通过这种方式来实现(其中defaultValue就是原生DOM中的value属性)

<input type="text" defaultValue="a" ref="input"/>

获取输入框的值的时候,需要这样做——即通过查询DOM,获取DOM属性的方式来做。

var input = this.refs.input
console.log(input.value)

这样做,跟之前jquery的做法一样,都是围绕着DOM来做的。缺点有两个:

  • 依赖DOM操作,不符合组件化的设计,也不易扩展
  • 查询DOM消耗更多性能

约束性

比较推荐的方式是这一种。即监控<input>的变化,将值实时保存到state中,直接从state中获取值。

<input type="text" value={this.state.name} onChange={this.handleChange} />

//...省略部分代码
handleChange: function(e) {
  this.setState({name: e.target.value});
}

React或者Vue都是一种基于数据驱动视图的设计方式,定好数据和视图的规则之后,只更改数据,不直接操作DOM。操作DOM的事情,交给React或者Vue这个框架的代码来搞定。

最后看一下实际代码中如何修改Home页面的输入框。

搜索结果页的开发 - part2

源码地址 https://github.com/wangfupeng1988/react-simple-o2o-demo/tree/stage3-search-page-2

页面效果

抽离 SearchInput 组件

根据最终实现的效果可以看到,搜索结果页的头部有一个输入框,而首页的头部也有一个输入框,两者的作用都是一样的。因此要把这个输入框抽离成一个组件,两个地方公用。

由于搜索结果页还没有开始创建,因此处理的这个组件先给首页的头部用,即用于HomeHeader组件中。

创建./app/components/SearchInput组件,并引用到HomeHeader中。

<SearchInput value="" enterHandle={this.enterHandle.bind(this)}/>

引用时需要传递两个参数,value即引用时要显示的默认值,enterHandle即在其中输入内容并回车时,要触发的事件。具体的实现,看实际代码即可。

SearchInput组件中,首先要满足约束性组件的条件,第二要用上传入的enterHandle的方法。

SearchHeader 组件

搜索结果页的头部,也是一个红色背景的Header,但是这个Header的样子,和之前做的其他页面的都不一样,因此又要重新做一个Header组件。

创建./app/components/SearchHeader组件,并引用到Search页面中。

<SearchHeader keyword={params.keyword}/>

注意,这里要传入一个keyword属性,即把搜索结果页拿到的keyword参数传递进去 —— 因为要在头部的 input 中显示搜索的关键字。(这个params.keyword在 part1 的时候已经解说过了)

SearchHeader组件的代码实现中,左侧有一个返回按钮,然后就是输入框。这里的输入框当然要引用刚刚抽离出来的SearchInput组件。

<SearchInput value={this.props.keyword || ''} enterHandle={this.enterHandle.bind(this)}/>

两个必要的参数是必须传的。其中传递给value参数的,正好是接收到的keyword属性值

结果列表

这里的结果列表和首页中的“猜你喜欢”基本差不多,也是需要在subpage目录下创建一个子页面,然后在子页面中获取数据,并传递给./app/components/List,加载更多的实现方式,也是一个样子的。

唯一不同的是,如果在搜索结果页头部的输入框中再次输入内容重新进行搜索时,就需要多一步处理。

    // 处理重新搜索
    componentDidUpdate(prevProps, prevState) {
        const keyword = this.props.keyword
        const category = this.props.category

        // 搜索条件完全相等时,忽略。重要!!!
        if (keyword === prevProps.keyword && category === prevProps.category) {
            return
        }

        // 重置 state
        this.setState(initialState)

        // 重新加载数据
        this.loadFirstPageData()
    }

这里需要理解componentDidMountcomponentDidUpdate两个生命周期的不同。

  • 页面初次渲染,会走componentDidMount
  • 页面再次渲染,就不会走componentDidMount,而只走componentDidUpdate
点击查看更多内容
11人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消