首页完成效果展现:javascript
<div style="text-align:center;"> <img src="https://img2018.cnblogs.com/blog/1312841/201907/1312841-20190718135309802-1875493361.gif" /> </div>java
1、开发占位图组件
在没有数据的时候使用占位图替代 items 的位置。react
在 components 目录里建立 moviesItemPlaceholder.jsajax
import React, { Component } from 'react'; import { View, StyleSheet } from 'react-native'; import { px } from '../utils/device'; export default class MoviesItemPlaceholder extends Component { render() { const arr = [1, 2, 3, 4]; return ( <View style={styles.page}> {arr.map((index) => ( <View style={styles.placeholder} key={index}> <View style={styles.img} /> <View style={styles.title} /> <View style={styles.rate} /> </View> ))} </View> ) } } const styles = StyleSheet.create({ page: { flexDirection: 'row', paddingLeft: px(30) }, placeholder: { width: px(160), marginRight: px(16) }, img: { width: px(160), height: px(224), overflow: 'hidden', borderRadius: px(8), backgroundColor: '#f8f8f8' }, title: { marginTop: px(20), backgroundColor: '#f8f8f8', height: px(30), width: px(130), overflow: 'hidden', borderRadius: px(8) }, rate: { marginTop: px(16), backgroundColor: '#f8f8f8', height: px(24), width: px(130), overflow: 'hidden', borderRadius: px(8) } });
2、首頁数据请求
使用 postman 之类的工具能够看到,首页接口返回的数据字段大体同样,数据均在 subject_collection_items 字段里,能够疯转一个方法量来请求数据。redux
var items = ['showing', 'hot', 'tv', 'variety', 'book', 'music']; items.forEach(type => { this.getList(type); }); getList = (type) => { ajax(type, { start: 0, count: 9 }).then(value => { let state = {} state[type] = value.subject_collection_items; this.setState(state); }) }
首页页面展现
纵向滑动,使用 ScrollView 组件;横向滑动,使用 FlatList 组件,FlatList 组件的 ListEmptyComponent 表示没有数据时显示的组件,在这里放置占位图组件;react-native
import React from "react"; import { View, Text, StatusBar, StyleSheet, ScrollView, FlatList, TouchableWithoutFeedback } from "react-native"; import { connect } from 'react-redux'; import ajax from "../utils/ajax"; import Header from '../components/header'; import ItemsHeader from '../components/itemsHeader'; import MoviesItem from '../components/moviesItem'; import MoviesItemPlaceholder from '../components/moviesItemPlaceholder'; import Icon from 'react-native-vector-icons/AntDesign'; import { px } from "../utils/device"; class Home extends React.Component { constructor(props) { super(props); this.state = { showing: [], hot: [], tv: [], variety: [], book: [], music: [], } var items = ['showing', 'hot', 'tv', 'variety', 'book', 'music']; items.forEach(type => { this.getList(type); }); } getList = (type) => { ajax(type, { start: 0, count: 9 }).then(value => { let state = {} state[type] = value.subject_collection_items; this.setState(state); }) } render() { const { dispatch, value, navigation } = this.props; const { showing, hot, tv, variety, book, music } = this.state; const sections = [ { title: '影院热映', data: showing, type: 'showing' }, { title: '豆瓣热门', data: hot, type: 'hot' }, { title: '近期热门剧集', data: tv, type: 'tv' }, { title: '近期热门综艺节目', data: variety, type: 'variety' }, { title: '畅销图书', data: book, type: 'book' }, { title: '热门单曲榜', data: music, type: 'music' } ] return ( <View style={styles.page}> <Header showBack={false} title='豆瓣评分' backgroundColor='#00b600' color='#fff' /> <ScrollView> <View style={styles.search}> <TouchableWithoutFeedback onPress={() => alert('search')}> <View style={styles.searchView}> <Icon name='search1' size={px(30)} color='#ccc' /> <Text style={styles.searchText}>搜索</Text> </View> </TouchableWithoutFeedback> </View> {sections.map((list, index) => ( <View key={index} style={styles.list}> <ItemsHeader title={list.title} onPress={() => navigation.push('List', { data: list })} /> <FlatList horizontal={true} data={list.data} keyExtractor={(item, index) => 'item' + index} ListEmptyComponent={() => <MoviesItemPlaceholder />} renderItem={({ item, index }) => ( <View style={{ marginRight: index !== showing.length - 1 ? px(16) : px(30), marginLeft: index === 0 ? px(30) : 0 }}> <MoviesItem data={item} /> </View> )} /> </View> ))} </ScrollView> </View> ); } } const select = (store) => { return { value: store.num.value, } } export default connect(select)(Home); const styles = StyleSheet.create({ page: { flex: 1, backgroundColor: '#fff' }, search: { backgroundColor: '#00b600', height: px(80), alignItems: 'center', justifyContent: 'center' }, searchView: { height: px(50), width: px(710), borderRadius: px(8), backgroundColor: '#fff', flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }, searchText: { fontSize: px(26), color: '#ccc', marginLeft: px(6) }, list: { marginBottom: px(30) } });
4、缓存列表数据
当处于弱网环境时,打开应用,可能会显示好久的占位图,此时咱们能够将列表数据缓存至本地,每次进入应用先展现本地缓存的数据,而后请求数据,替换本地数据。缓存
此时,就可使用 redux 了。工具
编译 reducer
为了目录整清晰点(让 redux 相关的代码文件都存储于 store 目录下),将 src 目录下的 reducer 目录移动到 store 目录下,并在 reducer 目录建立 list.js。post
const initList = { showing: [], hot: [], tv: [], variety: [], book: [], music: [] } const setListState = (state = initList, action) => { switch (action.type) { case 'showing': return { ...state, showing: action.data } case 'hot': return { ...state, hot: action.data } case 'tv': return { ...state, tv: action.data } case 'variety': return { ...state, showing: action.data } case 'book': return { ...state, book: action.data } case 'music': return { ...state, music: action.data } default: return state; } } export default setListState;
在 reducer 的 index.js 中导入 setListState;flex
... import setListState from './list'; ... export default combineReducers({ ... list: setListState ... });
修改 store/index.js 的路径引入
import reducer from './reducer';
编辑 action
将以前src下的 action 目录删除,在 store 目录下建立 action.js。
export function login(data) { return { type: 'login', data } } export function logout(data) { return { type: 'logout', data } } // set 首页列表数据 export function setShowing(data) { return { type: 'showing', data } } export function setHot(data) { return { type: 'hot', data } } export function setTv(data) { return { type: 'tv', data } } export function setVariety(data) { return { type: 'variety', data } } export function setBook(data) { return { type: 'book', data } } export function setMusic(data) { return { type: 'music', data } }
编辑首页
导入修改 store 的方法:
import { setShowing, setHot, setTv, setVariety, setBook, setMusic } from '../store/action';
页面获取 store 存储的数据:
const select = (store) => { return { showing: store.list.showing, hot: store.list.hot, tv: store.list.tv, variety: store.list.variety, book: store.list.book, music: store.list.music } } export default connect(select)(Home);
页面获取数据时,改变 store 里的数据
因为须要 save 数据,因此前面建立的 getList 和传入的 items 须要作一些改变:
... var items = [ { type: 'showing', save: setShowing }, { type: 'hot', save: setHot }, { type: 'tv', save: setTv }, { type: 'variety', save: setVariety }, { type: 'book', save: setBook }, { type: 'music', save: setmusic }, ] items.forEach(item => { this.getList(item); }); ... getList = (item) => { ajax(item.type, { start: 0, count: 9 }).then(value => { this.props.dispatch(item.save(value.subject_collection_items)); }) }
修改 render 里的获取数据方式:
render(){ const { dispatch, value, navigation, showing, hot, tv, variety, book, music } = this.props; ... }
至此,首页算是开发完了。