这个项目应该是一个标杆项目,看到之前很有几个项目都是按照这个项目的页面摆放顺序来的

不过可以作为自己做项目的一种方式

源码地址为:https://github.com/pgg-pgg/imooc_gp

项目的数据流是mobx

启动页不是定时器自动跳转那种,而是滑动那种

我们分析代码如下







上面是启动页的

//index.js
/** @format */ import {AppRegistry} from 'react-native';
import setup from "./js/pages/setup"
import {name as appName} from './app.json'; AppRegistry.registerComponent(appName, () => setup);
//js/pages/setup.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow
*/ import React, {Component} from 'react';
import {Navigator} from 'react-native-deprecated-custom-components'
import MobxTest from "../MobxTest";
import MyPageTest from "./My/MyPageTest";
import WelcomePage from "./WelcomePage"; function setup() {
//进行一些初始化的配置
class Root extends Component {
renderScene(route, navigator) {
let Component = route.component;
return <Component {...route.params} navigator={navigator}/>
} render() {
return <Navigator
initialRoute={{component: WelcomePage}}
renderScene={(route, navigator)=>this.renderScene(route, navigator)}
/>
}
}
return <Root/>;
} module.exports = setup;

首先进入的是welcomePage页面

//js/pages/WelcomePage.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Image,
Text,
View, AsyncStorage,
} from 'react-native';
import NavigationBar from "../common/NavigationBar"
import HomePage from "./HomePage"
import GuidePage from "./GuidePage";
import ThemeDao from "../expand/dao/ThemeDao";
import SplashScreen from 'react-native-splash-screen'
export default class WelcomePage extends Component{ openApp(){
//进行了判断是不是第一次打开
AsyncStorage.getItem('isFirst',(error,result)=>{ if (result === 'false') {
console.log('不是第一次打开'); this.props.navigator.resetTo({
//不是第一次打开就是进入home页面
component:HomePage,
params:{
theme:this.theme,
...this.props
}
}) } else {
console.log('第一次打开');
//是第一次打开就进入导航页
this.props.navigator.replace({
component:GuidePage,
params:{
theme:this.theme,
...this.props
}
})
}
});
}
componentDidMount(): void {
new ThemeDao().getTheme().then(data=>{
this.theme = data;
})
this.timer = setTimeout(()=>{
SplashScreen.hide();
this.openApp()
},1000)
} componentWillUnmount(): void {
this.timer&&clearTimeout(this.timer);
} constructor(props){
super(props)
} render(){
return null;
}
}

第一次打开进入的导航页面

//GuidePage
import {StyleSheet, View, Button, Text, Image, TouchableOpacity,AsyncStorage} from 'react-native';
import React, {Component} from 'react';
import {PagerTabIndicator, IndicatorViewPager, PagerTitleIndicator, PagerDotIndicator} from 'rn-viewpager';
import HomePage from "./HomePage"; export default class GuidePage extends Component {
render() {
let text1 = '消费者第一\n合作伙伴第二\nQunar第三';
let text2 = '大声说话\n无\'总\'称谓\n遇到批评三不问';
let text3 = '高层不诿过\n中层不放羊\n基层不跳步'; return (
<View style={{flex: 1}}>
<IndicatorViewPager
style={{flex: 1}}
indicator={GuidePage._renderDotIndicator()}>
<View style={{backgroundColor: '#ff8800', justifyContent: 'center'}}>
<Image resizeMode={'contain'} style={styles.image}
source={require('../../res/images/s_0_1.png')}/>
<Text style={styles.text_desc}>{text1}</Text>
</View>
<View style={{backgroundColor: '#669900', justifyContent: 'center'}}>
<Image resizeMode={'contain'} style={styles.image}
source={require('../../res/images/s_1_1.png')}/>
<Text style={styles.text_desc}>{text2}</Text>
</View>
<View style={{backgroundColor: '#aa66cc', justifyContent: 'center'}}>
<Image resizeMode={'contain'} style={styles.image}
source={require('../../res/images/s_2_1.png')}/>
<Text style={styles.text_desc}>{text3}</Text>
<TouchableOpacity onPress={()=>{
// 存储
AsyncStorage.setItem('isFirst','false',(error)=>{
if (error) {
alert(error);
}
});
this.props.navigator.resetTo({
component:HomePage,
params:{
// theme:this.props.theme,
...this.props
}
})
}}>
<Text style={styles.text}>开始使用</Text>
</TouchableOpacity>
</View>
</IndicatorViewPager>
</View>
);
} static _renderDotIndicator() {
return <PagerDotIndicator pageCount={3}/>;
} } const styles = StyleSheet.create({
text: {
alignSelf: 'center',
padding: 5,
backgroundColor: '#2196f3',
borderRadius: 5,
fontSize: 18,
color: 'white', },
text_desc: {
height:200,
textAlign: 'center',
textAlignVertical:'center',
fontSize: 20,
color: 'white',
alignSelf: 'center',
},
image: {
width: 200,
height: 200,
alignSelf: 'center'
},
btn: {
width: 150,
height: 40,
backgroundColor: '#1296db',
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 50 },
btnText: {
fontSize: 18,
color: '#fff'
}, });

