【水滴石穿】imooc_gp
这个项目应该是一个标杆项目,看到之前很有几个项目都是按照这个项目的页面摆放顺序来的
不过可以作为自己做项目的一种方式
源码地址为: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的更多相关文章
- iOS 开发笔记 -- 各种细枝末节的知识(水滴石穿)
在此总结整理,遇到的各种的小问题: 1.通过从字典(数组)中取出的NSString的length==0 作为if的判断条件导致的carsh: 由于在字典中通过Key取出值之后直接做了length相关操 ...
- 【水滴石穿】react-native-book
先推荐一个学习的地址:https://ke.qq.com/webcourse/index.html#cid=203313&term_id=100240778&taid=12778558 ...
- 【水滴石穿】rnTest
其实就是一个小的demo,不过代码分的挺精巧的 先放地址:https://github.com/linchengzzz/rnTest 来看看效果 确实没有什么可以说的,不过代码部分还行 先入口文件 / ...
- 【水滴石穿】rn_statusbar
先放项目地址https://github.com/hezhii/rn_statusbar 来看一下效果 咩有感觉很怎么样,看代码 根入口文件 //index.js //看代码我们知道入口是app.js ...
- 【水滴石穿】react-native-ble-demo
项目的话,是想打开蓝牙,然后连接设备 点击已经连接的设备,我们会看到一些设备 不过我这边在开启蓝牙的时候报错了 先放作者的项目地址: https://github.com/hezhii/react-n ...
- 【水滴石穿】ReactNative-Redux-Thunk
老实说,运行出来的项目让人失望,毕竟我想看各种有趣的demo啊- 先放上源码地址:https://github.com/ludejun/ReactNative-Redux-Thunk 我们来一起看看代 ...
- 【水滴石穿】mobx-todos
我觉得代码在有些程序员手里,就好像是画笔,可以创造很多东西 不要觉得创意少就叫没有创意,每天进步一点点,世界更美好 首先源码地址为:https://github.com/byk04712/mobx-t ...
- 【水滴石穿】ReactNativeMobxFrame
项目地址如下:https://github.com/FTD-ZF/ReactNativeMobxFrame 应该可以说的是,项目也只是一个花架子,不过底部的tab稍微改变了 我们一起来看代码 //in ...
- 【水滴石穿】react-native-aze
说个题外话,早上打开电脑的时候,电脑变成彩色的了,锅是我曾经安装的一个chrome扩展,没有经过我的同意开启了 (也许是昨天迷迷糊糊开启了) 上午运行项目都不成功,还以为被黑客攻击了---然后下午就排 ...
随机推荐
- 如何查看PostgreSQL正在执行的SQL
SELECT procpid, start, now() - start AS lap, current_query FROM (SELECT ...
- 微信小程序上传报错:以下文件没有被打包上传: · .gitignore
简单粗暴的办法就是:找到gitignore文件,把该文件删除掉即可. 在使用Git的过程中,我们喜欢有的文件比如日志,临时文件,编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这 ...
- 深入浅出 Java Concurrency (16): 并发容器 part 1 ConcurrentMap (1)[转]
从这一节开始正式进入并发容器的部分,来看看JDK 6带来了哪些并发容器. 在JDK 1.4以下只有Vector和Hashtable是线程安全的集合(也称并发容器,Collections.synchro ...
- Delphi 设计模式:《HeadFirst设计模式》Delphi2007代码---工厂模式之工厂方法[转]
1 2{<HeadFirst设计模式>工厂模式之工厂方法 } 3{ 产品类 } 4{ 编译工具 :Delphi20 ...
- 通过三个DEMO学会SignalR的三种实现方式 转载https://www.cnblogs.com/zuowj/p/5674615.html
一.理解SignalR ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信(即:客户端(Web页面)和服务器端可以互相实时的通知消息 ...
- Maven实战07_依赖
1:依赖声明 <project> ... <dependencies> <dependency> <groupId>...</groupId> ...
- java连接达梦数据库的简单代码
1. 引用DmJdbcDriver.jar包 2. 编写代码: String driver= "dm.jdbc.driver.DmDriver"; String url= &quo ...
- python学习之路-day1
1 变量 赋值:变量可以是字符串.序列.元组. # author:hams.ali # 界面 line = '-*'*20 # 数字直接可以计算 _var1 = ' # 字符变量拼接 _var_2 = ...
- 两周的业余时间,写了个简单的shell
Linux下的,环境是 Fedora 实现了基本的内部命令功能,及比较完善的内部命令框架. 类似于MFC消息映射表的方式,写完一个内部命令,只需要向这个头文件中,导入一个头文件,再写入命令处理函数,就 ...
- 浓缩版 《C和指针》基础篇(Chpt.1~Chpt.9)
导语 近日,笔者在课业之余阅读了<C和指针(Pointers on C)> (by Kenneth A.Reek)一书,从中记录了关于C语言的诸多知识点,包括在C语言基础特性的学习过程中没 ...