Flex 設置WMODE 後滾輪失效的解決方法


1.問題產生

Flex 設置 wmode 屬性爲 opaque 或 transparent ,是爲了解決flash 對象遮蓋頁面元素的問題。而隨之而來產生了鼠標滾輪失效的問題,本人使用的Chrome瀏覽器,據說火狐也存在同樣問題。

2.解決方法

解決方法主要是通過actionscript 中 ExternalInterface 的兩個方法 addCallback 與 call 實現與瀏覽器 js 的鼠標事件的監聽交互來實現的。以下代碼來源於開源項目:flex-wmode-mousewheel-handler-example 和 EarthBrowser 。後經測試不兼容IE8,代碼中已修正。

ActionScript 代碼:

package com.adobe.utils.mousewheel
{
	import flash.display.InteractiveObject;
	import flash.display.Stage;
	import flash.events.MouseEvent;
	import flash.external.ExternalInterface;
	
	/**
	   full credit goes to: 
		http://blog.earthbrowser.com/2009/01/simple-solution-for-mousewheel-events.html
	*/
	public class MouseWheelEnabler
	{
		static private var initialised : Boolean = false;
		static private var currentItem : InteractiveObject;
		static private var browserMouseEvent : MouseEvent;

		public static function init( stage : Stage ) : void
		{
			if( !initialised )
			{
				initialised = true;
				registerListenerForMouseMove( stage );
				registerJS();
			}
		}
		
		private static function registerListenerForMouseMove( stage : Stage ) : void
		{
			stage.addEventListener
			(
				MouseEvent.MOUSE_MOVE, 
				function( e : MouseEvent ) : void
				{
					currentItem = InteractiveObject( e.target );
					browserMouseEvent = MouseEvent( e );
				}
			);
		}

		private static function registerJS() : void
		{
			if( ExternalInterface.available )
			{
				var id:String = 'eb_' + Math.floor(Math.random()*1000000);
				ExternalInterface.addCallback(id, function():void{});
				ExternalInterface.call(MouseWheelEnabler_JavaScript.CODE);
				ExternalInterface.call("eb.InitMacMouseWheel", id);
				ExternalInterface.addCallback('externalMouseEvent', handleExternalMouseEvent);	
			}
		}
	
		private static function handleExternalMouseEvent(delta:Number):void
		{
			if(currentItem && browserMouseEvent)
			{
				currentItem.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_WHEEL, true, false, 
					browserMouseEvent.localX, browserMouseEvent.localY, browserMouseEvent.relatedObject,
					browserMouseEvent.ctrlKey, browserMouseEvent.altKey, browserMouseEvent.shiftKey, 
					browserMouseEvent.buttonDown,int(delta)));
			}
		}
	}
}

JavaScript 代碼段,直接寫在ActionScript中,使用 ExternalInterface.call(MouseWheelEnabler_JavaScript.CODE); 調用。

class MouseWheelEnabler_JavaScript
{
	public static const CODE : XML = 
	<script><![CDATA[
		function()
		{
			// create unique namespace
			if(typeof eb == "undefined" || !eb)	
			{
				eb = {};
			}
			
			var userAgent = navigator.userAgent.toLowerCase();
			eb.platform = 
			{
				win:/win/.test(userAgent),
				mac:/mac/.test(userAgent)
			};
			
			eb.vars = {};
			
			eb.browser = 
			{
				version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1],
				safari: /webkit/.test(userAgent),
				opera: /opera/.test(userAgent),
				msie: /msie/.test(userAgent) && !/opera/.test(userAgent),
				mozilla: /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent),
				chrome: /chrome/.test(userAgent)
			};
			
			// find the function we added
			eb.findSwf = function(id) 
			{
				var objects = document.getElementsByTagName("object");
				for(var i = 0; i < objects.length; i++)
				{
					if(typeof objects[i][id] != "undefined")
					{
						return objects[i];
					}
				}
				
				var embeds = document.getElementsByTagName("embed");
				
				for(var j = 0; j < embeds.length; j++)
				{
					if(typeof embeds[j][id] != "undefined")
					{
						return embeds[j];
					}
				}
					
				return null;
			}
			
			eb.usingWmode = function( swf )
			{
				if( typeof swf.getAttribute == "undefined" )
				{
					return false;
				}
				
				var wmode = swf.getAttribute( "wmode" );
				eb.log( "trying getAttributes: " + wmode );
				if( typeof wmode == "undefined" )
				{
					return false;
				}
				
				eb.log( "wmode: " + wmode );
				return true;
			}
			
			eb.log = function( message ) 
			{
				if( typeof console != "undefined" )
				{
					console.log( message );
				}
				else
				{
					//alert( message );
				}
			}
			
			eb.shouldAddHandler = function( swf )
			{
				if( !swf )
				{
					return false;
				}

				if( eb.platform.mac )
				{
					return true;
				}
				
				var usingWmode = eb.usingWmode( swf );
//				if( !eb.browser.msie && usingWmode ) return true;
				if(usingWmode ) return true;////修復IE8滾輪失效的bug
				
				return false;
			}
			
			eb.InitMacMouseWheel = function(id) 
			{	
				var swf = eb.findSwf(id);
				var shouldAdd = eb.shouldAddHandler( swf );

				if( shouldAdd ) 
				{
					var mouseOver = false;

					/// Mouse move detection for mouse wheel support
					function _mousemove(event) 
					{
						mouseOver = event && event.target && (event.target == swf);
					}

					/// Mousewheel support
					var _mousewheel = function(event) 
					{
						if(mouseOver || (typeof mouseOver == 'undefined' && eb.browser.msie)) 
						{
							var delta = 0;
							if(event.wheelDelta)		
								delta = event.wheelDelta / (eb.browser.opera ? 12 : 120);
							else if(event.detail)		
								delta = -event.detail;
							if(event.preventDefault)	
								event.preventDefault();
							swf.externalMouseEvent(delta);
							return true;
						}
						return false;
					}
					
					// install mouse listeners
					if(typeof window.addEventListener != 'undefined') 
					{
						window.addEventListener('DOMMouseScroll', _mousewheel, false);
						window.addEventListener('DOMMouseMove', _mousemove, false);
					}
					else if(typeof window.attachEvent != 'undefined') //修復IE8滾輪失效的bug
					{
						document.attachEvent('onmousemove',_mousemove);
						document.attachEvent('onmousewheel',_mousewheel);
					}

					window.onmousewheel = document.onmousewheel = _mousewheel;
					window.onmousemove = document.onmousemove = _mousemove;
				}
			}	
		}
	]]></script>;
}

3.使用示例

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application  xmlns:mx="http://www.adobe.com/2006/mxml"  
        layout="absolute"  addedToStage="initMouseWheel()"> 
        <mx:Script> 
                <![CDATA[ 
                        import com.adobe.utils.mousewheel.MouseWheelEnabler; 
                        private function initMouseWheel() : void 
                        { 
                                MouseWheelEnabler.init( stage ); 
                        }                      
                ]]> 
        </mx:Script> 
</mx:Application>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章