//js/pages/HomePage.js
//里面的tab切换,根据选中的跳转进去不同的页面
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow
*/ import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Image,
Text,
View,
DeviceEventEmitter, } from 'react-native';
import TabNavigator from 'react-native-tab-navigator'
import PopularPage from "./popular/PopularPage";
import Toast ,{DURATION}from "react-native-easy-toast";
import TrendingPage from "./trending/TrendingPage";
import FavoritePage from "./favorite/FavoritePage";
import MyPage from "./My/MyPage";
import BaseComponent from "./BaseComponent";
import codePush from "react-native-code-push"; export const ACTION_HOME = {A_SHOW_TOAST:'showToast',A_RESTART:'restart',A_THEME:'THEME'};
export const FLAG_TAB={
flag_popularTab:'tb_popular',
flag_trendingTab:'tb_trending',
flag_favoriteTab:'tb_favorite',
flag_myTab:'tb_my',
}
export default class HomePage extends BaseComponent {
constructor(props) {
super(props);
let selectedTab=this.props.selectedTab?this.props.selectedTab:'tb_popular';
this.state = {
selectedTab: selectedTab,
theme:this.props.theme,
}
} componentDidMount(): void {
super.componentDidMount();
this.listener = DeviceEventEmitter.
addListener('ACTION_HOME',
(action,params)=>this.onAction(action,params));
this.update();
} /**
* 想codepush检查更新
*/
update(){
codePush.sync({
updateDialog:{
appendReleaseDescription:true,
descriptionPrefix:'更新内容',
title:'更新',
mandatoryUpdateMessage:'',
mandatoryContinueButtonLabel:'更新',
},
mandatoryInstallMode:codePush.InstallMode.ON_NEXT_RESTART,
});
} /**
* 通知回调事件处理
* @param action
* @param params
*/
onAction(action,params){
if(ACTION_HOME.A_RESTART===action){
this.onRestart(params)
}else if(ACTION_HOME.A_SHOW_TOAST===action){
this.toast.show(params.text,DURATION.LENGTH_SHORT);
}
} /**
* 重启首页
* @param jumpToTab
*/
onRestart(jumpToTab){
this.props.navigator.resetTo({
component:HomePage,
params:{
...this.props,
selectedTab:jumpToTab
}
})
}
componentWillUnmount(): void {
super.componentWillUnmount();
if (this.listener) {
this.listener.remove();
}
}
_renderType(Component,selectTab,title,renderIcon){
return <TabNavigator.Item
selected={this.state.selectedTab === selectTab}
selectedTitleStyle={this.state.theme.styles.selectedTitleStyle}
title={title}
renderIcon={() => <Image style={styles.image} source={renderIcon}/>}
renderSelectedIcon={() => <Image style={[styles.image,this.state.theme.styles.tabBarSelectedIcon]} source={renderIcon}/>}
// badgeText="1"
onPress={() => this.setState({selectedTab: selectTab})}>
<View style={styles.page1}>
<Component {...this.props} theme={this.state.theme}/>
</View>
</TabNavigator.Item>
} render() {
return (
// tab切换
<View style={styles.container}>
<TabNavigator>
{this._renderType(PopularPage,'tb_popular','最热',require('../../res/images/ic_polular.png'))}
{this._renderType(TrendingPage,'tb_trending','趋势',require('../../res/images/ic_trending.png'))}
{this._renderType(FavoritePage,'tb_favorite','收藏',require('../../res/images/ic_favorite.png'))}
{this._renderType(MyPage,'tb_my','我的',require('../../res/images/ic_my.png'))}
</TabNavigator>
<Toast ref={toast=>this.toast=toast}/>
</View>
);
}
} const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
page1:{
flex: 1,
},
page2:{
flex: 2,
backgroundColor: 'green'
},
image:{
width:22,
height:22
}
});
//其实挺有意思的

tab首先的页面



应该只是布局,然后从后端请求数据渲染即可

代码如下:

