瀏覽代碼

refactor index.ios.js with using postMessage

iou90 5 年之前
父節點
當前提交
5e8d98fade
共有 3 個文件被更改,包括 82 次插入85 次删除
  1. 32
    10
      autoHeightWebView/common.js
  2. 48
    73
      autoHeightWebView/index.ios.js
  3. 2
    2
      demo/config.js

+ 32
- 10
autoHeightWebView/common.js 查看文件

@@ -109,7 +109,10 @@ export function handleSizeUpdated(height, width, onSizeUpdated) {
109 109
 }
110 110
 
111 111
 export function isSizeChanged(height, oldHeight, width, oldWidth) {
112
-  return (height && height !== oldHeight) || (width && width !== oldWidth);
112
+  if (height == null || width == null) {
113
+    return false;
114
+  }
115
+  return height !== oldHeight || width !== oldWidth;
113 116
 }
114 117
 
115 118
 export const domMutationObserveScript = `
@@ -121,13 +124,32 @@ observer.observe(document, {
121 124
 });
122 125
 `;
123 126
 
124
-export const getCurrentSize = `
125
-function getSize(container) {
126
-  var height = container.offsetHeight || document.body.offsetHeight;
127
-  var width = container.offsetWidth || document.body.offsetWidth;
128
-  return {
129
-    height: height,
130
-    width: width
131
-  };
127
+export function updateSizeWithMessage(element) {
128
+  return `
129
+  var updateSizeInterval = null;
130
+  var height = 0;
131
+  function updateSize() {
132
+    if (!window.hasOwnProperty('ReactNativeWebView') || !window.ReactNativeWebView.hasOwnProperty('postMessage')) {
133
+      !updateSizeInterval && (updateSizeInterval = setInterval(updateSize, 200));
134
+      return;
135
+    }
136
+    height = ${element}.offsetHeight || window.innerHeight,
137
+    width = ${element}.offsetWidth || window.innerWidth;
138
+    window.ReactNativeWebView.postMessage(JSON.stringify({ width: width, height: height }));
139
+  }
140
+  `;
141
+}
142
+
143
+export function getStateFromProps(props, state) {
144
+  const { height: oldHeight, width: oldWidth } = state;
145
+  const height = props.style ? props.style.height : null;
146
+  const width = props.style ? props.style.width : null;
147
+  if (isSizeChanged(height, oldHeight, width, oldWidth)) {
148
+    return {
149
+      height: height || oldHeight,
150
+      width: width || oldWidth,
151
+      isSizeChanged: true
152
+    };
153
+  }
154
+  return null;
132 155
 }
133
-`;

+ 48
- 73
autoHeightWebView/index.ios.js 查看文件

@@ -17,7 +17,8 @@ import {
17 17
   isSizeChanged,
18 18
   handleSizeUpdated,
19 19
   domMutationObserveScript,
20
-  getCurrentSize
20
+  getStateFromProps,
21
+  updateSizeWithMessage
21 22
 } from './common.js';
22 23
 
23 24
 import momoize from './momoize';
