暫無描述

index.js 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. 'use strict';
  2. import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
  3. import { StyleSheet, Platform, ViewPropTypes } from 'react-native';
  4. import PropTypes from 'prop-types';
  5. import { WebView } from 'react-native-webview';
  6. import { reduceData, getWidth, isSizeChanged, shouldUpdate } from './utils';
  7. const AutoHeightWebView = React.memo(
  8. forwardRef((props, ref) => {
  9. const { style, onMessage, onSizeUpdated, scrollEnabledWithZoomedin, scrollEnabled, source } = props;
  10. if (!source) {
  11. return null;
  12. }
  13. let webView = useRef();
  14. useImperativeHandle(ref, () => ({
  15. stopLoading: () => webView.current.stopLoading(),
  16. goForward: () => webView.current.goForward(),
  17. goBack: () => webView.current.goBack(),
  18. reload: () => webView.current.reload(),
  19. injectJavaScript: script => webView.current.injectJavaScript(script)
  20. }));
  21. const [size, setSize] = useState({
  22. height: style && style.height ? style.height : 0,
  23. width: getWidth(style)
  24. });
  25. const [scrollable, setScrollable] = useState(false);
  26. const handleMessage = event => {
  27. onMessage && onMessage(event);
  28. if (!event.nativeEvent) {
  29. return;
  30. }
  31. let data = {};
  32. // Sometimes the message is invalid JSON, so we ignore that case
  33. try {
  34. data = JSON.parse(event.nativeEvent.data);
  35. } catch (error) {
  36. console.error(error);
  37. return;
  38. }
  39. const { height, width, zoomedin } = data;
  40. !scrollEnabled && scrollEnabledWithZoomedin && setScrollable(!!zoomedin);
  41. const { height: previousHeight, width: previousWidth } = size;
  42. isSizeChanged({ height, previousHeight, width, previousWidth }) &&
  43. setSize({
  44. height,
  45. width
  46. });
  47. };
  48. const currentScrollEnabled = scrollEnabled === false && scrollEnabledWithZoomedin ? scrollable : scrollEnabled;
  49. const { currentSource, script } = reduceData(props);
  50. const { width, height } = size;
  51. useEffect(
  52. () =>
  53. onSizeUpdated &&
  54. onSizeUpdated({
  55. height,
  56. width
  57. }),
  58. [width, height, onSizeUpdated]
  59. );
  60. return (
  61. <WebView
  62. useWebKit={false}
  63. {...props}
  64. ref={webView}
  65. onMessage={handleMessage}
  66. style={[
  67. styles.webView,
  68. {
  69. width,
  70. height
  71. },
  72. style
  73. ]}
  74. injectedJavaScript={script}
  75. source={currentSource}
  76. scrollEnabled={currentScrollEnabled}
  77. />
  78. );
  79. }),
  80. (prevProps, nextProps) => !shouldUpdate({ prevProps, nextProps })
  81. );
  82. AutoHeightWebView.propTypes = {
  83. onSizeUpdated: PropTypes.func,
  84. files: PropTypes.arrayOf(
  85. PropTypes.shape({
  86. href: PropTypes.string,
  87. type: PropTypes.string,
  88. rel: PropTypes.string
  89. })
  90. ),
  91. style: ViewPropTypes.style,
  92. customScript: PropTypes.string,
  93. customStyle: PropTypes.string,
  94. viewportContent: PropTypes.string,
  95. scrollEnabledWithZoomedin: PropTypes.bool,
  96. // webview props
  97. originWhitelist: PropTypes.arrayOf(PropTypes.string),
  98. onMessage: PropTypes.func,
  99. scalesPageToFit: PropTypes.bool,
  100. source: PropTypes.object
  101. };
  102. let defaultProps = {
  103. showsVerticalScrollIndicator: false,
  104. showsHorizontalScrollIndicator: false,
  105. originWhitelist: ['*']
  106. };
  107. Platform.OS === 'android' &&
  108. Object.assign(defaultProps, {
  109. scalesPageToFit: false
  110. });
  111. Platform.OS === 'ios' &&
  112. Object.assign(defaultProps, {
  113. viewportContent: 'width=device-width'
  114. });
  115. AutoHeightWebView.defaultProps = defaultProps;
  116. const styles = StyleSheet.create({
  117. webView: {
  118. backgroundColor: 'transparent'
  119. }
  120. });
  121. export default AutoHeightWebView;