//js/pages/popular/PopularPage.js
import React, {Component} from 'react';
import {
Image,
StyleSheet, TouchableOpacity,
View,
} from 'react-native';
import NavigationBar from "../../common/NavigationBar";
import ScrollableTabView, {ScrollableTabBar} from 'react-native-scrollable-tab-view'
import LanguageDao, {FLAG_LANGUAGE} from '../../expand/dao/LanguageDao'
import PopularTab from "./PopularTab";
import ViewUtils from "../../util/ViewUtils";
import SearchPage from "../SearchPage";
import {MORE_MENU} from "../../common/MoreMenu";
import {FLAG_TAB} from "../HomePage";
import MoreMenu from "../../common/MoreMenu";
import BaseComponent from "../BaseComponent";
import CustomTheme from "../My/CustomTheme"; export default class PopularPage extends BaseComponent { constructor(props) {
super(props);
this.languageDao = new LanguageDao(FLAG_LANGUAGE.flag_key);
this.state = {
languages: [],
customThemeViewVisible: false,
theme:this.props.theme,
}
} componentDidMount() {
super.componentDidMount()
//渲染数据
this.loadData();
} loadData() {
//取出数据
this.languageDao.fetch()
.then(result => {
this.setState({
languages: result
})
}).catch(error => {
console.log(error)
})
}
//点击不同的语言界面,最后是进入不同的语言列表新闻中 renderRightButton() {
return <View style={{flexDirection:'row'}}>
<TouchableOpacity
onPress={()=> {
this.props.navigator.push({
component:SearchPage,
params:{
...this.props
}
})
}}>
<View style={{padding:5,marginRight:8}}>
<Image
style={{width:24,height:24}}
source={require('../../../res/images/ic_search_white_48pt.png')}
/>
</View> </TouchableOpacity>
{ViewUtils.getMoreButton(()=>this.refs.moreMenu.open())}
</View>
} renderMoreView(){
let params={...this.props,fromPage:FLAG_TAB.flag_popularTab};
return <MoreMenu
ref="moreMenu"
{...params}
menus={[MORE_MENU.Custom_Key,MORE_MENU.Sort_Key,MORE_MENU.Remove_Key,MORE_MENU.Share,MORE_MENU.Custom_Theme,
MORE_MENU.About_Author,MORE_MENU.About]}
anchorView={()=>this.refs.moreMenuButton}
onMoreMenuSelect={(e)=> {
if (e === MORE_MENU.Custom_Theme) {
this.setState({
customThemeViewVisible:true
})
}
}}
/>
} renderCustomThemeView() {
return (
<CustomTheme visible={this.state.customThemeViewVisible}
{...this.props}
onClose={() => {
this.setState({
customThemeViewVisible: false,
})
}}/>
)
} render() {
let statusBar = {
backgroundColor:this.state.theme.themeColor,
barStyle:'light-content',
};
//判断语言切换的,这边用到的是ScrollableTabView组件
let content = this.state.languages.length > 0 ? <ScrollableTabView
tabBarBackgroundColor={this.state.theme.themeColor}
tabBarActiveTextColor='#fff'
tabBarInactiveTextColor='#333'
tabBarUnderlineStyle={{backgroundColor: '#e7e7e7', height: 2}}
renderTabBar={() => <ScrollableTabBar/>}>
{this.state.languages.map((result, i, arr) => {
let lan = arr[i];
return lan.checked ?
<PopularTab key={i} tabLabel={lan.name} {...this.props}/>: null;
})}
</ScrollableTabView> : null;
//底部图标切换
return <View style={styles.container}>
<NavigationBar
title={'最热'}
leftButton={<View/>}
rightButton={this.renderRightButton()}
statusBar={statusBar}
style={this.state.theme.styles.navBar}/>
{content}
{this.renderMoreView()}
{this.renderCustomThemeView()}
</View>
}
} const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
}, });
//js/pages/popular/PopularTab.js
//下拉刷新和获取数据
import React, {Component} from 'react';
import {DeviceEventEmitter, ListView, RefreshControl, StyleSheet, View} from "react-native";
import ProjectModel from "../../model/ProjectModel";
import Utils from "../../util/Utils";
import DescPage from "./DescPage";
import {FLAG_STORAGE} from "../../expand/dao/DataRepository";
import RepositoryCell from "../../common/RepositoryCell";
import FavoriteDao from "../../expand/dao/FavoriteDao";
import DataRepository from "../../expand/dao/DataRepository";
import ActionUtils from "../../util/ActionUtils"; const URL = "https://api.github.com/search/repositories?q=";
const QUERY_STR = '&sort=stars';
const favoriteDao = new FavoriteDao(FLAG_STORAGE.flag_popular);
const dataRepository = new DataRepository(FLAG_STORAGE.flag_popular); export default class PopularTab extends Component {
constructor(props) {
super(props);
this.isFavoriteChange=false;
this.state = {
result: '',
isLoading: false,
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),
favoriteKeys :[],
theme:this.props.theme,
}
} componentDidMount(): void {
this.onLoad();
this.listener= DeviceEventEmitter.addListener('favoriteChanged_popular',()=>{
this.isFavoriteChange = true;
})
} componentWillUnmount(): void {
if (this.listener){
this.listener.remove();
}
} componentWillReceiveProps(nextProps: Readonly<P>, nextContext: any): void {
if (this.isFavoriteChange) {
this.isFavoriteChange=false;
this.getFavoriteKeys()
}else if (nextProps.theme !== this.state.theme) {
this.updateState({
theme:nextProps.theme,
})
this.flushFavoriteState()
}
} /**
* 更新project item收藏状态
*/
flushFavoriteState(){
let projectModels = [];
let items = this.items;
for(let i =0 ,len = items.length;i<len;i++){
projectModels.push(new ProjectModel(items[i],Utils.checkFavorite(items[i],this.state.favoriteKeys)))
}
this.updateState({
isLoading:false,
dataSource:this.getDataSource(projectModels),
})
} getDataSource(data){
return this.state.dataSource.cloneWithRows(data);
} getFavoriteKeys(){
favoriteDao.getFavoriteKeys()
.then(keys=>{
if (keys) {
this.updateState({
favoriteKeys: keys
})
}
this.flushFavoriteState();
})
.catch(e=>{
this.flushFavoriteState()
})
} updateState(dic){
if (!this) return;
this.setState(dic);
} onLoad() {
this.updateState({
isLoading: true
});
let url = URL + this.props.tabLabel + QUERY_STR;
dataRepository.fetchRepository(url)
.then(result => {
this.items = result && result.items ? result.items : result ? result : [];
this.getFavoriteKeys();
if (!this.items||result && result.update_date && !dataRepository.checkData(result.update_date)) {
return dataRepository.fetchNetRepository(url)
}
})
.then(items => {
if (!items || items.length === 0) {
return;
} else {
this.items=items;
this.getFavoriteKeys()
}
})
.catch(error => {
console.log(error);
this.updateState({
isLoading:false,
})
});
} choose(projectModel) {
return <RepositoryCell
onSelect={()=>ActionUtils.onSelectRepository({
flag: FLAG_STORAGE.flag_popular,
...this.props,
projectModel: projectModel,
})}
theme={this.state.theme}
key={projectModel.item.id}
onFavorite={(item,isFavorite)=>ActionUtils.onFavorite(favoriteDao,item, isFavorite)}
projectModel={projectModel}/>
} render() {
return <View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={(data) => this.choose(data)}
refreshControl={
<RefreshControl
refreshing={this.state.isLoading}
onRefresh={() => this.onLoad()}
color={this.state.theme.themeColor}
tintColor={this.state.theme.themeColor}
title={'Loading...'}
titleColor={this.state.theme.themeColor}
/>
} />
</View>
} } const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
page1: {
flex: 1,
backgroundColor: 'red'
},
page2: {
flex: 2,
backgroundColor: 'green'
},
image: {
width: 22,
height: 22
},
item: {
backgroundColor: '#169',
height: 100,
margin: 15,
alignItems: 'center',
justifyContent: 'center',
},
text_my: {
color: 'black',
fontSize: 20,
},
text: {
color: 'white',
fontSize: 20,
},
indicatorContainer: {
alignItems: 'center'
},
indicator: {
color: 'red',
margin: 10
}
});
//js/pages/popular/store/Store.js
import {observable} from "mobx";
import DataRepository from "../../../expand/dao/DataRepository"; export default class PopularStore {
api; @observable popularItems=[]; constructor(){
this.api=new DataRepository();
} getPopularItem(id){
return this.popularItems.find(item=>item.id.toString()===id);
} @action.bound()
fetchPopularList(tabLabel){
return this.api.getPopularInfo(tabLabel)
.then(action(result => {
this.items = result && result.items ? result.items : result ? result : [];
this.getFavoriteKeys();
if (!this.items||result && result.update_date && !dataRepository.checkData(result.update_date)) {
return dataRepository.fetchNetRepository(url)
}
})
.then(items => {
if (!items || items.length === 0) {
return;
} else {
this.items=items;
this.getFavoriteKeys()
}
})
.catch(error => {
console.log(error);
this.updateState({
isLoading:false,
})
}));
} }
//js/pages/popular/model/ProjectModel.js
import {observable} from "mobx"; export default class ProjectModel{
@observable item;
@observable isFavorite;
}
//js/pages/popular/DescPage.js
import React, {Component} from 'react'
import {
View,
StyleSheet,
WebView,
TouchableOpacity,
Image, } from 'react-native'
import NavigationBar from "../../common/NavigationBar";
import ViewUtils from "../../util/ViewUtils";
import FavoriteDao from "../../expand/dao/FavoriteDao";
import share from "../../../res/data/share";
import UShare from "../../common/UShare";
import BackPressComponent from "../../common/BackPressComponent"; const TRENDING_URL = 'https://github.com/';
export default class DescPage extends Component {
constructor(props) {
super(props);
// alert(this.props.title);
this.backPress = new BackPressComponent({backPress:(e)=>this.onBackPress(e)});
this.url = this.props.projectModel.item.html_url ? this.props.projectModel.item.html_url : TRENDING_URL + this.props.projectModel.item.fullName;
let title = this.props.projectModel.item.full_name ? this.props.projectModel.item.full_name : this.props.projectModel.item.fullName;
this.favoriteDao = new FavoriteDao(this.props.flag);
this.state = {
url: this.url,
title: title,
canGoBack: false,
isFavorite: this.props.projectModel.isFavorite,
favoriteIcon: this.props.projectModel.isFavorite ? require('../../../res/images/ic_star.png')
: require('../../../res/images/ic_star_navbar.png'),
theme: this.props.theme,
}
}
componentDidMount(): void {
this.backPress.componentDidMount();
} componentWillUnmount(): void {
this.backPress.componentWillUnmount();
if (this.props.onUpdateFavorite)this.props.onUpdateFavorite();
} onBack() {
if (this.state.canGoBack) {
this.webView.goBack()
} else {
this.props.navigator.pop();
} } onBackPress(e){
this.onBack();
return true;
} go() {
this.setState({
url: this.text
})
} onNavigationStateChange(e) {
this.setState({
canGoBack: e.canGoBack,
url: e.url,
})
} onRightButtonClick() {
let projectModel = this.props.projectModel;
this.setFavoriteState(projectModel.isFavorite = !projectModel.isFavorite);
const key = projectModel.item.fullName ? projectModel.item.fullName : projectModel.item.id.toString();
if (projectModel.isFavorite) {
this.favoriteDao.saveFavoriteItem(key, JSON.stringify(projectModel.item))
} else {
this.favoriteDao.removeFavoriteItem(key)
}
} setFavoriteState(isFavorite) {
this.setState({
isFavorite: isFavorite,
favoriteIcon: isFavorite ? require('../../../res/images/ic_star.png')
: require('../../../res/images/ic_star_navbar.png')
})
} renderRightButton() {
return <View style={{flexDirection: 'row'}}>
{ViewUtils.getShareButton(()=>this.shareInfo())}
<TouchableOpacity onPress={() => this.onRightButtonClick()}>
<Image style={{width: 20, height: 20, marginRight: 10}} source={this.state.favoriteIcon}/>
</TouchableOpacity>
</View>
} shareInfo(){
const shareApp = share.share_app;
UShare.share(shareApp.title, shareApp.content,
shareApp.imgUrl,shareApp.url,()=>{},()=>{});
} render() {
let statusBar = {
backgroundColor: this.state.theme.themeColor
};
let titleLayoutStyle = this.state.title.length>20?{paddingRight: 30}:null;
return <View style={styles.container}>
<NavigationBar
title={this.state.title}
statusBar={statusBar}
titleLayoutStyle={titleLayoutStyle}
style={this.state.theme.styles.navBar}
rightButton={this.renderRightButton()}
leftButton={ViewUtils.getLeftButton(() => this.onBack())}
/>
<WebView ref={webView => this.webView = webView}
source={{uri: this.state.url}}
startInLoadingState={true}
onNavigationStateChange={(e) =>
this.onNavigationStateChange(e)}>
</WebView>
</View>
} } const styles = StyleSheet.create({
container: {
flex: 1
},
tips: {
fontSize: 20
},
row: {
flexDirection: 'row',
alignItems: 'center',
margin: 10
},
input: {
height: 40,
flex: 1,
borderWidth: 1,
margin: 2,
}
});

