Browse Source

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

iou90 6 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
 
22
 
23
 ```javascript
23
 ```javascript
24
 <AutoHeightWebView
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
     // if page contains iframe on iOS, use a specific script for it
28
     // if page contains iframe on iOS, use a specific script for it
27
     hasIframe={true}
29
     hasIframe={true}
28
     /*
30
     /*

+ 28
- 7
autoHeightWebView/common.js View File

2
 
2
 
3
 import { Dimensions } from 'react-native';
3
 import { Dimensions } from 'react-native';
4
 
4
 
5
+import Immutable from 'immutable';
6
+
5
 function appendFilesToHead(files, script) {
7
 function appendFilesToHead(files, script) {
6
   if (!files) {
8
   if (!files) {
7
     return script;
9
     return script;
33
 `;
35
 `;
34
 
36
 
35
 function appendStylesToHead(styles, script) {
37
 function appendStylesToHead(styles, script) {
36
-  const currentStyles = bodyStyle + styles;
38
+  const currentStyles = styles ? bodyStyle + styles : bodyStyle;
37
   // Escape any single quotes or newlines in the CSS with .replace()
39
   // Escape any single quotes or newlines in the CSS with .replace()
38
   const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
40
   const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
39
   return `
41
   return `
40
           var styleElement = document.createElement('style');
42
           var styleElement = document.createElement('style');
41
-          var styleText = document.createTextNode('${escaped}');
42
-          styleElement.appendChild(styleText);
43
+          styleElement.innerHTML = '${escaped}';
43
           document.head.appendChild(styleElement);
44
           document.head.appendChild(styleElement);
44
           ${script}
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
 function getScript(props, getBaseScript, getIframeBaseScript) {
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
   script = files ? appendFilesToHead(files, baseScript) : baseScript;
68
   script = files ? appendFilesToHead(files, baseScript) : baseScript;
53
   script = appendStylesToHead(customStyle, script);
69
   script = appendStylesToHead(customStyle, script);
70
+  customScript && (script = customScript + script);
54
   return script;
71
   return script;
55
 }
72
 }
56
 
73
 
74
+function needChangeSource(nextProps, props) {
75
+ return nextProps && props && isChanged(getReloadRelatedData(nextProps), getReloadRelatedData(props));
76
+}
77
+
57
 function handleSizeUpdated(height, width, onSizeUpdated) {
78
 function handleSizeUpdated(height, width, onSizeUpdated) {
58
   onSizeUpdated &&
79
   onSizeUpdated &&
59
     onSizeUpdated({
80
     onSizeUpdated({
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
 
6
 
7
 import PropTypes from 'prop-types';
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
 export default class AutoHeightWebView extends PureComponent {
11
 export default class AutoHeightWebView extends PureComponent {
12
   static propTypes = {
12
   static propTypes = {
66
       height && this.setState({ height });
66
       height && this.setState({ height });
67
     }
67
     }
68
     this.setState({ script: getScript(nextProps, getBaseScript, getIframeBaseScript) });
68
     this.setState({ script: getScript(nextProps, getBaseScript, getIframeBaseScript) });
69
+    this.needChangeSource = needChangeSource(nextProps, this.props);
69
   }
70
   }
70
 
71
 
71
   handleNavigationStateChange = navState => {
72
   handleNavigationStateChange = navState => {
116
       enableAnimation,
117
       enableAnimation,
117
       source,
118
       source,
118
       heightOffset,
119
       heightOffset,
119
-      customScript,
120
       style,
120
       style,
121
       scrollEnabled
121
       scrollEnabled
122
     } = this.props;
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
     return (
128
     return (
125
       <Animated.View
129
       <Animated.View
126
         style={[
130
         style={[
141
           onLoadEnd={onLoadEnd}
145
           onLoadEnd={onLoadEnd}
142
           onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
146
           onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
143
           style={styles.webView}
147
           style={styles.webView}
144
-          injectedJavaScript={script + customScript}
145
-          scrollEnabled={scrollEnabled}
148
+          injectedJavaScript={script}
149
+          scrollEnabled={!!scrollEnabled}
146
           scalesPageToFit={scalesPageToFit}
150
           scalesPageToFit={scalesPageToFit}
147
           source={webViewSource}
151
           source={webViewSource}
148
           onNavigationStateChange={this.handleNavigationStateChange}
152
           onNavigationStateChange={this.handleNavigationStateChange}
184
     ;
188
     ;
185
     ${getSize}
189
     ${getSize}
186
     (function () {
190
     (function () {
187
-        var i = 0;
188
         var height = 0;
191
         var height = 0;
189
         var width = ${getWidth(style)};
192
         var width = ${getWidth(style)};
190
         var wrapper = document.createElement('div');
193
         var wrapper = document.createElement('div');
199
                 height = size.height;
202
                 height = size.height;
200
                 width = size.width;
203
                 width = size.width;
201
                 document.title = height.toString() + ',' + width.toString();
204
                 document.title = height.toString() + ',' + width.toString();
202
-                window.location.hash = ++i;
203
             }
205
             }
204
         }
206
         }
205
         ${commonScript}
207
         ${commonScript}
213
     ;
215
     ;
214
     ${getSize}
216
     ${getSize}
215
     (function () {
217
     (function () {
216
-        var i = 0;
217
         var height = 0;
218
         var height = 0;
218
         var width = ${getWidth(style)};
219
         var width = ${getWidth(style)};
219
         function updateSize() {
220
         function updateSize() {
222
                 height = size.height;
223
                 height = size.height;
223
                 width = size.width;
224
                 width = size.width;
224
                 document.title = height.toString() + ',' + width.toString();
225
                 document.title = height.toString() + ',' + width.toString();
225
-                window.location.hash = ++i;
226
             }
226
             }
227
         }
227
         }
228
         ${commonScript}
228
         ${commonScript}

+ 33
- 7
demo/App.js View File

11
     super(props);
11
     super(props);
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>`;
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
     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”.`;
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
     this.script1 = `document.body.style.background = 'cornflowerblue';`;
24
     this.script1 = `document.body.style.background = 'cornflowerblue';`;
25
+    // this.script1 = null;
16
     this.state = {
26
     this.state = {
17
       html: this.html0,
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
     }));
40
     }));
27
   };
41
   };
28
 
42
 
43
+  changeStyle = () => {
44
+    this.setState(prevState => ({
45
+      webViewStyle: prevState.webViewStyle == null ? this.testStyle : null
46
+    }));
47
+  };
48
+
29
   changeScript = () => {
49
   changeScript = () => {
30
-    this.changeSource();
50
+    // this.changeSource();
31
     this.setState(prevState => ({
51
     this.setState(prevState => ({
32
       script: prevState.script === this.script0 ? this.script1 : this.script0
52
       script: prevState.script === this.script0 ? this.script1 : this.script0
33
     }));
53
     }));
34
   };
54
   };
35
 
55
 
36
   render() {
56
   render() {
37
-    const { html, script, height } = this.state;
57
+    const { html, size, webViewStyle, script } = this.state;
38
     return (
58
     return (
39
       <ScrollView
59
       <ScrollView
40
         style={{
60
         style={{
46
         }}
66
         }}
47
       >
67
       >
48
         <AutoHeightWebView
68
         <AutoHeightWebView
69
+          customStyle={webViewStyle}
49
           onError={() => console.log('on error')}
70
           onError={() => console.log('on error')}
50
           onLoad={() => console.log('on load')}
71
           onLoad={() => console.log('on load')}
51
           onLoadStart={() => console.log('on load start')}
72
           onLoadStart={() => console.log('on load start')}
54
             console.log(result);
75
             console.log(result);
55
             return true;
76
             return true;
56
           }}
77
           }}
57
-          onHeightUpdated={height => this.setState({ height })}
78
+          onSizeUpdated={size => this.setState({ size })}
58
           source={{ html }}
79
           source={{ html }}
59
           customScript={script}
80
           customScript={script}
60
         />
81
         />
61
         <TouchableOpacity onPress={this.changeSource} style={styles.button}>
82
         <TouchableOpacity onPress={this.changeSource} style={styles.button}>
62
           <Text>change source</Text>
83
           <Text>change source</Text>
63
         </TouchableOpacity>
84
         </TouchableOpacity>
85
+        <TouchableOpacity onPress={this.changeStyle} style={styles.button}>
86
+          <Text>change style</Text>
87
+        </TouchableOpacity>
64
         <TouchableOpacity onPress={this.changeScript} style={styles.button}>
88
         <TouchableOpacity onPress={this.changeScript} style={styles.button}>
65
           <Text>change script (have to change source to reload on android)</Text>
89
           <Text>change script (have to change source to reload on android)</Text>
66
         </TouchableOpacity>
90
         </TouchableOpacity>
67
-        <Text style={{ padding: 5 }}>{height}</Text>
91
+        <Text style={{ padding: 5 }}>
92
+          height: {size.height}, width: {size.width}
93
+        </Text>
68
       </ScrollView>
94
       </ScrollView>
69
     );
95
     );
70
   }
96
   }