暂无描述

index.ios.js 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. 'use strict';
  2. import React, { PureComponent } from 'react';
  3. import { Animated, Dimensions, StyleSheet, ViewPropTypes, WebView } from 'react-native';
  4. import PropTypes from 'prop-types';
  5. import { getScript, onHeightUpdated, onWidthUpdated, onHeightWidthUpdated, domMutationObserveScript } from './common.js';
  6. const screenWidth = Dimensions.get('window').width;
  7. export default class AutoHeightWebView extends PureComponent {
  8. static propTypes = {
  9. hasIframe: PropTypes.bool,
  10. source: WebView.propTypes.source,
  11. onHeightUpdated: PropTypes.func,
  12. onWidthUpdated: PropTypes.func,
  13. onHeightWidthUpdated: PropTypes.func,
  14. shouldResizeWidth: PropTypes.bool,
  15. customScript: PropTypes.string,
  16. customStyle: PropTypes.string,
  17. enableAnimation: PropTypes.bool,
  18. // if set to true may cause some layout issues (smaller font size)
  19. scalesPageToFit: PropTypes.bool,
  20. // only works on enable animation
  21. animationDuration: PropTypes.number,
  22. // offset of rn webview margin
  23. heightOffset: PropTypes.number,
  24. widthOffset: PropTypes.number,
  25. style: ViewPropTypes.style,
  26. // rn WebView callback
  27. onError: PropTypes.func,
  28. onLoad: PropTypes.func,
  29. onLoadStart: PropTypes.func,
  30. onLoadEnd: PropTypes.func,
  31. onShouldStartLoadWithRequest: PropTypes.func,
  32. // add web/files... to project root
  33. files: PropTypes.arrayOf(
  34. PropTypes.shape({
  35. href: PropTypes.string,
  36. type: PropTypes.string,
  37. rel: PropTypes.string
  38. })
  39. )
  40. };
  41. static defaultProps = {
  42. scalesPageToFit: false,
  43. enableAnimation: true,
  44. animationDuration: 555,
  45. heightOffset: 12,
  46. widthOffset: 12,
  47. shouldResizeWidth: false
  48. };
  49. constructor(props) {
  50. super(props);
  51. props.enableAnimation && (this.opacityAnimatedValue = new Animated.Value(0));
  52. this.state = {
  53. height: 0,
  54. //heightOffset: 0, //?? I added this
  55. width: screenWidth,
  56. //widthOffset: 0,
  57. script: getScript(props, baseScript, iframeBaseScript)
  58. };
  59. }
  60. componentWillReceiveProps(nextProps) {
  61. this.setState({ script: getScript(nextProps, baseScript, iframeBaseScript) });
  62. }
  63. handleNavigationStateChange = navState => {
  64. var [width, height] = navState.title.split(',');
  65. width = Number(width);
  66. height = Number(height);
  67. const { enableAnimation, animationDuration } = this.props;
  68. if (height && height !== this.state.height) { // ??? add to logic ??? width && width !== this.state.width
  69. enableAnimation && this.opacityAnimatedValue.setValue(0);
  70. this.setState({ height, width }, () => {
  71. enableAnimation
  72. ? Animated.timing(this.opacityAnimatedValue, {
  73. toValue: 1,
  74. duration: animationDuration
  75. }).start(() => onHeightWidthUpdated(height, width, this.props))
  76. : onHeightWidthUpdated(height, width, this.props);
  77. });
  78. }
  79. };
  80. getWebView = webView => (this.webView = webView);
  81. stopLoading() {
  82. this.webView.stopLoading();
  83. }
  84. render() {
  85. const { height, width, script } = this.state;
  86. const {
  87. onError,
  88. onLoad,
  89. onLoadStart,
  90. onLoadEnd,
  91. onShouldStartLoadWithRequest,
  92. scalesPageToFit,
  93. enableAnimation,
  94. source,
  95. heightOffset,
  96. widthOffset,
  97. customScript,
  98. style
  99. } = this.props;
  100. const webViewSource = Object.assign({}, source, { baseUrl: 'web/' });
  101. return (
  102. <Animated.View
  103. style={[
  104. styles.container,
  105. {
  106. opacity: enableAnimation ? this.opacityAnimatedValue : 1,
  107. height: height + heightOffset,
  108. width: width + widthOffset
  109. },
  110. style
  111. ]}
  112. >
  113. <WebView
  114. ref={this.getWebView}
  115. onError={onError}
  116. onLoad={onLoad}
  117. onLoadStart={onLoadStart}
  118. onLoadEnd={onLoadEnd}
  119. onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
  120. style={styles.webView}
  121. injectedJavaScript={script + customScript}
  122. scrollEnabled={false}
  123. scalesPageToFit={scalesPageToFit}
  124. source={webViewSource}
  125. onNavigationStateChange={this.handleNavigationStateChange}
  126. />
  127. </Animated.View>
  128. );
  129. }
  130. }
  131. const styles = StyleSheet.create({
  132. container: {
  133. backgroundColor: 'transparent'
  134. },
  135. webView: {
  136. flex: 1,
  137. backgroundColor: 'transparent'
  138. }
  139. });
  140. const commonScript = `
  141. updateSize();
  142. window.addEventListener('load', updateSize);
  143. window.addEventListener('resize', updateSize);
  144. `;
  145. const _getter = `
  146. function getHeight(height) {
  147. if(height < 1) {
  148. return document.body.offsetHeight;
  149. }
  150. return height;
  151. }
  152. function getWidth(width) {
  153. if(width < 1) {
  154. return document.body.clientWidth; // maybe should be .offsetWidth ??
  155. }
  156. return width;
  157. }
  158. `;
  159. const baseScript = `
  160. ;
  161. ${_getter}
  162. (function () {
  163. var i = 0;
  164. var height = 0;
  165. var width = ${screenWidth};
  166. var wrapper = document.createElement('div');
  167. wrapper.id = 'height-wrapper';
  168. while (document.body.firstChild instanceof Node) {
  169. wrapper.appendChild(document.body.firstChild);
  170. }
  171. document.body.appendChild(wrapper);
  172. function updateSize() {
  173. var rect = document.body.firstElementChild.getBoundingClientRect().toJSON();
  174. var newWidth = Math.round(rect.width);
  175. var newHeight = Math.round(rect.height);
  176. if(newHeight !== height) {
  177. //height = getHeight(wrapper.clientHeight);
  178. //width = getWidth(wrapper.clientWidth);
  179. document.title = newWidth + ',' + newHeight;
  180. window.location.hash = ++i;
  181. }
  182. }
  183. ${commonScript}
  184. ${domMutationObserveScript}
  185. } ());
  186. `;
  187. const iframeBaseScript = `
  188. ;
  189. ${_getter}
  190. (function () {
  191. var i = 0;
  192. var height = 0;
  193. var width = ${screenWidth};
  194. function updateSize() {
  195. var rect = document.body.firstElementChild.getBoundingClientRect().toJSON();
  196. var newWidth = Math.round(rect.width);
  197. var newHeight = Math.round(rect.height);
  198. if(newHeight !== height) {
  199. //height = getHeight(document.body.firstChild.clientHeight);
  200. //width = getWidth(document.body.firstChild.clientHeight);
  201. document.title = newWidth + ',' + newHeight;
  202. window.location.hash = ++i;
  203. }
  204. }
  205. ${commonScript}
  206. ${domMutationObserveScript}
  207. } ());
  208. `;