趋势页面跟最热页面类似

//js/pages/trending/TrendingPage.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Image,
Text,
View,
TextInput,
ListView,
RefreshControl,
DeviceEventEmitter,
TouchableOpacity,
} from 'react-native';
import NavigationBar from "../../common/NavigationBar"
import DataRepository, {FLAG_STORAGE} from "../../expand/dao/DataRepository"
import ScrollableTabView, {ScrollableTabBar} from 'react-native-scrollable-tab-view'
import RepositoryCell from "../../common/RepositoryCell";
import LanguageDao, {FLAG_LANGUAGE} from '../../expand/dao/LanguageDao'
import DescPage from "../popular/DescPage";
import TrendingCell from "../../common/TrendingCell";
import TimeSpan from "../../model/TimeSpan";
import Popover from "../../common/Popover";
import FavoriteDao from "../../expand/dao/FavoriteDao";
import ProjectModel from "../../model/ProjectModel";
import Utils from "../../util/Utils";
import ActionUtils from "../../util/ActionUtils";
import {FLAG_TAB} from "../HomePage";
import MoreMenu, {MORE_MENU} from "../../common/MoreMenu";
import ViewUtils from "../../util/ViewUtils";
import BaseComponent from "../BaseComponent";
import CustomTheme from "../My/CustomTheme"; const API_URL = "https://github.com/trending/";
var timeSpanTextArray = [new TimeSpan('今 天', 'since=daily'), new TimeSpan('本 周', 'since=weekly'), new TimeSpan('本 月', 'since=monthly')];
var favoriteDao = new FavoriteDao(FLAG_STORAGE.flag_trending);
var dataRespository = new DataRepository(FLAG_STORAGE.flag_trending); export default class TrendingPage extends BaseComponent { constructor(props) {
super(props);
this.languageDao = new LanguageDao(FLAG_LANGUAGE.flag_language);
this.state = {
languages: [],
isVisible: false,
buttonRect: {},
timeSpan: timeSpanTextArray[0],
theme:this.props.theme,
customThemeViewVisible: false,
}
} componentDidMount() {
super.componentDidMount();
this.loadData();
} componentWillReceiveProps(nextProps: Readonly<P>, nextContext: any): void {
if (nextProps.timeSpan !== this.props.timeSpan) {
this.loadData(nextProps.timeSpan)
}
} loadData() {
this.languageDao.fetch()
.then(result => {
this.setState({
languages: result
})
}).catch(error => {
console.log(error)
})
} showPopover() {
this.refs.button.measure((ox, oy, width, height, px, py) => {
this.setState({
isVisible: true,
buttonRect: {x: px, y: py, width: width, height: height}
});
});
} closePopover() {
this.setState({
isVisible: false,
});
} renderTitleView() {
return <View>
<TouchableOpacity ref={'button'} onPress={() => {
this.showPopover()
}}>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{
fontSize: 18,
color: 'white',
fontWeight: '400'
}}>趋势 {this.state.timeSpan.showText}</Text>
<Image style={{width: 12, height: 12, marginLeft: 5}}
source={require('../../../res/images/ic_spinner_triangle.png')}/>
</View>
</TouchableOpacity>
</View>
} onSelectTimeSpan(timeSpan) {
this.setState({
timeSpan: timeSpan,
isVisible: false,
})
} renderMoreView() {
let params = {...this.props, fromPage: FLAG_TAB.flag_popularTab};
return <MoreMenu
ref="moreMenu"
{...params}
menus={[MORE_MENU.Custom_Language, MORE_MENU.Sort_Language,MORE_MENU.Share, MORE_MENU.Custom_Theme,
MORE_MENU.About_Author, MORE_MENU.About]}
anchorView={() => this.refs.moreMenuButton}
onMoreMenuSelect={(e) => {
if (e === MORE_MENU.Custom_Theme) {
this.setState({
customThemeViewVisible: true
})
}
}}
/>
} renderCustomThemeView() {
return (
<CustomTheme visible={this.state.customThemeViewVisible}
{...this.props}
onClose={() => {
this.setState({
customThemeViewVisible: false,
})
}}/>
)
} render() {
let statusBar = {
backgroundColor:this.state.theme.themeColor
};
let content = this.state.languages.length > 0 ? <ScrollableTabView
tabBarBackgroundColor={this.state.theme.themeColor}
tabBarActiveTextColor='#fff'
tabBarInactiveTextColor='#333'
tabBarUnderlineStyle={{backgroundColor: '#e7e7e7', height: 2}}
renderTabBar={() => <ScrollableTabBar/>}>
{this.state.languages.map((result, i, arr) => {
let lan = arr[i];
return lan.checked ?
<TrendingTab key={i} tabLabel={lan.name}
timeSpan={this.state.timeSpan} {...this.props}>{lan.name}</TrendingTab> : null;
})}
</ScrollableTabView> : null;
let timeSpanView = <Popover
isVisible={this.state.isVisible}
fromRect={this.state.buttonRect}
placement={'bottom'}
contentStyle={{backgroundColor: '#343434', opacity: 0.5}}
onClose={() => this.closePopover()}>
{timeSpanTextArray.map((result, i, arr) => {
return <TouchableOpacity key={i} underlayColor={'transparent'}
onPress={() => this.onSelectTimeSpan(arr[i])}>
<Text style={{fontSize: 18, color: 'white', padding: 8, fontWeight: '400'}}>{arr[i].showText}</Text>
</TouchableOpacity>
})}
</Popover>;
return <View style={styles.container}>
<NavigationBar
titleView={this.renderTitleView()}
leftButton={<View/>}
rightButton={ViewUtils.getMoreButton(() => this.refs.moreMenu.open())}
statusBar={statusBar}
style={this.state.theme.styles.navBar}/>
{content}
{timeSpanView}
{this.renderMoreView()}
{this.renderCustomThemeView()}
</View>
}
} class TrendingTab extends Component {
constructor(props) {
super(props);
this.isFavoriteChange = false;
this.state = {
result: '',
isLoading: false,
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),
favoriteKeys: [],
theme:this.props.theme,
}
} /**
* 更新project item收藏状态
*/
flushFavoriteState() {
let projectModels = [];
let items = this.items;
for (let i = 0, len = items.length; i < len; i++) {
projectModels.push(new ProjectModel(items[i], Utils.checkFavorite(items[i], this.state.favoriteKeys)))
}
this.updateState({
isLoading: false,
dataSource: this.getDataSource(projectModels),
})
} getDataSource(data) {
return this.state.dataSource.cloneWithRows(data);
} getFavoriteKeys() {
favoriteDao.getFavoriteKeys()
.then(keys => {
if (keys) {
this.updateState({
favoriteKeys: keys
})
}
this.flushFavoriteState();
})
.catch(e => {
this.flushFavoriteState()
})
} updateState(dic) {
if (!this) return;
this.setState(dic);
} componentDidMount(): void {
this.onLoad(this.props.timeSpan, true)
this.listener = DeviceEventEmitter.addListener('favoriteChanged_trending', () => {
this.isFavoriteChange = true;
})
} onUpdateFavorite() {
this.getFavoriteKeys();
} componentWillUnmount(): void {
if (this.listener) {
this.listener.remove();
}
} componentWillReceiveProps(nextProps: Readonly<P>, nextContext: any): void {
if (this.isFavoriteChange) {
this.isFavoriteChange = false;
this.getFavoriteKeys()
}else if (nextProps.theme !== this.state.theme) {
this.updateState({
theme:nextProps.theme,
});
this.flushFavoriteState()
}
} getFetchUrl(timeSpan, category) {
return API_URL + category + '?' + timeSpan.searchText
} onLoad(timeSpan, isRefresh) {
this.updateState({
isLoading: true
}); let url = this.getFetchUrl(timeSpan, this.props.tabLabel)
dataRespository.fetchRepository(url)
.then(result => {
this.items = result && result.items ? result.items : result ? result : [];
this.getFavoriteKeys();
if (!this.items || isRefresh && result && result.update_date && !dataRespository.checkData(result.update_date)) {
return dataRespository.fetchNetRepository(url)
}
})
.then(items => {
if (!items || items.length === 0) {
return;
} else {
this.items = items;
this.getFavoriteKeys();
}
})
.catch(error => {
this.updateState({
isLoading: false
})
});
} choose(projectModel) {
return <TrendingCell
onSelect={() => ActionUtils.onSelectRepository({
projectModel: projectModel,
flag: FLAG_STORAGE.flag_trending,
...this.props,
parentComponent: this,
onUpdateFavorite: ()=>this.onUpdateFavorite(),
})}
theme={this.props.theme}
key={projectModel.item.fullName}
onFavorite={(item, isFavorite) => ActionUtils.onFavorite(favoriteDao, item, isFavorite, FLAG_STORAGE.flag_trending)}
projectModel={projectModel}/>
} onRefresh() {
this.onLoad(this.props.timeSpan, true);
} render() {
return <View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={(data) => this.choose(data)}
refreshControl={
<RefreshControl
refreshing={this.state.isLoading}
onRefresh={() => this.onRefresh()}
color={this.state.theme.themeColor}
tintColor={this.state.theme.themeColor}
title={'Loading...'}
titleColor={this.state.theme.themeColor}
/>
} />
</View>
} } const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
page1: {
flex: 1,
backgroundColor: 'red'
},
page2: {
flex: 2,
backgroundColor: 'green'
},
image: {
width: 22,
height: 22
},
item: {
backgroundColor: '#169',
height: 100,
margin: 15,
alignItems: 'center',
justifyContent: 'center',
},
text_my: {
color: 'black',
fontSize: 20,
},
text: {
color: 'white',
fontSize: 20,
},
indicatorContainer: {
alignItems: 'center'
},
indicator: {
color: 'red',
margin: 10
}
});

