暫無描述

index.android.old.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. 'use strict';
  2. import React, { PureComponent } from 'react';
  3. import { Animated, Dimensions, StyleSheet, WebView } from 'react-native';
  4. import { androidPropTypes } from './propTypes.js';
  5. import Immutable from 'immutable';
  6. import { handleSizeUpdated, domMutationObserveScript } from './common.js';
  7. export default class AutoHeightWebView extends PureComponent {
  8. static propTypes = androidPropTypes;
  9. static defaultProps = {
  10. scalesPageToFit: true,
  11. enableBaseUrl: false,
  12. enableAnimation: true,
  13. animationDuration: 555,
  14. heightOffset: 20
  15. };
  16. constructor(props) {
  17. super(props);
  18. props.enableAnimation && (this.opacityAnimatedValue = new Animated.Value(0));
  19. this.state = {
  20. isChangingSource: false,
  21. height: 0,
  22. heightOffset: 0,
  23. script: baseScript
  24. };
  25. }
  26. componentDidMount() {
  27. this.startInterval();
  28. }
  29. componentWillReceiveProps(nextProps) {
  30. // injectedJavaScript only works when webView reload (source changed)
  31. if (Immutable.is(Immutable.fromJS(this.props.source), Immutable.fromJS(nextProps.source))) {
  32. return;
  33. } else {
  34. this.setState(
  35. {
  36. isChangingSource: true,
  37. height: 0,
  38. heightOffset: 0
  39. },
  40. () => {
  41. this.startInterval();
  42. this.setState({ isChangingSource: false });
  43. }
  44. );
  45. }
  46. this.setState({ script: baseScript });
  47. }
  48. componentWillUnmount() {
  49. this.stopInterval();
  50. }
  51. startInterval() {
  52. this.finishInterval = false;
  53. this.interval = setInterval(() => !this.finishInterval && this.webView.postMessage('getBodyHeight'), 205);
  54. }
  55. stopInterval() {
  56. this.finishInterval = true;
  57. clearInterval(this.interval);
  58. }
  59. onMessage = event => {
  60. const height = parseInt(event.nativeEvent.data);
  61. if (height && height !== this.state.height) {
  62. const { enableAnimation, animationDuration, heightOffset, onSizeUpdated, style } = this.props;
  63. enableAnimation && this.opacityAnimatedValue.setValue(0);
  64. this.stopInterval();
  65. this.setState(
  66. {
  67. heightOffset,
  68. height
  69. },
  70. () => {
  71. const currentWidth = Object.assign(styles.container, style).width;
  72. enableAnimation
  73. ? Animated.timing(this.opacityAnimatedValue, {
  74. toValue: 1,
  75. duration: animationDuration
  76. }).start(() => handleSizeUpdated(height, currentWidth, onSizeUpdated))
  77. : handleSizeUpdated(height, currentWidth, onSizeUpdated);
  78. }
  79. );
  80. }
  81. const { onMessage } = this.props;
  82. onMessage && onMessage(event);
  83. };
  84. getWebView = webView => (this.webView = webView);
  85. render() {
  86. const { height, script, isChangingSource, heightOffset } = this.state;
  87. const {
  88. thirdPartyCookiesEnabled,
  89. domStorageEnabled,
  90. userAgent,
  91. geolocationEnabled,
  92. allowUniversalAccessFromFileURLs,
  93. mixedContentMode,
  94. onNavigationStateChange,
  95. renderError,
  96. originWhitelist,
  97. mediaPlaybackRequiresUserAction,
  98. scalesPageToFit,
  99. enableAnimation,
  100. source,
  101. customScript,
  102. style,
  103. enableBaseUrl,
  104. onError,
  105. onLoad,
  106. onLoadStart,
  107. onLoadEnd
  108. } = this.props;
  109. let webViewSource = source;
  110. if (enableBaseUrl) {
  111. webViewSource = Object.assign({}, source, {
  112. baseUrl: 'file:///android_asset/web/'
  113. });
  114. }
  115. return (
  116. <Animated.View
  117. style={[
  118. styles.container,
  119. {
  120. opacity: enableAnimation ? this.opacityAnimatedValue : 1,
  121. height: height + heightOffset
  122. },
  123. style
  124. ]}
  125. >
  126. {isChangingSource ? null : (
  127. <WebView
  128. onNavigationStateChange={onNavigationStateChange}
  129. domStorageEnabled={domStorageEnabled}
  130. thirdPartyCookiesEnabled={thirdPartyCookiesEnabled}
  131. userAgent={userAgent}
  132. geolocationEnabled={geolocationEnabled}
  133. allowUniversalAccessFromFileURLs={allowUniversalAccessFromFileURLs}
  134. mixedContentMode={mixedContentMode}
  135. renderError={renderError}
  136. mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction}
  137. originWhitelist={originWhitelist}
  138. ref={this.getWebView}
  139. onMessage={this.onMessage}
  140. onError={onError}
  141. onLoad={onLoad}
  142. onLoadStart={onLoadStart}
  143. onLoadEnd={onLoadEnd}
  144. style={styles.webView}
  145. scalesPageToFit={scalesPageToFit}
  146. javaScriptEnabled={true}
  147. injectedJavaScript={script + customScript}
  148. source={webViewSource}
  149. messagingEnabled={true}
  150. />
  151. )}
  152. </Animated.View>
  153. );
  154. }
  155. }
  156. const screenWidth = Dimensions.get('window').width;
  157. const styles = StyleSheet.create({
  158. container: {
  159. height: 50,
  160. width: screenWidth,
  161. backgroundColor: 'transparent'
  162. },
  163. webView: {
  164. flex: 1,
  165. backgroundColor: 'transparent'
  166. }
  167. });
  168. const baseScript = `
  169. ; (function () {
  170. document.addEventListener('message', function (e) {
  171. window.postMessage(String(document.body.offsetHeight));
  172. });
  173. ${domMutationObserveScript}
  174. } ());
  175. `;