@@ -61,17 +62,7 @@ export default class AutoHeightWebView extends PureComponent {
61 62
   getUpdatedState = momoize(setState, isEqual);
62 63
 
63 64
   static getDerivedStateFromProps(props, state) {
64
-    const { height: oldHeight, width: oldWidth } = state;
65
-    const height = props.style ? props.style.height : null;
66
-    const width = props.style ? props.style.width : null;
67
-    if (isSizeChanged(height, oldHeight, width, oldWidth)) {
68
-      return {
69
-        height: height || oldHeight,
70
-        width: width || oldWidth,
71
-        isSizeChanged: true
72
-      };
73
-    }
74
-    return null;
65
+    return getStateFromProps(props, state);
75 66
   }
76 67
 
77 68
   componentDidUpdate() {
@@ -92,16 +83,19 @@ export default class AutoHeightWebView extends PureComponent {
92 83
     }
93 84
   }
94 85
 
95
-  handleNavigationStateChange = navState => {
96
-    const { title } = navState;
97
-    const { onNavigationStateChange } = this.props;
98
-    if (!title) {
99
-      onNavigationStateChange && onNavigationStateChange(navState);
86
+  onMessage = event => {
87
+    if (!event.nativeEvent) {
100 88
       return;
101 89
     }
102
-    const [heightValue, widthValue] = title.split(',');
103
-    const width = Number(widthValue);
104
-    const height = Number(heightValue);
90
+    let data = {};
91
+    // Sometimes the message is invalid JSON, so we ignore that case
92
+    try {
93
+      data = JSON.parse(event.nativeEvent.data);
94
+    } catch (error) {
95
+      console.error(error);
96
+      return;
97
+    }
98
+    const { height, width } = data;
105 99
     const { height: oldHeight, width: oldWidth } = this.state;
106 100
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
107 101
       this.props.enableAnimation && this.opacityAnimatedValue.setValue(0);
@@ -111,7 +105,8 @@ export default class AutoHeightWebView extends PureComponent {
111 105
         width
112 106
       });
113 107
     }
114
-    onNavigationStateChange && onNavigationStateChange(navState);
108
+    const { onMessage } = this.props;
109
+    onMessage && onMessage(event);
115 110
   };
116 111
 
117 112
   stopLoading() {
@@ -128,7 +123,7 @@ export default class AutoHeightWebView extends PureComponent {
128 123
       decelerationRate,
129 124
       allowsInlineMediaPlayback,
130 125
       dataDetectorTypes,
131
-      onMessage,
126
+      onNavigationStateChange,
132 127
       onError,
133 128
       onLoad,
134 129
       onLoadStart,
@@ -161,7 +156,7 @@ export default class AutoHeightWebView extends PureComponent {
161 156
           dataDetectorTypes={dataDetectorTypes}
162 157
           originWhitelist={originWhitelist || ['*']}
163 158
           ref={this.webView}
164
-          onMessage={onMessage}
159
+          onMessage={this.onMessage}
165 160
           onError={onError}
166 161
           onLoad={onLoad}
167 162
           onLoadStart={onLoadStart}
@@ -171,7 +166,7 @@ export default class AutoHeightWebView extends PureComponent {
171 166
           scrollEnabled={!!scrollEnabled}
172 167
           injectedJavaScript={script}
173 168
           source={source}
174
-          onNavigationStateChange={this.handleNavigationStateChange}
169
+          onNavigationStateChange={onNavigationStateChange}
175 170
         />
176 171
       </Animated.View>
177 172
     );
@@ -190,60 +185,40 @@ const styles = StyleSheet.create({
190 185
 
191 186
 // add viewport setting to meta for WKWebView
192 187
 const commonScript = `
193
-    var meta = document.createElement('meta'); 
194
-    meta.setAttribute('name', 'viewport'); 
195
-    meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);
196
-    updateSize();
197
-    window.addEventListener('load', updateSize);
198
-    window.addEventListener('resize', updateSize);
199
-    `;
188
+var meta = document.createElement('meta'); 
189
+meta.setAttribute('name', 'viewport'); 
190
+meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);
191
+updateSize();
192
+window.addEventListener('load', updateSize);
193
+window.addEventListener('resize', updateSize);
194
+`;
200 195
 
201 196
 function getBaseScript(style) {
202 197
   return `
203
-    ;
204
-    ${getCurrentSize}
205
-    (function () {
206
-      if (!document.getElementById("rnahw-wrapper")) { 
207
-          var height = 0;
208
-          var width = ${getWidth(style)};
209
-          var wrapper = document.createElement('div');
210
-          wrapper.id = 'rnahw-wrapper';
211
-          while (document.body.firstChild instanceof Node) {
212
-              wrapper.appendChild(document.body.firstChild);
213
-          }
214
-          document.body.appendChild(wrapper);
215
-          function updateSize() {
216
-            if (document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
217
-               var size = getSize(wrapper);
218
-               height = size.height;
219
-               width = size.width;
220
-               document.title = height.toString() + ',' + width.toString();
221
-            }
222
-          }
223
-        ${commonScript}
224
-        ${domMutationObserveScript}
225
-        }
226
-    } ());
227
-    `;
198
+  ;
199
+  (function () {
200
+    if (!document.getElementById("rnahw-wrapper")) {
201
+      var wrapper = document.createElement('div');
202
+      wrapper.id = 'rnahw-wrapper';
203
+      wrapper.appendChild(document.body.firstChild);
204
+      document.body.appendChild(wrapper);
205
+    }
206
+    var width = ${getWidth(style)};
207
+    ${updateSizeWithMessage('wrapper')}
208
+    ${commonScript}
209
+    ${domMutationObserveScript}
210
+  } ());
211
+  `;
228 212
 }
229 213
 
230 214
 function getIframeBaseScript(style) {
231 215
   return `
232
-    ;
233
-    ${getCurrentSize}
234
-    (function () {
235
-        var height = 0;
236
-        var width = ${getWidth(style)};
237
-        function updateSize() {
238
-            if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
239
-                var size = getSize(document.body.firstChild);
240
-                height = size.height;
241
-                width = size.width;
242
-                document.title = height.toString() + ',' + width.toString();
243
-            }
244
-        }
245
-        ${commonScript}
246
-        ${domMutationObserveScript}
247
-    } ());
248
-    `;
216
+  ;
217
+  (function () {
218
+    var width = ${getWidth(style)};
219
+    ${updateSizeWithMessage('document.body.firstChild')}
220
+    ${commonScript}
221
+    ${domMutationObserveScript}
222
+  } ());
223
+  `;
249 224
 }

+ 2
- 2
demo/config.js 查看文件

@@ -28,12 +28,12 @@ const inlineBodyStyle = `
28 28
 
29 29
 //https://medium.com/@elhardoum/opening-external-links-in-browser-in-react-native-webview-18fe6a66312a
30 30
 const autoDetectLinkScript = `
31
-!function(){
31
+(function(){
32 32
   function isUrl(str){
33 33
     return str.startsWith('http');
34 34
   }
35 35
   var e=function(e,n,t){if(n=n.replace(/^on/g,""),"addEventListener"in window)e.addEventListener(n,t,!1);else if("attachEvent"in window)e.attachEvent("on"+n,t);else{var o=e["on"+n];e["on"+n]=o?function(e){o(e),t(e)}:t}return e},n=document.querySelectorAll("a[href]");if(n)for(var t in n)n.hasOwnProperty(t)&&e(n[t],"onclick",function(e){!isUrl(this.href)||(e.preventDefault(),window.postMessage(JSON.stringify({url:this.href})))})
36
-}();
36
+}());
37 37
 `;
38 38
 
39 39
 const autoHeightScript = `