//收藏页面
//js/pages/favorite/FavoritePage.js
import React, {Component} from 'react';
import {
StyleSheet,
View,
ListView,
RefreshControl,
DeviceEventEmitter,
} from 'react-native';
import NavigationBar from "../../common/NavigationBar"
import {FLAG_STORAGE} from "../../expand/dao/DataRepository"
import ScrollableTabView, {ScrollableTabBar} from 'react-native-scrollable-tab-view'
import RepositoryCell from "../../common/RepositoryCell";
import DescPage from "../popular/DescPage";
import ProjectModel from "../../model/ProjectModel";
import FavoriteDao from "../../expand/dao/FavoriteDao";
import TrendingCell from "../../common/TrendingCell";
import ArrayUtils from "../../util/ArrayUtils";
import ActionUtils from "../../util/ActionUtils";
import MoreMenu, {MORE_MENU} from "../../common/MoreMenu";
import {FLAG_TAB} from "../HomePage";
import ViewUtils from "../../util/ViewUtils";
import BaseComponent from "../BaseComponent";
import CustomTheme from "../My/CustomTheme"; export default class FavoritePage extends BaseComponent { constructor(props) {
super(props);
this.state = {
theme: this.props.theme,
customThemeViewVisible: false,
}
} renderMoreView() {
let params = {...this.props, fromPage: FLAG_TAB.flag_popularTab}
return <MoreMenu
ref="moreMenu"
{...params}
menus={[MORE_MENU.Custom_Theme, MORE_MENU.Share,
MORE_MENU.About_Author, MORE_MENU.About]}
anchorView={() => this.refs.moreMenuButton}
onMoreMenuSelect={(e) => {
if (e === MORE_MENU.Custom_Theme) {
this.setState({
customThemeViewVisible: true
})
}
}}
/>
} renderCustomThemeView() {
return (
<CustomTheme visible={this.state.customThemeViewVisible}
{...this.props}
onClose={() => {
this.setState({
customThemeViewVisible: false,
})
}}/>
)
} render() {
let statusBar = {
backgroundColor: this.state.theme.themeColor
};
let content = <ScrollableTabView
tabBarBackgroundColor={this.state.theme.themeColor}
tabBarActiveTextColor='#fff'
tabBarInactiveTextColor='#333'
tabBarUnderlineStyle={{backgroundColor: '#e7e7e7', height: 2}}
renderTabBar={() => <ScrollableTabBar/>}
>
<FavoriteTab tabLabel='最热' flag={FLAG_STORAGE.flag_popular} {...this.props}/>
<FavoriteTab tabLabel='趋势' flag={FLAG_STORAGE.flag_trending} {...this.props}/>
</ScrollableTabView>
return <View style={styles.container}>
<NavigationBar
title={'收藏'}
leftButton={<View/>}
rightButton={ViewUtils.getMoreButton(() => this.refs.moreMenu.open())}
statusBar={statusBar}
style={this.state.theme.styles.navBar}/>
{content}
{this.renderMoreView()}
{this.renderCustomThemeView()}
</View>
}
} class FavoriteTab extends Component {
constructor(props) {
super(props);
this.unFavoriteItems = [];
this.favoriteDao = new FavoriteDao(this.props.flag);
this.state = {
result: '',
isLoading: false,
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),
favoriteKeys: [],
theme: this.props.theme,
}
} componentDidMount(): void {
this.onLoad(true)
} componentWillReceiveProps(nextProps: Readonly<P>, nextContext: any): void {
this.onLoad(false)
} updateState(dic) {
if (!this) return;
this.setState(dic);
} getDataSource(data) {
return this.state.dataSource.cloneWithRows(data);
} onLoad(isShowLoading) {
if (isShowLoading) {
this.updateState({
isLoading: true
});
}
this.favoriteDao.getAllItems()
.then(items => {
let resultData = [];
for (let i = 0, len = items.length; i < len; i++) {
resultData.push(new ProjectModel(items[i], true));
}
this.updateState({
isLoading: false,
dataSource: this.getDataSource(resultData)
})
})
.catch(e => {
this.updateState({
isLoading: false
})
})
} choose(projectModel) {
let CellComponent = this.props.flag === FLAG_STORAGE.flag_popular ? RepositoryCell : TrendingCell;
return <CellComponent
onSelect={() => ActionUtils.onSelectRepository({
flag: FLAG_STORAGE.flag_popular,
...this.props,
projectModel: projectModel,
})}
theme={this.props.theme}
key={this.props.flag === FLAG_STORAGE.flag_popular ? projectModel.item.id : projectModel.item.fullName}
onFavorite={(item, isFavorite) => ActionUtils.onFavorite(this.favoriteDao, item, isFavorite, this.props.flag)}
projectModel={projectModel}/>
} render() {
return <View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={(data) => this.choose(data)}
enableEmptySections={true}
refreshControl={
<RefreshControl
refreshing={this.state.isLoading}
onRefresh={() => this.onLoad()}
color={this.state.theme.themeColor}
tintColor={this.state.theme.themeColor}
title={'Loading...'}
titleColor={this.state.theme.themeColor}
/>
} />
</View>
} } const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
page1: {
flex: 1,
backgroundColor: 'red'
},
page2: {
flex: 2,
backgroundColor: 'green'
},
image: {
width: 22,
height: 22
},
item: {
backgroundColor: '#169',
height: 100,
margin: 15,
alignItems: 'center',
justifyContent: 'center',
},
text_my: {
color: 'black',
fontSize: 20,
},
text: {
color: 'white',
fontSize: 20,
},
indicatorContainer: {
alignItems: 'center'
},
indicator: {
color: 'red',
margin: 10
}
});

