动态设置标题栏背景
// 关联dva
const mapStateToProps = ({ album }: RootState) => {
return {
datas: album.albumDatas,//这里的home就是model中的namespace
}
}
//这里需要connect对象
const connector = connect(mapStateToProps)
//自动推导dva中的state类型
type ModelState = ConnectedProps<typeof connector>
// 这里需要继承ModelState ,区别于antd pro中的umi.js umi不需要
// antd umi.js中使用dva:https://huangxiaoguo.blog.csdn.net/article/details/114890454
interface IProps extends ModelState {
navigation: RootStackNavigation,
headerHeight: number,
route: RouteProp<RootStackParamList, 'Album'>
}
componentDidMount() {
const { navigation, dispatch, route: { params: { item: { id, image, title } } } } = this.props;
navigation.setOptions({
headerTitle: title,
headerTransparent: true,//导航栏透明
headerTitleStyle: {
// opacity: 0
},
// headerBackground: () => {
// return (
// <Animated.View style={styles.headerBackground} />
// )
// }
})
TabView使用
models/album.ts:数据类
pages/home/album:分类模块
pages/home/album/index.tsx:分类页面
pages/home/album/data.d.ts:分类数据类型
pages/home/album/service.ts:分类数据请求
pages/home/album/components/tab:tab分类
pages/home/album/list:节目分类
pages/home/album/introdution:简介分类
- models/album.ts:数据类
import { Model, Effect } from 'dva-core-ts'
import { Reducer } from 'redux'
//导入service远端数据请求
import { getAlbumData } from '@/pages/home/album/service'
import type { AlbumType } from '@/pages/home/album/data'
import { RootState } from '.'
import { pageCurrent, perpage } from '@/config/contant'
type AlbumState = {
albumDatas: AlbumType
}
interface AlbumModelType extends Model {
namespace: string
state: AlbumState;//封装后台返回的数据
effects: {
asyncAlbumData: Effect;
};
reducers: {
setStates: Reducer<AlbumState>,
};
}
const AlbumModel: AlbumModelType = {
namespace: 'album',
state: {
albumDatas: {
id: '',
introduction: '',
summary: '',
thumbnailUrl: '',
title: '',
author: {
name: '',
avatar: ''
},
list: []
}
},
//异步
effects: {
*asyncAlbumData({ payload }, { call, put }) {
const response = yield call(getAlbumData, { ...payload })
if (response && response instanceof Object) {
const { data } = response
yield put({
type: 'setStates',
payload: {
albumDatas: { ...data }
}
})
}
},
},
//同步
reducers: {
setStates(state, action) {
return {
...state,
...action.payload,
};
},
}
}
export default AlbumModel
- pages/home/album/index.tsx:分类页面
import React, { Component } from 'react';
import { View, Text, Image, Animated, StyleSheet } from 'react-native';
import { RootState } from '@/models/index';
import { connect, ConnectedProps } from 'react-redux';
import { RootStackNavigation, RootStackParamList } from '@/navigator/index';
import { RouteProp } from '@react-navigation/native';
import { useHeaderHeight } from '@react-navigation/elements';
import { BlurView } from '@react-native-community/blur'
import Tab from './components/tab'
// 关联dva
const mapStateToProps = ({ album }: RootState) => {
return {
datas: album.albumDatas,//这里的home就是model中的namespace
}
}
//这里需要connect对象
const connector = connect(mapStateToProps)
//自动推导dva中的state类型
type ModelState = ConnectedProps<typeof connector>
// 这里需要继承ModelState ,区别于antd pro中的umi.js umi不需要
// antd umi.js中使用dva:https://huangxiaoguo.blog.csdn.net/article/details/114890454
interface IProps extends ModelState {
navigation: RootStackNavigation,
headerHeight: number,
route: RouteProp<RootStackParamList, 'Album'>
}
class Album extends Component<IProps> {
componentDidMount() {
const { navigation, dispatch, route: { params: { item: { id, image, title } } } } = this.props;
navigation.setOptions({
headerTitle: title,
headerTransparent: true,//导航栏透明
headerTitleStyle: {
opacity: 0
},
headerBackground: () => {
return (
<Animated.View style={styles.headerBackground} />
)
}
})
dispatch({
type: 'album/asyncAlbumData',
payload: {
id
}
})
}
render() {
const { headerHeight, route: { params: { item: { id, image, title } } }, datas } = this.props
return (
<View style={styles.container}>
<View style={[styles.header, { paddingTop: headerHeight }]}>
<Image source={{ uri: image }} style={styles.backgroud} />
<BlurView blurType='light' blurAmount={10} style={StyleSheet.absoluteFillObject} />
<View style={styles.leftView}>
<Image source={{ uri: image }} style={styles.thumbNail} />
<Image source={require('@/assets/images/cover-right.png')} style={styles.coverRight} />
</View>
<View style={styles.rightView}>
<Text style={styles.title}>{datas.title}</Text>
<View style={styles.summary}>
<Text numberOfLines={1} style={styles.summaryText}>{datas.summary}</Text>
</View>
{
datas.author?.avatar ? (
<View style={styles.author}>
<Image source={{ uri: datas.author?.avatar }} style={styles.avatar} />
<Text style={styles.name}>{datas.author.name}</Text>
</View>
) : null
}
</View>
</View>
{/* 标签页面 */}
<Tab />
</View>
);
}
}
//获取标题栏高度
function Wrapper(props: IProps) {
const headerHeight = useHeaderHeight()
return <Album {...props} headerHeight={headerHeight} />
}
const styles = StyleSheet.create({
headerBackground: {
flex: 1,
},
container: {
flex: 1
},
header: {
height: 260,
flexDirection: 'row',
paddingHorizontal: 20,
alignItems: 'center'
},
backgroud: {
...StyleSheet.absoluteFillObject,
},
leftView: {
marginRight: 26
},
thumbNail: {
width: 98,
height: 98,
borderColor: '#fff',
borderWidth: StyleSheet.hairlineWidth,
borderRadius: 8,
backgroundColor: '#fff'
},
coverRight: {
height: 98,
position: 'absolute',
right: -25,
resizeMode: 'contain'
},
rightView: {
flex: 1,
},
title: {
color: '#fff',
fontSize: 18,
fontWeight: '700'
},
summary: {
backgroundColor: 'rgba(0,0,0,0.3)',
padding: 10,
marginVertical: 10,
borderRadius: 4
},
author: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 10,
},
avatar: {
borderRadius: 13,
height: 26,
width: 26,
marginRight: 8,
},
name: {
color: '#fff',
fontSize: 12,
},
summaryText: {
color: '#fff'
}
});
// export default Album;
export default connector(Wrapper)
- pages/home/album/data.d.ts:分类数据类型
/**
* 获取Item
*/
export type ListType = {
date?: string,
duration?: string,
id: string,
playVolume: number,
title?: string
}
/**
* 获取作者
*/
export type AuthorType = {
avatar?: string,
name?: string,
}
/**
* 频道模块
*/
export type AlbumType = {
id: string,
introduction: string,
summary: string,
thumbnailUrl: string,
title: string,
author: AuthorType,
list: ListType[]
}
- pages/home/album/service.ts:分类数据请求
import request from '@/config/request';
import type { ListParamsType } from '@/models/data'
/**
* 数据
* @param params
* @returns
*/
export async function getAlbumData(params: { id: number }): Promise<any> {
return request({
url: '/album/list',
method: 'GET',
params: { ...params }
});
}
- pages/home/album/components/tab:tab分类
import React, { Component } from 'react'
import { SceneRendererProps, TabBar, TabView } from 'react-native-tab-view'
import Introdution from '@/pages/home/album/introdution'
import List from '@/pages/home/album/list'
import { Platform, StyleSheet } from 'react-native'
type IRoute = {
key: string,
title: string
}
type IState = {
index: number
routes: IRoute[],
}
type IProps = {}
class Tab extends Component<IProps, IState>{
state = {
routes: [
{ key: 'introdution', title: '简介' },
{ key: 'albums', title: '节目' }
],
index: 0
}
render() {
const { routes, index } = this.state
return (
<TabView
navigationState={{
routes: [...routes],
index: index,
}}
onIndexChange={(index: number) => {
//切换标签
this.setState({
index
})
}}
renderScene={({ route }: { route: IRoute }) => {
//标签对应的页面
switch (route.key) {
case 'introdution':
return <Introdution />;
case 'albums':
return <List />;
default:
break;
}
return null
}}
//修改tab样式
renderTabBar={(props: SceneRendererProps & { navigationState: IState }) => {
return <TabBar {...props}
scrollEnabled={true}
tabStyle={styles.tabStyle}
labelStyle={styles.label}
style={styles.tabbar}
indicatorStyle={styles.indicator} />
}} />
)
}
}
const styles = StyleSheet.create({
tabStyle: {
width: 80
},
label: {
color: '#333'
},
tabbar: {
backgroundColor: '#fff',
...Platform.select({
android: {
elevation: 0,
borderBottomColor: '#e3e3e3',
borderBottomWidth: StyleSheet.hairlineWidth
}
})
},
indicator: {
backgroundColor: '#eb6d48',
borderLeftWidth: 20,
borderRightWidth: 20,
borderColor: '#fff'
}
})
export default Tab
- pages/home/album/list:节目分类
import { RootState } from '@/models/index';
import React, { Component } from 'react';
import { FlatList, ListRenderItemInfo, StyleSheet, Text, View } from 'react-native';
import { connect, ConnectedProps } from 'react-redux';
import Touchable from '@/components/touchable/index'
import IconFont from '@/assets/iconfont';
import { ListType } from '../data';
// 关联dva
const mapStateToProps = ({ album }: RootState) => {
return {
datas: album,//这里的home就是model中的namespace
}
}
//这里需要connect对象
const connector = connect(mapStateToProps)
//自动推导dva中的state类型
type ModelState = ConnectedProps<typeof connector>
// 这里需要继承ModelState ,区别于antd pro中的umi.js umi不需要
// antd umi.js中使用dva:https://huangxiaoguo.blog.csdn.net/article/details/114890454
interface IProps extends ModelState {
}
class List extends Component<IProps> {
//每个item数据
renderItem = ({ item, index }: ListRenderItemInfo<ListType>) => {
return (
<Touchable style={styles.item} >
<View style={styles.left}>
<Text style={styles.serial}>{index + 1}</Text>
</View>
<View style={styles.centerView}>
<Text style={styles.title}>{item.title}</Text>
<View style={styles.centerRight}>
<View style={styles.volumeView}>
<IconFont name="icon24gf-headphones" color="#939393" />
<Text style={styles.otherText}>{item.playVolume}</Text>
</View>
<View style={styles.duration}>
<IconFont name="iconshijian" color="#939393" />
<Text style={styles.otherText}>{item.duration}</Text>
</View>
</View>
</View>
<View>
<Text style={styles.date}>{item.date}</Text>
</View>
</Touchable>
)
}
render() {
const { datas: { albumDatas: { list } } } = this.props
return (
<FlatList
style={styles.container}
data={list}
renderItem={this.renderItem}
keyExtractor={(item, index) => index + ''} //默认是以id来区分的,可以省略改设置,当无id字段的时候可以通过keyExtractor创建 keys
// keyExtractor={(item, index) => item.id} //默认是以id来区分的,可以省略改设置,当无id字段的时候可以通过keyExtractor创建 keys
/>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#fff'
},
item: {
flexDirection: 'row',
padding: 20,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#dedede',
},
left: {
justifyContent: 'center',
alignItems: 'center',
},
serial: {
color: '#838383',
fontWeight: '800',
},
title: {
fontWeight: '500',
color: '#333',
marginBottom: 15,
},
centerView: {
flex: 1,
marginHorizontal: 25,
},
centerRight: {
flexDirection: 'row',
},
volumeView: {
flexDirection: 'row',
marginRight: 10,
},
duration: { flexDirection: 'row' },
otherText: {
marginHorizontal: 5,
color: '#939393',
fontWeight: '100',
},
date: {
color: '#939393',
fontWeight: '100',
},
});
// export default List;
export default connector(List);
- pages/home/album/introdution:简介分类
import { RootState } from '@/models/index';
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { connect, ConnectedProps } from 'react-redux';
// 关联dva
const mapStateToProps = ({ album }: RootState) => {
return {
datas: album,//这里的home就是model中的namespace
}
}
//这里需要connect对象
const connector = connect(mapStateToProps)
//自动推导dva中的state类型
type ModelState = ConnectedProps<typeof connector>
// 这里需要继承ModelState ,区别于antd pro中的umi.js umi不需要
// antd umi.js中使用dva:https://huangxiaoguo.blog.csdn.net/article/details/114890454
interface IProps extends ModelState {
}
class Introdution extends Component<IProps>{
render() {
const { datas } = this.props
return (
<View style={styles.container}>
<Text>{datas.albumDatas.introduction}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
padding: 10
}
})
// export default Introdution;
export default connector(Introdution);