React Native 實例 - BBC新聞客戶端

song4r4u 8年前發布 | 41K 次閱讀 ReactNative 移動開發 React Native

 

關于 React Native 的實例, BBC新聞客戶端. 通過訪問BBC的公開網絡接口, 獲取新聞內容, 也可以根據類型顯示. 在編寫代碼中, 學習RN的知識, 源碼是使用ES6的規范編寫, 符合非死book的RN代碼最新規范.

歡迎Follow我的GitHub: https://github.com/SpikeKing

主要技術

  1. 訪問網絡請求, 過濾內容, 獲取數據.
  2. 顯示多媒體頁面, 圖片, 視頻, 鏈接等.

本文源碼的GitHub 下載地址

配置項目

初始化項目 WclBBCNews , 修改 package.json , 添加依賴庫.

Html解析庫: htmlparser , 時間處理庫: moment , 線性梯度庫: react-native-linear-gradient , 視頻庫: react-native-video .

"dependencies": {
  "react": "^0.14.8",
  "react-native": "^0.24.1",

  "htmlparser": "^1.7.7",
  "moment": "^2.11.1",

  "react-native-linear-gradient": "^1.4.0",
  "react-native-video": "^0.6.1"
}

目前, React Native禁止使用 - 初始化項目名稱, 最好使用駝峰式.

初始化主模塊 index.ios.js , 使用 NavigatorIOS 導航頁面, 首頁組件 Feed模塊 .

render() {
  return (
    <NavigatorIOS
 style={{flex:1}}
 translucent={false}
 barTintColor={'#BB1919'}
 titleTextColor={'white'}
 tintColor={'white'}
 initialRoute={{
 component: Feed,
 title: "Feed",
 passProps: {}
 }}/>
 );
}

渲染使用動態加載組件, StatusBar使用淺色樣式.

_renderScene(route, navigator) {
  var Component = route.component;
  StatusBar.setBarStyle('light-content');
  return (
    <Component
 {...route.props}
 changeNavBarHeight={this.changeNavBarHeight}
 navigator={navigator}
 route={route}/>
 );
}

StatusBar 樣式只有兩種, 默認 default , 字是黑色; 可選 light-content , 字是白色.

新聞列表

Feed頁面, 主要以列表形式, 即 ListView 標簽, 顯示新聞. 未加載完成時, 調用頁面加載提示符 ActivityIndicatorIOS , 顯示動畫.

render() {
  // 未加載完成時, 調用加載頁面
  if (!this.state.loaded) {
    return this._renderLoading();
  }
  // ...
}

_renderLoading() {
  return (
    <View style={{flexDirection: 'row', justifyContent: 'center', flex: 1}}>
 <ActivityIndicatorIOS
 animating={this.state.isAnimating}
 style={{height: 80}}
 size="large"/>
 </View>
 );
}

加載完成后, 調用 ListView 顯示頁面, renderRow 渲染每一行, refreshControl 加載頁面的過場.

return (
  <ListView
    testID={"Feed Screen"}
    dataSource={this.state.dataSource}
    renderRow={this._renderStories.bind(this)}
    style={{backgroundColor: '#eee'}}
    contentInset={{top:0, left:0, bottom: 64, right: 0}}
    scrollEventThrottle={200}
    {...this.props}
    refreshControl={
      <RefreshControl
        refreshing={this.state.isRefreshing}
        onRefresh={this._fetchData.bind(this)}
        tintColor='#BB1919'
        title="Loading..."
        progressBackgroundColor="#FFFF00"
      />}
    />
);

每一行使用 Story 模塊渲染.

_renderStories(story) {
  return (
    <Story story={story} navigator={this.props.navigator}/>
 );
}

啟動頁面的時候, 使用 fetch 方法加載數據.

componentDidMount() {
  this._fetchData();
}

通過訪問BBC的網絡請求, 異步獲取數據. 使用 _filterNews 過濾需要的數據, 把數據設置入每一行, 修改狀態 setState , 重新渲染頁面.