//js/pages/My/MyPage.js
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
ScrollView,
TouchableHighlight,
Image,
} from 'react-native';
import NavigationBar from "../../common/NavigationBar";
import GlobalStyles from "../../../res/styles/GlobalStyles"
import ViewUtils from "../../util/ViewUtils";
import CustomKeyPage from "./CustomKeyPage";
import {FLAG_LANGUAGE} from "../../expand/dao/LanguageDao";
import SortKeyPage from "./SortKeyPage";
import AboutMePage from "./about/AboutMePage";
import AboutPage from "./about/AboutPage";
import {MORE_MENU} from "../../common/MoreMenu";
import CustomTheme from "./CustomTheme";
import BaseComponent from "../BaseComponent";
import codePush from "react-native-code-push"; export default class MyPage extends BaseComponent {
constructor(props) {
super(props);
this.state = {
customThemeViewVisible: false,
theme:this.props.theme,
}
} onClick(tab) {
let TargetComponent, params = {...this.props, menuType: tab};
switch (tab) {
case MORE_MENU.Custom_Language:
TargetComponent = CustomKeyPage;
params.flag = FLAG_LANGUAGE.flag_language;
break;
case MORE_MENU.Custom_Key:
TargetComponent = CustomKeyPage;
params.flag = FLAG_LANGUAGE.flag_key;
break;
case MORE_MENU.Remove_Key:
TargetComponent = CustomKeyPage;
params.flag = FLAG_LANGUAGE.flag_key;
params.isRemoveKey = true;
break;
case MORE_MENU.Sort_Language:
TargetComponent = SortKeyPage;
params.flag = FLAG_LANGUAGE.flag_language;
break;
case MORE_MENU.Sort_Key:
TargetComponent = SortKeyPage;
params.flag = FLAG_LANGUAGE.flag_key;
break;
case MORE_MENU.Custom_Theme:
this.setState({customThemeViewVisible: true});
break;
case MORE_MENU.About_Author:
TargetComponent = AboutMePage;
break;
case MORE_MENU.About:
TargetComponent = AboutPage;
break;
case '更新':
// this.update();
break; } if (TargetComponent) {
this.props.navigator.push({
component: TargetComponent,
params: params,
});
}
} getItem(tag, icon, text) {
return ViewUtils.getSettingItem(() => this.onClick(tag), icon, text, this.state.theme.styles.tabBarSelectedIcon, null);
} renderCustomThemeView() {
return (
<CustomTheme visible={this.state.customThemeViewVisible}
{...this.props}
onClose={() => {
this.setState({
customThemeViewVisible: false,
})
}}/>
)
} render() { let statusBar = {
backgroundColor:this.state.theme.themeColor
};
let navigatorBar = <NavigationBar title={'我的'}
statusBar={statusBar}
style={this.state.theme.styles.navBar}/>;
return <View style={GlobalStyles.root_container}>
{navigatorBar}
<ScrollView>
{/*最热管理*/}
<TouchableHighlight onPress={() => this.onClick(MORE_MENU.About)}>
<View style={[styles.item, {height: 90}]}>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Image source={require('../../../res/images/ic_trending.png')}
style={[{width: 40, height: 40, marginRight: 10}, this.state.theme.styles.tabBarSelectedIcon]}/> <Text>Github Popular</Text>
</View>
<Image style={[{marginRight: 10, height: 22, width: 22,}, this.state.theme.styles.tabBarSelectedIcon]}
source={require('../../../res/images/ic_tiaozhuan.png')}/>
</View>
</TouchableHighlight>
<View style={GlobalStyles.line}/>
{/*趋势管理*/}
<Text style={styles.groupTitle}>趋势管理</Text>
<View style={GlobalStyles.line}/>
{/*自定义语言*/}
{this.getItem(MORE_MENU.Custom_Language, require('./img/ic_custom_language.png'), '自定义语言')}
<View style={GlobalStyles.line}/>
{/*语言排序*/}
{this.getItem(MORE_MENU.Sort_Language, require('./img/ic_sort.png'), '语言排序')}
<View style={GlobalStyles.line}/> {/*标签管理*/}
<Text style={styles.groupTitle}>标签管理</Text>
<View style={GlobalStyles.line}/>
{/*自定义标签*/}
{this.getItem(MORE_MENU.Custom_Key, require('./img/ic_custom_language.png'), '自定义标签')}
<View style={GlobalStyles.line}/>
{/*标签排序*/}
{this.getItem(MORE_MENU.Sort_Key, require('./img/ic_swap_vert.png'), '标签排序')}
<View style={GlobalStyles.line}/>
{/*标签移除*/}
{this.getItem(MORE_MENU.Remove_Key, require('./img/ic_remove.png'), '标签移除')}
<View style={GlobalStyles.line}/>
{/*设置*/}
<Text style={styles.groupTitle}>设置</Text>
<View style={GlobalStyles.line}/>
{this.getItem(MORE_MENU.Custom_Theme, require('./img/ic_custom_theme.png'), '自定义主题')}
<View style={GlobalStyles.line}/>
{this.getItem(MORE_MENU.About_Author, require('./img/ic_insert_emoticon.png'), '关于作者')}
<View style={GlobalStyles.line}/> </ScrollView> {this.renderCustomThemeView()}
</View>
}
} const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 10,
height: 60,
backgroundColor: 'white',
},
groupTitle: {
marginLeft: 10,
marginTop: 10,
marginBottom: 5,
fontSize: 12,
color: 'gray', }
});
//js/pages/My/CustomTheme.js
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
ScrollView,
TouchableHighlight,
Image,
Platform,
DeviceEventEmitter,
Modal,
} from 'react-native'; import GlobalStyles from "../../../res/styles/GlobalStyles"
import ThemeFactory,{ThemeFlags} from "../../../res/styles/ThemeFactory"
import ThemeDao from "../../expand/dao/ThemeDao";
import {ACTION_HOME} from "../HomePage"; export default class CustomTheme extends Component {
constructor(props) {
super(props);
this.themeDao = new ThemeDao();
} onSelectTheme(themeKey){
this.props.onClose();
this.themeDao.save(ThemeFlags[themeKey]);
DeviceEventEmitter.emit('ACTION_BASE',ACTION_HOME.A_THEME,ThemeFactory.createTheme(
ThemeFlags[themeKey]
))
} getThemeItem(themeKey){
return <TouchableHighlight underlayColor={'white'} onPress={()=>this.onSelectTheme(themeKey)} style={{flex: 1}}>
<View style={[{backgroundColor: ThemeFlags[themeKey]},styles.themeItem]}>
<Text style={styles.themeText}>{themeKey}</Text>
</View>
</TouchableHighlight>
} /**
* 创建主题列表
* @returns {Array}
*/
renderThemeItems(){
const views = [];
for (let i=0,keys=Object.keys(ThemeFlags),l=keys.length;i<l;i+=3){
const key1 = keys[i], key2 = keys[i + 1], key3 = keys[i + 2];
views.push(
<View keys={i} style={{flexDirection: 'row'}}>
{this.getThemeItem(key1)}
{this.getThemeItem(key2)}
{this.getThemeItem(key3)}
</View>
)
}
return views;
} renderContentView(){
return <Modal animationType={"slide"}
transparent={true}
visible={this.props.visible}
onRequestClose={() => {this.props.onClose()}}> <View style={styles.modalContainer}>
<ScrollView>
{this.renderThemeItems()}
</ScrollView>
</View> </Modal>
} render() {
let view = this.props.visible?<View style={GlobalStyles.root_container}>
{this.renderContentView()}
</View>:null;
return view;
}
} const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
modalContainer:{
flex:1,
margin: 10,
marginTop: Platform.OS==='ios'?20:10,
backgroundColor:'white',
borderRadius: 3,
shadowColor: 'gray',
shadowOffset: {width: 2,height: 2},
shadowOpacity: 0.5,
shadowRadius: 2,
padding: 3
},
themeItem:{
flex:1,
height: 120,
margin: 3,
padding:3,
borderRadius:2,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
},
themeText:{
color:'white',
fontWeight: '500',
fontSize:16,
} });

