Browse Source

add a feature when changing the customStyle or customScript, auto changing the height of webview on iOS

iou90 5 years ago
parent
commit
10c1516970
4 changed files with 73 additions and 24 deletions
  1. 3
    1
      README.md
  2. 28
    7
      autoHeightWebView/common.js
  3. 9
    9
      autoHeightWebView/index.ios.js
  4. 33
    7
      demo/App.js

+ 3
- 1
README.md View File

@@ -22,7 +22,9 @@ Cause of moving View.propTypes to ViewPropTypes in React Naitve 0.44 (https://gi
22 22
 
23 23
 ```javascript
24 24
 <AutoHeightWebView
25
-    onHeightUpdated={height => console.log(height)},
25
+    scrollEnabled: PropTypes.bool,
26
+    // either height or width updated will trigger this
27
+    onSizeUpdated: PropTypes.func,
26 28
     // if page contains iframe on iOS, use a specific script for it
27 29
     hasIframe={true}
28 30
     /*

+ 28
- 7
autoHeightWebView/common.js View File

@@ -2,6 +2,8 @@
2 2
 
3 3
 import { Dimensions } from 'react-native';
4 4
 
5
+import Immutable from 'immutable';
6
+
5 7
 function appendFilesToHead(files, script) {
6 8
   if (!files) {
7 9
     return script;
@@ -33,27 +35,46 @@ body {
33 35
 `;
34 36
 
35 37
 function appendStylesToHead(styles, script) {
36
-  const currentStyles = bodyStyle + styles;
38
+  const currentStyles = styles ? bodyStyle + styles : bodyStyle;
37 39
   // Escape any single quotes or newlines in the CSS with .replace()
38 40
   const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
39 41
   return `
40 42
           var styleElement = document.createElement('style');
41
-          var styleText = document.createTextNode('${escaped}');
42
-          styleElement.appendChild(styleText);
43
+          styleElement.innerHTML = '${escaped}';
43 44
           document.head.appendChild(styleElement);
44 45
           ${script}
45 46
         `;
46 47
 }
47 48
 
49
+function getReloadRelatedData(props) {
50
+  const { hasIframe, files, customStyle, customScript, style } = props;
51
+  return {
52
+    hasIframe,
53
+    files,
54
+    customStyle,
55
+    customScript,
56
+    style
57
+  };
58
+}
59
+
60
+function isChanged(newValue, oldValue) {
61
+  return !Immutable.is(Immutable.fromJS(newValue), Immutable.fromJS(oldValue));
62
+}
63
+
48 64
 function getScript(props, getBaseScript, getIframeBaseScript) {
49
-  const { hasIframe, files, customStyle } = props;
50
-  const baseScript = getBaseScript(props.style);
51
-  let script = hasIframe ? baseScript : getIframeBaseScript(props.style);
65
+  const { hasIframe, files, customStyle, customScript, style } = props;
66
+  const baseScript = getBaseScript(style);
67
+  let script = hasIframe ? baseScript : getIframeBaseScript(style);
52 68
   script = files ? appendFilesToHead(files, baseScript) : baseScript;
53 69
   script = appendStylesToHead(customStyle, script);
70
+  customScript && (script = customScript + script);
54 71
   return script;
55 72
 }
56 73
 
74
+function needChangeSource(nextProps, props) {
75
+ return nextProps && props && isChanged(getReloadRelatedData(nextProps), getReloadRelatedData(props));
76
+}
77
+
57 78
 function handleSizeUpdated(height, width, onSizeUpdated) {
58 79
   onSizeUpdated &&
59 80
     onSizeUpdated({
@@ -71,4 +92,4 @@ observer.observe(document, {
71 92
 });
72 93
 `;
73 94
 
74
-export { getWidth, getScript, handleSizeUpdated, domMutationObserveScript };
95
+export { needChangeSource, getWidth, getScript, handleSizeUpdated, domMutationObserveScript };

+ 9
- 9
autoHeightWebView/index.ios.js View File

@@ -6,7 +6,7 @@ import { Animated, StyleSheet, ViewPropTypes, WebView } from 'react-native';
6 6
 
7 7
 import PropTypes from 'prop-types';
8 8
 
9
-import { getWidth, getScript, handleSizeUpdated, domMutationObserveScript } from './common.js';
9
+import { needChangeSource, getWidth, getScript, handleSizeUpdated, domMutationObserveScript } from './common.js';
10 10
 
11 11
 export default class AutoHeightWebView extends PureComponent {
12 12
   static propTypes = {
@@ -66,6 +66,7 @@ export default class AutoHeightWebView extends PureComponent {
66 66
       height && this.setState({ height });
67 67
     }
68 68
     this.setState({ script: getScript(nextProps, getBaseScript, getIframeBaseScript) });
69
+    this.needChangeSource = needChangeSource(nextProps, this.props);
69 70
   }
70 71
 
71 72
   handleNavigationStateChange = navState => {
@@ -116,11 +117,14 @@ export default class AutoHeightWebView extends PureComponent {
116 117
       enableAnimation,
117 118
       source,
118 119
       heightOffset,
119
-      customScript,
120 120
       style,
121 121
       scrollEnabled
122 122
     } = this.props;
123
-    const webViewSource = Object.assign({}, source, { baseUrl: 'web/' });
123
+    let webViewSource = Object.assign({}, source, { baseUrl: 'web/' });
124
+    if (this.needChangeSource) {
125
+      this.changeSourceFlag = !this.changeSourceFlag;
126
+      webViewSource = Object.assign(webViewSource, { changeSourceFlag: this.changeSourceFlag });
127
+    }
124 128
     return (
125 129
       <Animated.View
126 130
         style={[
@@ -141,8 +145,8 @@ export default class AutoHeightWebView extends PureComponent {
141 145
           onLoadEnd={onLoadEnd}
142 146
           onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
143 147
           style={styles.webView}
144
-          injectedJavaScript={script + customScript}
145
-          scrollEnabled={scrollEnabled}
148
+          injectedJavaScript={script}
149
+          scrollEnabled={!!scrollEnabled}
146 150
           scalesPageToFit={scalesPageToFit}
147 151
           source={webViewSource}
148 152
           onNavigationStateChange={this.handleNavigationStateChange}
@@ -184,7 +188,6 @@ function getBaseScript(style) {
184 188
     ;
185 189
     ${getSize}
186 190
     (function () {
187
-        var i = 0;
188 191
         var height = 0;
189 192
         var width = ${getWidth(style)};
190 193
         var wrapper = document.createElement('div');
@@ -199,7 +202,6 @@ function getBaseScript(style) {
199 202
                 height = size.height;
200 203
                 width = size.width;
201 204
                 document.title = height.toString() + ',' + width.toString();
202
-                window.location.hash = ++i;
203 205
             }
204 206
         }
205 207
         ${commonScript}
@@ -213,7 +215,6 @@ function getIframeBaseScript(style) {
213 215
     ;
214 216
     ${getSize}
215 217
     (function () {
216
-        var i = 0;
217 218
         var height = 0;
218 219
         var width = ${getWidth(style)};
219 220
         function updateSize() {
@@ -222,7 +223,6 @@ function getIframeBaseScript(style) {
222 223
                 height = size.height;
223 224
                 width = size.width;
224 225
                 document.title = height.toString() + ',' + width.toString();
225
-                window.location.hash = ++i;
226 226
             }
227 227
         }
228 228
         ${commonScript}

+ 33
- 7
demo/App.js View File

@@ -11,12 +11,26 @@ export default class Explorer extends Component {
11 11
     super(props);
12 12
     this.html0 = `<p style="font-weight: 400;font-style: normal;font-size: 21px;line-height: 1.58;letter-spacing: -.003em;">Tags are great for describing the essence of your story in a single word or phrase, but stories are rarely about a single thing. <span style="background-color: transparent !important;background-image: linear-gradient(to bottom, rgba(146, 249, 190, 1), rgba(146, 249, 190, 1));">If I pen a story about moving across the country to start a new job in a car with my husband, two cats, a dog, and a tarantula, I wouldn’t only tag the piece with “moving”. I’d also use the tags “pets”, “marriage”, “career change”, and “travel tips”.</span></p>`;
13 13
     this.html1 = `Tags are great for describing the essence of your story in a single word or phrase, but stories are rarely about a single thing. If I pen a story about moving across the country to start a new job in a car with my husband, two cats, a dog, and a tarantula, I wouldn’t only tag the piece with “moving”. I’d also use the tags “pets”, “marriage”, “career change”, and “travel tips”.`;
14
-    this.script0 = '';
14
+    this.testStyle = `
15
+    p {
16
+      font-size: 25px !important;
17
+    }
18
+    `;
19
+    this.script0 = `
20
+    var styleElement = document.createElement('style');
21
+    styleElement.innerHTML = '${this.testStyle.replace(/\'/g, "\\'").replace(/\n/g, '\\n')}';
22
+    document.head.appendChild(styleElement)
23
+    `;
15 24
     this.script1 = `document.body.style.background = 'cornflowerblue';`;
25
+    // this.script1 = null;
16 26
     this.state = {
17 27
       html: this.html0,
18
-      script: this.script0,
19
-      height: 0
28
+      script: null,
29
+      webViewStyle: null,
30
+      size: {
31
+        height: 0,
32
+        width: 0
33
+      }
20 34
     };
21 35
   }
22 36
 
@@ -26,15 +40,21 @@ export default class Explorer extends Component {
26 40
     }));
27 41
   };
28 42
 
43
+  changeStyle = () => {
44
+    this.setState(prevState => ({
45
+      webViewStyle: prevState.webViewStyle == null ? this.testStyle : null
46
+    }));
47
+  };
48
+
29 49
   changeScript = () => {
30
-    this.changeSource();
50
+    // this.changeSource();
31 51
     this.setState(prevState => ({
32 52
       script: prevState.script === this.script0 ? this.script1 : this.script0
33 53
     }));
34 54
   };
35 55
 
36 56
   render() {
37
-    const { html, script, height } = this.state;
57
+    const { html, size, webViewStyle, script } = this.state;
38 58
     return (
39 59
       <ScrollView
40 60
         style={{
@@ -46,6 +66,7 @@ export default class Explorer extends Component {
46 66
         }}
47 67
       >
48 68
         <AutoHeightWebView
69
+          customStyle={webViewStyle}
49 70
           onError={() => console.log('on error')}
50 71
           onLoad={() => console.log('on load')}
51 72
           onLoadStart={() => console.log('on load start')}
@@ -54,17 +75,22 @@ export default class Explorer extends Component {
54 75
             console.log(result);
55 76
             return true;
56 77
           }}
57
-          onHeightUpdated={height => this.setState({ height })}
78
+          onSizeUpdated={size => this.setState({ size })}
58 79
           source={{ html }}
59 80
           customScript={script}
60 81
         />
61 82
         <TouchableOpacity onPress={this.changeSource} style={styles.button}>
62 83
           <Text>change source</Text>
63 84
         </TouchableOpacity>
85
+        <TouchableOpacity onPress={this.changeStyle} style={styles.button}>
86
+          <Text>change style</Text>
87
+        </TouchableOpacity>
64 88
         <TouchableOpacity onPress={this.changeScript} style={styles.button}>
65 89
           <Text>change script (have to change source to reload on android)</Text>
66 90
         </TouchableOpacity>
67
-        <Text style={{ padding: 5 }}>{height}</Text>
91
+        <Text style={{ padding: 5 }}>
92
+          height: {size.height}, width: {size.width}
93
+        </Text>
68 94
       </ScrollView>
69 95
     );
70 96
   }