_fetchData() {
  this.setState({isRefreshing: true});
  fetch(`http://trevor-producer-cdn.api.bbci.co.uk/content${this.props.collection || '/cps/news/world'}`)
    .then((response) => response.json())
    .then((responseData) => this._filterNews(responseData.relations))
    .then((newItems) => {
      this.setState({
        dataSource: this.state.dataSource.cloneWithRows(newItems),
        loaded: true,
        isRefreshing: false,
        isAnimating: false
      })
    }).done();
}

列表項提供分類顯示功能, 點擊類別, 可以重新加載所選類型的新聞, 把 Feed 頁面再次添加至導航 navigator , 即頁面棧.

_pressedCollection(collection) {
  this.props.navigator.push({
    component: Feed,
    title: collection.content.name,
    passProps: {
      collection: collection.content.id,
      navigator: this.props.navigator
    }
  });
}

點擊列表項, 跳轉至詳情頁面 StoryDetail .

_pressedStory(story) {
  this.props.navigator.push({
    component: StoryDetail,
    title: this._truncateTitle(story.content.name),
    passProps: {story, navigator: this.props.navigator}
  });
}

新聞詳情

主要是解析HTML頁面, 加載并顯示, 除了文字之外, 會顯示圖片\視頻\超鏈接等樣式. 渲染使用動態元素, 狀態 state 的 elements 屬性.

render() {
  if (this.state.loading) {
    return (
      <Text>Loading</Text>
    );
  }
  return this.state.elements;
}

頁面啟動時, 加載數據. 在 _fetchStoryData 方法中, 進行處理, 使用回調返回數據. 主要內容 body 與多媒體 media 通過滾動視圖 ScrollView 的形式顯示出來.

componentDidMount() {
  this._fetchStoryData(
    // media表示視頻或圖片.
    (result, media) => {
      const rootElement = result.find(item => {
        return item.name === 'body';
      });

      XMLToReactMap.createReactElementsWithXMLRoot(rootElement, media)
        .then(array => {
          var scroll = React.createElement(ScrollView, {
            contentInset: {top: 0, left: 0, bottom: 64, right: 0},
            style: {flex: 1, flexDirection: 'column', backgroundColor: 'white'},
            accessibilityLabel: "Story Detail"
          }, array);

          this.setState({loading: false, elements: scroll});
        });
    }
  );
}

處理數據, 使用 fetch 方法, 分離視頻與圖片, 還有頁面, 通過回調 cb(callback) 的處理返回數據.

_fetchStoryData(cb) {
  // 提取數據, 轉換JSON格式, 圖片過濾, 視頻過濾, 組合relations, 解析.
  fetch(`http://trevor-producer-cdn.api.bbci.co.uk/content${this.props.story.content.id}`)
    .then((response) => response.json())
    .then((responseData) => {
      const images = responseData.relations.filter(item => {
        return item.primaryType === 'bbc.mobile.news.image';
      });
      const videos = responseData.relations.filter(item => {
        return item.primaryType === 'bbc.mobile.news.video';
      });
      const relations = {images, videos};
      this._parseXMLBody(responseData.body, (result) => {
        cb(result, relations);
      });
    }).done();
}

使用 Tautologistics 解析 dom 數據與 body 數據. DOM, 即Document Object Model, 文件對象模型.

_parseXMLBody(body, cb) {
  var handler = new Tautologistics.NodeHtmlParser.DefaultHandler(
    function (error, dom) {
      cb(dom)
    }, {enforceEmptyTags: false, ignoreWhitespace: true});

  var parser = new Tautologistics.NodeHtmlParser.Parser(handler);
  parser.parseComplete(body);
}

XML解析類 XMLToReactMap 比較復雜, 不做過多介紹, 參考源碼.

通過編寫新聞類應用, 學習使用網絡請求和解析HTML格式的文本. 多編碼多思考, 不斷學習, React Native 是非常有意思的開發語言.

 

OK, that’s all! Enjoy it!

來自: https://github.com/SpikeKing/WclBBCNews

 本文由用戶 song4r4u 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!