by最后,如果你看代码看的想睡觉,那么它是提醒你,换一个项目看看~

没有看代码看睡着的人,只有不够有吸引力的代码

【水滴石穿】imooc_gp的更多相关文章

  1. iOS 开发笔记 -- 各种细枝末节的知识(水滴石穿)

    在此总结整理,遇到的各种的小问题: 1.通过从字典(数组)中取出的NSString的length==0 作为if的判断条件导致的carsh: 由于在字典中通过Key取出值之后直接做了length相关操 ...

  2. 【水滴石穿】react-native-book

    先推荐一个学习的地址:https://ke.qq.com/webcourse/index.html#cid=203313&term_id=100240778&taid=12778558 ...

  3. 【水滴石穿】rnTest

    其实就是一个小的demo,不过代码分的挺精巧的 先放地址:https://github.com/linchengzzz/rnTest 来看看效果 确实没有什么可以说的,不过代码部分还行 先入口文件 / ...

  4. 【水滴石穿】rn_statusbar

    先放项目地址https://github.com/hezhii/rn_statusbar 来看一下效果 咩有感觉很怎么样,看代码 根入口文件 //index.js //看代码我们知道入口是app.js ...

  5. 【水滴石穿】react-native-ble-demo

    项目的话,是想打开蓝牙,然后连接设备 点击已经连接的设备,我们会看到一些设备 不过我这边在开启蓝牙的时候报错了 先放作者的项目地址: https://github.com/hezhii/react-n ...

  6. 【水滴石穿】ReactNative-Redux-Thunk

    老实说,运行出来的项目让人失望,毕竟我想看各种有趣的demo啊- 先放上源码地址:https://github.com/ludejun/ReactNative-Redux-Thunk 我们来一起看看代 ...

  7. 【水滴石穿】mobx-todos

    我觉得代码在有些程序员手里,就好像是画笔,可以创造很多东西 不要觉得创意少就叫没有创意,每天进步一点点,世界更美好 首先源码地址为:https://github.com/byk04712/mobx-t ...

  8. 【水滴石穿】ReactNativeMobxFrame

    项目地址如下:https://github.com/FTD-ZF/ReactNativeMobxFrame 应该可以说的是,项目也只是一个花架子,不过底部的tab稍微改变了 我们一起来看代码 //in ...

  9. 【水滴石穿】react-native-aze

    说个题外话,早上打开电脑的时候,电脑变成彩色的了,锅是我曾经安装的一个chrome扩展,没有经过我的同意开启了 (也许是昨天迷迷糊糊开启了) 上午运行项目都不成功,还以为被黑客攻击了---然后下午就排 ...

