diff --git a/js/project/Fireworks.js b/js/project/Fireworks.js new file mode 100644 index 0000000..ad163ed --- /dev/null +++ b/js/project/Fireworks.js @@ -0,0 +1,191 @@ +'use strict' +import React,{ + StyleSheet, + View, + Animated, + Component +} from 'react-native'; +import Dimensions from 'Dimensions'; + +var screenWidth = Dimensions.get('window').width; +var screenHeight = Dimensions.get('window').height; + +var COLORS = ['#FF5252', '#FF4081', '#E040FB', '#7C4DFF', '#448AFF', '#40C4FF', '#69F0AE', '#FFFF00', '#FFD740', '#FF6E40']; +var PARTICLE_COUNT = 12; + +class SingleFirework extends Component { + constructor(props) { + super(props); + this._mounted = false; + this.riseAnim = new Animated.Value(0); + this.riseOpacity = new Animated.Value(1); + this.particles = []; + for (var i = 0; i < PARTICLE_COUNT; i++) { + this.particles.push({ + x: new Animated.Value(0), + y: new Animated.Value(0), + opacity: new Animated.Value(0), + }); + } + this.state = { + color: COLORS[Math.floor(Math.random() * COLORS.length)], + originX: Math.random() * (screenWidth - 60) + 30, + targetY: -(Math.random() * screenHeight * 0.3 + screenHeight * 0.15), + }; + } + + componentDidMount() { + this._mounted = true; + this._delayTimer = setTimeout(() => { + if (this._mounted) { + this._startAnimation(); + } + }, this.props.delay || 0); + } + + componentWillUnmount() { + this._mounted = false; + if (this._delayTimer) { + clearTimeout(this._delayTimer); + } + if (this._restartTimer) { + clearTimeout(this._restartTimer); + } + } + + _resetValues() { + this.riseAnim.setValue(0); + this.riseOpacity.setValue(1); + this.particles.forEach(function(p) { + p.x.setValue(0); + p.y.setValue(0); + p.opacity.setValue(0); + }); + } + + _startAnimation() { + if (!this._mounted) return; + + this._resetValues(); + + var newColor = COLORS[Math.floor(Math.random() * COLORS.length)]; + var newOriginX = Math.random() * (screenWidth - 60) + 30; + var newTargetY = -(Math.random() * screenHeight * 0.3 + screenHeight * 0.15); + this.setState({color: newColor, originX: newOriginX, targetY: newTargetY}); + + var riseDuration = 800 + Math.random() * 400; + + var riseAnimation = Animated.parallel([ + Animated.timing(this.riseAnim, { + toValue: 1, + duration: riseDuration, + }), + Animated.timing(this.riseOpacity, { + toValue: 0, + duration: riseDuration, + }), + ]); + + var explodeAnimations = this.particles.map(function(p, i) { + var angle = (i / PARTICLE_COUNT) * Math.PI * 2; + var distance = 30 + Math.random() * 60; + var dx = Math.cos(angle) * distance; + var dy = Math.sin(angle) * distance; + + return Animated.parallel([ + Animated.timing(p.x, {toValue: dx, duration: 700}), + Animated.timing(p.y, {toValue: dy + 20, duration: 700}), + Animated.sequence([ + Animated.timing(p.opacity, {toValue: 1, duration: 50}), + Animated.timing(p.opacity, {toValue: 0, duration: 650}), + ]), + ]); + }); + + var self = this; + Animated.sequence([ + riseAnimation, + Animated.parallel(explodeAnimations), + ]).start(function() { + if (self._mounted) { + self._restartTimer = setTimeout(function() { + self._startAnimation(); + }, Math.random() * 1000 + 500); + } + }); + } + + render() { + var color = this.state.color; + var originX = this.state.originX; + var targetY = this.state.targetY; + + var riseY = this.riseAnim.interpolate({ + inputRange: [0, 1], + outputRange: [0, targetY], + }); + + var particleViews = this.particles.map(function(p, i) { + return ( + + ); + }); + + return ( + + + + {particleViews} + + + ); + } +} + +export default class Fireworks extends Component { + render() { + return ( + + + + + + + + ); + } +} + +var styles = StyleSheet.create({ + container: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: 'transparent', + }, +}); diff --git a/js/project/MyIndex.js b/js/project/MyIndex.js index c9b371a..269cf77 100644 --- a/js/project/MyIndex.js +++ b/js/project/MyIndex.js @@ -8,22 +8,25 @@ import React,{ TouchableHighlight, TouchableOpacity, NavigatorIOS, - Component + Component, + Alert, + AppState } from 'react-native'; import Swiper from 'react-native-swiper'; import Dimensions from 'Dimensions'; import ServiceType from './serviceType'; import Home from './Home.js'; +import Fireworks from './Fireworks.js'; var width = Dimensions.get('window').width; export default class MyIndex extends Component{ constructor(props){ super(props); this.state = { - imageurls:[] } - + this._lastAlertDate = null; + this._handleAppStateChange = this._handleAppStateChange.bind(this); } banner(urls){ @@ -44,7 +47,35 @@ export default class MyIndex extends Component{ }); } + _checkDailyReminder(){ + var now = new Date(); + var hour = now.getHours(); + var todayStr = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate(); + if (hour === 8 && this._lastAlertDate !== todayStr) { + this._lastAlertDate = todayStr; + Alert.alert( + '新品推荐', + '今日有新产品上线,欢迎前往线下门店选购!', + [{text: '知道了'}] + ); + } + } + _handleAppStateChange(appState){ + if (appState === 'active') { + this._checkDailyReminder(); + } + } componentDidMount(){ + Alert.alert( + '温馨提示', + '本网站正在升级中,部分功能可能暂时无法使用,敬请谅解!', + [{text: '我知道了'}] + ); + this._checkDailyReminder(); + this._reminderTimer = setInterval(() => { + this._checkDailyReminder(); + }, 60000); + AppState.addEventListener('change', this._handleAppStateChange); fetch('http://api.gujia007.com/v1/flash-data') .then((res) => { @@ -62,6 +93,12 @@ export default class MyIndex extends Component{ } + componentWillUnmount(){ + if (this._reminderTimer) { + clearInterval(this._reminderTimer); + } + AppState.removeEventListener('change', this._handleAppStateChange); + } render() { let urls = this.state.imageurls; @@ -94,6 +131,7 @@ export default class MyIndex extends Component{ + );