iou90 6 年前
父节点
当前提交
8d0f99f8eb
共有 1 个文件被更改,包括 127 次插入104 次删除
  1. 127
    104
      autoHeightWebView/index.android.js

+ 127
- 104
autoHeightWebView/index.android.js 查看文件

@@ -11,14 +11,22 @@ import {
11 11
   Platform,
12 12
   UIManager,
13 13
   ViewPropTypes,
14
-  WebView
14
+  WebView,
15
+  View
15 16
 } from 'react-native';
16 17
 
17 18
 import PropTypes from 'prop-types';
18 19
 
19
-import Immutable from 'immutable';
20
-
21
-import { handleSizeUpdated, getWidth, getScript, domMutationObserveScript, getCurrentSize } from './common.js';
20
+import {
21
+  isEqual,
22
+  setState,
23
+  isSizeChanged,
24
+  handleSizeUpdated,
25
+  getWidth,
26
+  getScript,
27
+  domMutationObserveScript,
28
+  getCurrentSize
29
+} from './common.js';
22 30
 
23 31
 const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', AutoHeightWebView, {
24 32
   nativeOnly: {
@@ -31,6 +39,12 @@ const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', Auto
31 39
   }
32 40
 });
33 41
 
42
+import momoize from './momoize';
43
+
44
+const baseUrl = 'file:///android_asset/web/';
45
+
46
+const getUpdatedState = momoize(setState, isEqual);
47
+
34 48
 export default class AutoHeightWebView extends PureComponent {
35 49
   static propTypes = {
36 50
     onMessage: PropTypes.func,
@@ -75,15 +89,16 @@ export default class AutoHeightWebView extends PureComponent {
75 89
 
76 90
   constructor(props) {
77 91
     super(props);
78
-    const { enableAnimation, style } = props;
92
+    const { enableAnimation, style, source, enableBaseUrl } = props;
79 93
     enableAnimation && (this.opacityAnimatedValue = new Animated.Value(0));
80 94
     isBelowKitKat && DeviceEventEmitter.addListener('webViewBridgeMessage', this.listenWebViewBridgeMessage);
81 95
     this.state = {
82
-      isChangingSource: false,
96
+      isSizeChanged: false,
97
+      isSizeMayChange: false,
83 98
       height: 0,
84
-      heightOffset: 0,
85 99
       width: getWidth(style),
86
-      script: getScript(props, getBaseScript)
100
+      script: getScript(props, getBaseScript),
101
+      source: enableBaseUrl ? Object.assign({}, source, { baseUrl }) : source
87 102
     };
88 103
   }
89 104
 
@@ -91,25 +106,50 @@ export default class AutoHeightWebView extends PureComponent {
91 106
     this.startInterval();
92 107
   }
93 108
 
94
-  UNSAFE_componentWillReceiveProps(nextProps) {
95
-    // injectedJavaScript only works when webView reload (source changed)
96
-    if (Immutable.is(Immutable.fromJS(this.props.source), Immutable.fromJS(nextProps.source))) {
97
-      return;
98
-    } else {
99
-      this.setState(
100
-        {
101
-          isChangingSource: true,
102
-          height: 0,
103
-          heightOffset: 0,
104
-          width: 0
105
-        },
106
-        () => {
107
-          this.startInterval();
108
-          this.setState({ isChangingSource: false });
109
-        }
110
-      );
109
+  static getDerivedStateFromProps(props, state) {
110
+    const { height: oldHeight, width: oldWidth, source: prevSource, script: prevScript } = state;
111
+    const { style, enableBaseUrl } = props;
112
+    const { source, script } = getUpdatedState(props, enableBaseUrl ? baseUrl : null, getBaseScript);
113
+    const height = style ? style.height : null;
114
+    const width = style ? style.width : null;
115
+    // if (source !== prevSource || script !== prevScript) {
116
+    //   console.log(1)
117
+    //   return {
118
+    //     source,
119
+    //     script,
120
+    //     isSizeMayChange: true
121
+    //   };
122
+    // }
123
+    if (isSizeChanged(height, oldHeight, width, oldWidth)) {
124
+      return {
125
+        height,
126
+        width,
127
+        isSizeChanged: true
128
+      };
129
+    }
130
+    return null;
131
+  }
132
+
133
+  componentDidUpdate() {
134
+    const { height, width, isSizeChanged, isSizeMayChange } = this.state;
135
+    if (isSizeMayChange) {
136
+      this.startInterval();
137
+      this.setState({ isSizeMayChange: false });
138
+    }
139
+    if (isSizeChanged) {
140
+      const { enableAnimation, animationDuration, onSizeUpdated } = this.props;
141
+      if (enableAnimation) {
142
+        Animated.timing(this.opacityAnimatedValue, {
143
+          toValue: 1,
144
+          duration: animationDuration
145
+        }).start(() => {
146
+          handleSizeUpdated(height, width, onSizeUpdated);
147
+        });
148
+      } else {
149
+        handleSizeUpdated(height, width, onSizeUpdated);
150
+      }
151
+      this.setState({ isSizeChanged: false });
111 152
     }
112
-    this.setState({ script: getScript(nextProps, getBaseScript) });
113 153
   }
114 154
 
115 155
   componentWillUnmount() {
@@ -152,32 +192,19 @@ export default class AutoHeightWebView extends PureComponent {
152 192
   }
153 193
 
154 194
   onMessage = e => {
155
-    console.log(e)
195
+    if (!e.nativeEvent) {
196
+      return;
197
+    }
156 198
     const { height, width } = JSON.parse(isBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
157 199
     const { height: oldHeight, width: oldWidth } = this.state;
158
-    if ((height && height !== oldHeight) || (width && width !== oldWidth)) {
159
-      const { enableAnimation, animationDuration, heightOffset, onSizeUpdated } = this.props;
160
-      enableAnimation && this.opacityAnimatedValue.setValue(0);
200
+    if (isSizeChanged(height, oldHeight, width, oldWidth)) {
201
+      this.props.enableAnimation && this.opacityAnimatedValue.setValue(0);
161 202
       this.stopInterval();
162
-      this.setState(
163
-        {
164
-          heightOffset,
165
-          height,
166
-          width
167
-        },
168
-        () => {
169
-          if (enableAnimation) {
170
-            Animated.timing(this.opacityAnimatedValue, {
171
-              toValue: 1,
172
-              duration: animationDuration
173
-            }).start(() => {
174
-              handleSizeUpdated(height, width, onSizeUpdated);
175
-            });
176
-          } else {
177
-            handleSizeUpdated(height, width, onSizeUpdated);
178
-          }
179
-        }
180
-      );
203
+      this.setState({
204
+        isSizeChanged: true,
205
+        height,
206
+        width
207
+      });
181 208
     }
182 209
     const { onMessage } = this.props;
183 210
     onMessage && onMessage(e);
@@ -201,8 +228,6 @@ export default class AutoHeightWebView extends PureComponent {
201 228
     onLoadEnd && onLoadEnd(event);
202 229
   };
203 230
 
204
-  getWebView = webView => (this.webView = webView);
205
-
206 231
   stopLoading() {
207 232
     UIManager.dispatchViewManagerCommand(
208 233
       findNodeHandle(this.webView),
@@ -211,47 +236,41 @@ export default class AutoHeightWebView extends PureComponent {
211 236
     );
212 237
   }
213 238
 
239
+  getWebView = webView => (this.webView = webView);
240
+
214 241
   render() {
215
-    const { height, width, script, isChangingSource, heightOffset } = this.state;
216
-    const { scalesPageToFit, enableAnimation, source, style, enableBaseUrl, scrollEnabled } = this.props;
217
-    let webViewSource = source;
218
-    if (enableBaseUrl) {
219
-      webViewSource = Object.assign({}, source, {
220
-        baseUrl: 'file:///android_asset/web/'
221
-      });
222
-    }
242
+    const { height, width, script, source } = this.state;
243
+    const { scalesPageToFit, style, scrollEnabled, heightOffset } = this.props;
223 244
     return (
224
-      <Animated.View
245
+      <View
225 246
         style={[
226 247
           styles.container,
227 248
           {
228
-            opacity: enableAnimation ? this.opacityAnimatedValue : 1,
229
-            height: height + heightOffset,
249
+            opacity: 1,
250
+            height: height ? height + heightOffset : 0,
230 251
             width: width
231 252
           },
232 253
           style
233 254
         ]}
234 255
       >
235
-        {isChangingSource ? null : (
236
-          <RCTAutoHeightWebView
237
-            onLoadingStart={this.onLoadingStart}
238
-            onLoadingFinish={this.onLoadingFinish}
239
-            onLoadingError={this.onLoadingError}
240
-            originWhitelist={['.*']}
241
-            ref={this.getWebView}
242
-            style={styles.webView}
243
-            javaScriptEnabled={true}
244
-            injectedJavaScript={script}
245
-            scalesPageToFit={scalesPageToFit}
246
-            scrollEnabled={!!scrollEnabled}
247
-            source={webViewSource}
248
-            onMessage={this.onMessage}
249
-            messagingEnabled={true}
250
-            // below kitkat
251
-            onChange={this.onMessage}
252
-          />
253
-        )}
254
-      </Animated.View>
256
+        <RCTAutoHeightWebView
257
+          onLoadingStart={this.onLoadingStart}
258
+          onLoadingFinish={this.onLoadingFinish}
259
+          onLoadingError={this.onLoadingError}
260
+          originWhitelist={['.*']}
261
+          ref={this.getWebView}
262
+          style={styles.webView}
263
+          javaScriptEnabled={true}
264
+          injectedJavaScript={script}
265
+          scalesPageToFit={scalesPageToFit}
266
+          scrollEnabled={!!scrollEnabled}
267
+          source={source}
268
+          onMessage={this.onMessage}
269
+          messagingEnabled={true}
270
+          // below kitkat
271
+          onChange={this.onMessage}
272
+        />
273
+      </View>
255 274
     );
256 275
   }
257 276
 }
@@ -268,20 +287,8 @@ const styles = StyleSheet.create({
268 287
   }
269 288
 });
270 289
 
271
-const updateSize = `
272
-  function updateSize() {
273
-    if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
274
-      var size = getSize(document.body.firstChild); 
275
-      height = size.height;
276
-      width = size.width;
277
-      AutoHeightWebView.send(JSON.stringify({ width, height }));
278
-    }
279
-  }
280
-`
281
-
282 290
 const commonScript = `
283 291
     ${getCurrentSize}
284
-    ${updateSize}
285 292
     var wrapper = document.createElement('div');
286 293
     wrapper.id = 'wrapper';
287 294
     while (document.body.firstChild instanceof Node) {
@@ -293,26 +300,42 @@ const getBaseScript = isBelowKitKat
293 300
   ? function(style) {
294 301
       return `
295 302
     ; 
303
+    ${commonScript}
296 304
     var height = 0;
297 305
     var width = ${getWidth(style)};
306
+    function updateSize() {
307
+      if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
308
+        var size = getSize(document.body.firstChild); 
309
+        height = size.height;
310
+        width = size.width;
311
+        AutoHeightWebView.send(JSON.stringify({ width, height }));
312
+      }
313
+    }
298 314
     (function () {
299
-    ${commonScript}
300
-    document.body.appendChild(wrapper);
301
-    AutoHeightWebView.onMessage = updateSize;
302
-    ${domMutationObserveScript}
303
-} ());
315
+      document.body.appendChild(wrapper);
316
+      AutoHeightWebView.onMessage = updateSize;
317
+      ${domMutationObserveScript}
318
+    } ());
304 319
   `;
305 320
     }
306 321
   : function(style) {
307 322
       return `
308 323
     ; 
324
+    ${commonScript}
309 325
     var height = 0;
310 326
     var width = ${getWidth(style)};
327
+    function updateSize() {
328
+      if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
329
+        var size = getSize(document.body.firstChild); 
330
+        height = size.height;
331
+        width = size.width;
332
+        window.postMessage(JSON.stringify({ width, height }));
333
+      }
334
+    }
311 335
     (function () {
312
-    ${commonScript}
313
-    document.body.appendChild(wrapper);
314
-    document.addEventListener('message', updateSize);
315
-    ${domMutationObserveScript}
316
-} ());
336
+      document.body.appendChild(wrapper);
337
+      document.addEventListener('message', updateSize);
338
+      ${domMutationObserveScript}
339
+    } ());
317 340
   `;
318 341
     };