随机推荐

  1. Postfix+Dovecot+MySQL搭建邮件服务器(续)

    上一篇中的原文中$7$是错的,应该用$6$, 找到: 原因可参考 https://passlib.readthedocs.io/en/stable/lib/passlib.hash.sha512_cr ...

  2. Java基础——List集合整理(脑图,源码,面试题)

    常在知乎牛客网关注Java的一些面试,了解过校招社招常面哪些内容.Java集合不仅使用频率高而且在初面中也常常被问到,何止是常常,关于ArrayList的扩容,HashMap的一些底层等等都被问到烂了 ...

  3. 移动端Web适配单位rem的坑,oppo r9手机出现错位bug

    我们做了一个抽奖的H5活动页面,被一个oppo R9手机客户反馈,抽奖的转盘错位了.刷新了好几次都不行.网上百度一搜真的有部分安卓手机有坑.赶紧修复bug.分享完整的rem.js代码出来.各位看官自己 ...

  4. sqlserver 创建用户 sp_addlogin

    创建新的 Microsoft® SQL Server™ 登录,使用户得以连接使用 SQL Server 身份验证的 SQL Server 实例.  语法: sp_addlogin [ @loginam ...

  5. 转载 ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(一) 整理基础数据

    ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(一) 整理基础数据   最近碰巧发现一款比较好的Web即时通讯前端组件,layim,百度关键字即可,我下面要做的就是基于这个前 ...

  6. HashMap基础知识

    HashMap 简介 HashMap 主要用来存放键值对,它基于哈希表的Map接口实现,是常用的Java集合之一. JDK1.8 之前 HashMap 由 数组+链表 组成的,数组是 HashMap ...

  7. Ajax技术 - (Asynchronous JavaScript + XML)

    Ajax Ajax = 异步JavaScript和XML,Ajax是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新.可以再网页不重新加载的情况下, ...

  8. spring boot项目启动报DataSource错误

    初建一个简单的spring boot 项目,启动后会报错. Exception encountered during context initialization - cancelling refre ...

  9. JasperReport导出报表8

    我们已经看到在前面的章节中,如何打印和查看的JasperReport生成的文档.在这里,我们将看到如何在其他格式,如PDF,HTML和XLS转换或导出这些报告. Facade类net.sf.jaspe ...

  10. OSG能够在当前帧截图,也就是能转换视角后马上截图

    #include <Windows.h> #include <osg/GraphicsContext> #include <osg/Group> #include ...