React Native 实例 - 房产搜索

ctpy9661 8年前
   <p> </p>    <p><a href="/misc/goto?guid=4958872159930900776" rel="nofollow,noindex">React Native</a> 开发已经初见端倪, 可以完成最基本的功能. 通过开发一些简单的应用, 可以更加熟练的掌握 RN 的知识. 本文介绍非常简单的一款 <strong>房产搜索</strong> 的App, 通过调用公开的搜索服务, 把网络的数据展示在应用中. 通过代码更多的了解 RN 的特性.</p>    <p>更多: <a href="/misc/goto?guid=4959670394917131015" rel="nofollow,noindex">http://www.wangchenlong.org/</a></p>    <p>欢迎Follow我的GitHub: <a href="/misc/goto?guid=4959652813041333444" rel="nofollow,noindex">https://github.com/SpikeKing</a></p>    <p><img src="https://simg.open-open.com/show/b61cab5af9c035288f343addfc36e543.png"></p>    <p>已经实现 iOS 版本, 仅供学习和参考, 可以直接运行, 但是 RN 变化较快, 可能不兼容. 关于在运行项目中可能出现的问题, 请参考.</p>    <p>本文源码的GitHub <a href="/misc/goto?guid=4959670395057399740" rel="nofollow,noindex">下载地址</a></p>    <h2>配置</h2>    <p>初始化 React Native 的项目.</p>    <pre>  <code class="language-javascript">react-native init WclPropertyFinder  </code></pre>    <p>修改 Android 的 Gradle 构建版本.</p>    <pre>  <code class="language-javascript">dependencies {      classpath 'com.android.tools.build:gradle:1.2.3'  }  </code></pre>    <p>运行 iOS 和 Android 项目.</p>    <p>调试: iOS 模拟机, Cmd + R 重新加载, Cmd + D 模拟晃动; Android, 晃动手机.</p>    <p>修改 index.ios.js 的内容, 启动新的模块.</p>    <pre>  <code class="language-javascript">'use strict';    var React = require('react-native');    // 搜索页面  var SearchPage = require('./SearchPage')    // 使用Navigator管理组件, 注意: 不要纠结于跨平台, 学习为主  class WclPropertyFinderApp extends React.Component {    render() {      return (        <React.NavigatorIOS   style={styles.container}   initialRoute={{   title: '搜房产',   component: SearchPage,   }}/>   );   }  }    // 样式  var styles = React.StyleSheet.create({   text: {   color: 'black',   backgroundColor: 'white',   fontSize: 30,   margin: 80   },   container: {   flex: 1   }  });    // 注册组件  React.AppRegistry.registerComponent('WclPropertyFinder', () => WclPropertyFinderApp);  </code></pre>    <h2>搜索页</h2>    <p>搜索页(SearchPage)包含一个搜索库, 可以使用地址或邮编搜索英国的房产信息.</p>    <p>通过输入框的参数创建网络请求URL, 并把请求发送出去, 获取信息.</p>    <pre>  <code class="language-javascript">/**   * 访问网络服务的Api, 拼接参数   * 输出: http://api.nestoria.co.uk/api?country=uk&pretty=1&encoding=json&listing_type=buy&action=search_listings&page=1&place_name=London   *   * @param key 最后一个参数的键, 用于表示地理位置   * @param value 最后一个参数的值, 具体位置   * @param pageNumber page的页面数   * @returns {string} 网络请求的字符串   */  function urlForQueryAndPage(key, value, pageNumber) {    var data = {      country: 'uk',      pretty: '1',      encoding: 'json',      listing_type: 'buy',      action: 'search_listings',      page: pageNumber    };      data[key] = value;      var querystring = Object.keys(data)      .map(key => key + '=' + encodeURIComponent(data[key]))      .join('&');    return 'http://api.nestoria.co.uk/api?' + querystring;  }  </code></pre>    <p>获取信息以后, 使用 <strong>Navigator</strong> 跳转到搜索结果页面, 使用 <strong>ListView</strong> 显示详细内容.</p>    <pre>  <code class="language-javascript">/**   * 执行网络请求, 下划线表示私有   * @param query url   * @private   */  _executeQuery(query) {    console.log(query);    this.setState({isLoading: true});      // 网络请求    fetch(query)      .then(response => response.json())      .then(json => this._handleResponse(json.response))      .catch(error => this.setState({        isLoading: false,        message: 'Something bad happened ' + error      }));  }    /**   * 处理网络请求的回调   * @param response 请求的返回值   * @private   */  _handleResponse(response) {    this.setState({isLoading: false, message: ''});    if (response.application_response_code.substr(0, 1) === '1') {      console.log('Properties found: ' + response.listings.length);        // 使用listings调用结果页面SearchResults      this.props.navigator.push({        title: '搜索结果',        component: SearchResults,        passProps: {listings: response.listings}      });    } else {      this.setState({message: 'Location not recognized; please try again.'});    }  }  </code></pre>    <h2>搜索结果</h2>    <p>把获取的房产信息, 逐行显示于ListView中.</p>    <pre>  <code class="language-javascript">/**   * 渲染列表视图的每一行   * @param rowData 行数据   * @param sectionID 块ID   * @param rowID 行ID   * @returns {XML} 页面   */  renderRow(rowData, sectionID, rowID) {    var price = rowData.price_formatted.split(' ')[0];    return (      <TouchableHighlight        onPress={()=>this.rowPressed(rowData.guid)}        underlayColor='#dddddd'>        <View style={styles.rowContainer}>          <Image style={styles.thumb} source={{uri:rowData.img_url}}/>          <View style={styles.textContainer}>            <Text style={styles.price}>${price}</Text>            <Text style={styles.title} numberOfLines={1}>              {rowData.title}            </Text>          </View>        </View>      </TouchableHighlight>    );  }    /**   * 渲染, 每行使用renderRow渲染   * @returns {XML} 结果页面的布局   */  render() {    return (      <ListView        dataSource={this.state.dataSource}        renderRow={this.renderRow.bind(this)}        />    );  }  </code></pre>    <p>点击ListView的行, 可以跳转至 <strong>房产信息</strong> 页面.</p>    <pre>  <code class="language-javascript">/**   * 点击每行, 通过行数选择信息   * @param propertyGuid 行ID   */  rowPressed(propertyGuid) {    var property = this.props.listings.filter(prop => prop.guid === propertyGuid)[0];      this.props.navigator.push({      title: '房产信息',      component: PropertyView,      passProps: {property: property}    });  }  </code></pre>    <h2>房产信息</h2>    <p>房产信息是单纯显示页面, 显示图片和文字内容.</p>    <pre>  <code class="language-javascript">class PropertyView extends Component {    render() {      var property = this.props.property; // 由SearchResult传递的搜索结果      var stats = property.bedroom_number + ' bed ' + property.property_type;      if (property.bathroom_number) {        stats += ', ' + property.bathroom_number + ' ' +          (property.bathroom_number > 1 ? 'bathrooms' : 'bathroom');      }        var price = property.price_formatted.split(' ')[0];        return (        <View style={styles.container}>          <Image style={styles.image}                 source={{uri: property.img_url}}/>          <View style={styles.heading}>            <Text style={styles.price}>${price}</Text>            <Text style={styles.title}>{property.title}</Text>            <View style={styles.separator}/>          </View>          <Text style={styles.description}>{stats}</Text>          <Text style={styles.description}>{property.summary}</Text>        </View>      );    }  }  </code></pre>    <p>最终效果</p>    <p><img src="https://simg.open-open.com/show/8788f6124aa2730e8c81018d46980957.gif"></p>    <p>使用 RN 开发应用非常快捷, 可以复用代码逻辑到多个平台.</p>    <p>本文参考我的朋友Tom的一篇 <a href="/misc/goto?guid=4959670395147321274" rel="nofollow,noindex">文章</a> .</p>    <p>OK, that’s all! Enjoy it!</p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959670395236294113" rel="nofollow">http://www.wangchenlong.org/2016/04/12/1604/121-rn-property-demo/</a></p>