Skip to content

无法触发web的鼠标按下移动事件 #868

@Gasang-Pon

Description

@Gasang-Pon

Affected version

0.24.13+1

Flutter versions

3.29.2

No same issues found.

  • Yes, I search all issues but not found.

Steps to Reproduce

加载并渲染HTML后,无法触发web的鼠标按下移动事件;

web部分已添加对应的事件

Image
webf-demo.mp4

Code example

Image

`WebF.fromControllerName(
controllerName: _controllerName,
loadingWidget: const shadcn.CustomButtonLoading(size: 24),
errorBuilder: (context, error) => Text('加载失败: $error'),
bundle: WebFBundle.fromUrl(bundleUrl),
createController: () => WebFController(
background: Colors.white,
viewportWidth: _viewportWidth,
viewportHeight: _viewportHeight,
onControllerInit: (c) async {
await c.view.evaluateJavaScripts('''
try {
if (typeof document === 'object') {
if (!document.implementation) {
document.implementation = {};
}
if (!document.implementation.createHTMLDocument) {
document.implementation.createHTMLDocument = function(title) {
// Create a dummy document-like object to satisfy jQuery's support check
// preventing it from wiping the real document.body
var dummyBody = document.createElement('div');
var dummyHead = document.createElement('div');
return {
body: dummyBody,
head: dummyHead,
createElement: function(tag) { return document.createElement(tag); },
title: title
};
};
}
}

                  // Location Polyfill - Force replacement of native location to avoid 'assets' scheme errors
                  try {
                     var fakeLocation = {
                        href: 'https://captcha.local/index.html',
                        origin: 'https://captcha.local',
                        protocol: 'https:',
                        host: 'captcha.local',
                        hostname: 'captcha.local',
                        port: '',
                        pathname: '/index.html',
                        search: '',
                        hash: '',
                        reload: function() {},
                        replace: function() {},
                        assign: function() {},
                        toString: function() { return this.href; }
                     };
                     
                     // Attempt to replace window.location
                     try {
                        Object.defineProperty(window, 'location', {
                           value: fakeLocation,
                           writable: true,
                           configurable: true
                        });
                     } catch(e1) {
                        console.log('Failed to replace window.location', e1);
                        // Fallback: try to override origin on the native object
                        try {
                            Object.defineProperty(window.location, 'origin', {
                              value: 'https://captcha.local',
                              writable: true,
                              configurable: true
                            });
                        } catch(e2) {
                            console.log('Failed to override location.origin', e2);
                        }
                     }
                  } catch (e) {
                    console.log('Location polyfill fatal error', e);
                  }

                  if (typeof alert === 'undefined') {
                    globalThis.alert = function(msg) { console.log('[alert]', msg); };
                  }
                  if (typeof globalThis.crypto === 'undefined') {
                    globalThis.crypto = {
                      getRandomValues: function(typedArray) {
                        for (var i = 0; i < typedArray.length; i++) {
                          typedArray[i] = Math.floor(Math.random() * 256);
                        }
                        return typedArray;
                      }
                    };
                  }
                    try {
                      if (typeof location === 'object') {
                         if (!location.origin) {
                            location.origin = 'https://captcha.local';
                         }
                      } else {
                        globalThis.location = {
                            href: 'https://captcha.local/index.html',
                            origin: 'https://captcha.local',
                            protocol: 'https:',
                            host: 'captcha.local',
                            hostname: 'captcha.local',
                            port: '',
                            pathname: '/index.html',
                            search: '',
                            hash: ''
                        };
                      }
                    } catch (e) {
                      console.log('location polyfill error', e);
                    }
                  if (typeof navigator === 'undefined') {
                    globalThis.navigator = {
                      userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
                      language: 'zh-CN',
                      platform: 'Win32',
                      appName: 'Netscape',
                      appVersion: '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
                    };
                  }
                  if (typeof screen === 'undefined') {
                    globalThis.screen = {
                      width: 1920,
                      height: 1080,
                      availWidth: 1920,
                      availHeight: 1040,
                      colorDepth: 24,
                      pixelDepth: 24
                    };
                  }
    
                  if (typeof requestAnimationFrame === 'undefined') {
                    globalThis.requestAnimationFrame = function(callback) {
                      return setTimeout(callback, 16);
                    };
                    globalThis.cancelAnimationFrame = function(id) {
                       clearTimeout(id);
                     };
                   }
                   // Force patch document.cookie to avoid native crash in CookieManager
                   try {
                     Object.defineProperty(document, 'cookie', {
                       get: function() { return ''; },
                       set: function(v) {},
                       configurable: true
                     });
                   } catch (e) {
                      console.log('cookie polyfill error', e);
                    }
                    
                    // getRootNode Polyfill for jQuery 3.x (WebF missing API)
                    try {
                       var Prototypes = [
                          window.Node, 
                          window.Element, 
                          window.HTMLElement, 
                          window.DocumentFragment,
                          window.Document
                       ];
                       
                       Prototypes.forEach(function(Proto) {
                          if (Proto && Proto.prototype && !Proto.prototype.getRootNode) {
                              Proto.prototype.getRootNode = function(opts) {
                                  var composed = opts && opts.composed;
                                  var node = this;
                                  while (node.parentNode) {
                                      node = node.parentNode;
                                  }
                                  return node;
                              };
                          }
                       });
                    } catch(e) {
                         console.log('getRootNode polyfill error', e);
                      }

                      // Mouse Event Polyfill for WebF (Dragging support) - Safe Implementation
                      try {
                         if (typeof MouseEvent === 'undefined') {
                           globalThis.MouseEvent = function(type, params) {
                             params = params || { bubbles: false, cancelable: false };
                             // Create a plain object that mimics a MouseEvent instead of calling document.createEvent
                             // calling document.createEvent('MouseEvent') and initMouseEvent might trigger native side effects causing the loop
                             this.type = type;
                             this.bubbles = params.bubbles;
                             this.cancelable = params.cancelable;
                             this.view = window;
                             this.detail = 0;
                             this.screenX = params.screenX || 0;
                             this.screenY = params.screenY || 0;
                             this.clientX = params.clientX || 0;
                             this.clientY = params.clientY || 0;
                             this.ctrlKey = false;
                             this.altKey = false;
                             this.shiftKey = false;
                             this.metaKey = false;
                             this.button = 0;
                             this.relatedTarget = null;
                           };
                           globalThis.MouseEvent.prototype = Event.prototype;
                         }
                      } catch (e) {
                         console.log('MouseEvent polyfill error', e);
                      }

                      // Storage Polyfill
                   if (typeof localStorage === 'undefined') {
                      var _store = {};
                      globalThis.localStorage = {
                         getItem: function(k) { return _store[k] || null; },
                         setItem: function(k, v) { _store[k] = String(v); },
                         removeItem: function(k) { delete _store[k]; },
                         clear: function() { _store = {}; },
                         key: function(i) { return Object.keys(_store)[i] || null; },
                         get length() { return Object.keys(_store).length; }
                      };
                   }
                   if (typeof sessionStorage === 'undefined') {
                      var _sessStore = {};
                      globalThis.sessionStorage = {
                         getItem: function(k) { return _sessStore[k] || null; },
                         setItem: function(k, v) { _sessStore[k] = String(v); },
                         removeItem: function(k) { delete _sessStore[k]; },
                         clear: function() { _sessStore = {}; },
                         key: function(i) { return Object.keys(_sessStore)[i] || null; },
                         get length() { return Object.keys(_sessStore).length; }
                      };
                   }
                   if (typeof document.referrer === 'undefined') {
                     Object.defineProperty(document, 'referrer', {
                       get: function() { return ''; }
                     });
                   }
                   if (typeof window.top === 'undefined') {
                     window.top = window;
                   }
                   if (typeof window.parent === 'undefined') {
                     window.parent = window;
                   }
                   if (typeof window.self === 'undefined') {
                     window.self = window;
                   }
                   if (typeof window.matchMedia === 'undefined') {
                     window.matchMedia = function(query) {
                       return {
                         matches: false,
                         media: query,
                         onchange: null,
                         addListener: function() {},
                         removeListener: function() {},
                         addEventListener: function() {},
                         removeEventListener: function() {},
                         dispatchEvent: function() { return false; },
                       };
                     };
                   }
                 } catch (e) {
                   console.log('polyfill error', e);
                 }
              ''');
            },
          ),
          forceLoad: true,
          setup: (controller) {
            controller.onJSError = (error) {
              print('🔴 JS Error: ${error} \nStack: ${error}');
            };

            controller.onDOMContentLoaded = (event) async {
              print('📄 DOM Content Loaded !!!');
              final data = CustomWebViewSliderCodeData(
                lang: ThemeConfigStore.to.appLangName,
                device: 'FLUTTER',
                codeType: 'SLIDER',
                AccessKey: AppEnvConfig.appAccessKey,
                AppEndKey: AppEnvConfig.appEndKey,
                IP: AppEnvConfig.apiBaseUrl,
                theme: theme.brightness == Brightness.light ? 'light' : 'dark',
              );
              final configJson = jsonEncode(data);
              final jsArg = jsonEncode(configJson);
              try {
                await controller.view.evaluateJavaScripts('initCofig($jsArg);');
                final element = controller.view.document.getElementsByTagName(['div']);
                print('element: ${element.toString()}');
              } catch (e) {
                print('Error executing initCofig: $e');
              }
            };
            
            controller.loadingState.onConstructor((event) {
                print('🏗️ Constructor at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onInit((event) {
                print('🚀 Initialize at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onPreload((event) {
                print('📦 Preload at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onResolveEntrypointStart((event) {
                print('🔍 Resolve Entrypoint Start at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onResolveEntrypointEnd((event) {
                print('✅ Resolve Entrypoint End at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onParseHTMLStart((event) {
                print('📄 Parse HTML Start at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onParseHTMLEnd((event) async {
                print('✅ Parse HTML End at ${event.elapsed.inMilliseconds}ms');
                
              });

              controller.loadingState.onScriptQueue((event) {
                print('📋 Script Queue at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onScriptLoadStart((event) {
                print('📥 Script Load Start at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onScriptLoadComplete((event) {
                print('✅ Script Load Complete at ${event.elapsed.inMilliseconds}ms ${event.parameters}');
              });

              controller.loadingState.onAttachToFlutter((event) {
                print('🔗 Attach to Flutter at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onScriptExecuteStart((event) {
                print('▶️ Script Execute Start at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onScriptExecuteComplete((event) {
                print('✅ Script Execute Complete at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onDOMContentLoaded((event) async {
                print('📄 DOM Content Loaded at ${event.elapsed.inMilliseconds}ms');
                
              });

              controller.loadingState.onWindowLoad((event) {
                print('🪟 Window Load at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onBuildRootView((event) {
                print('🏗️ Build Root View at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onFirstPaint((event) {
                print('🎨 First Paint (FP) at ${event.elapsed.inMilliseconds}ms');
              });

              controller.loadingState.onFirstContentfulPaint((event) {
                print('🖼️ First Contentful Paint (FCP) at ${event.elapsed.inMilliseconds}ms');
              });
          },
        ),
      `

Expected results

按下鼠标能正常触发移动事件

Actual results

没有任何响应

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions