精华内容
下载资源
问答
  • EventListener

    2017-06-09 23:53:45
    EventListener listener = go.GetComponent<EventListener>(); if (listener == null) listener = go.AddComponent<EventListener>(); return listener; } public static void SetFocus(GameObject go) { ...

    类使用方式:

    可以方便的为UGUI对象批量添加事件

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class Test : MonoBehaviour {
    
        public Image []images;
    
        private void Awake(){
            foreach(var image in images){
                EventListener.Get(image.gameObject).onClick += e=>{
                Debug.Log(image.gameObject);
                };
            }
        }
    }

    using UnityEngine;
    using UnityEngine.EventSystems;
    using System;
    
    public class EventListener : 
    MonoBehaviour,
    IPointerClickHandler,
    IPointerDownHandler,
    IPointerUpHandler,
    IPointerEnterHandler,
    IPointerExitHandler,
    IInitializePotentialDragHandler,
    IBeginDragHandler,
    IEndDragHandler,
    IDragHandler,
    IDropHandler,
    IScrollHandler,
    ISelectHandler,
    IUpdateSelectedHandler,
    IDeselectHandler,
    IMoveHandler,
    ISubmitHandler,
    ICancelHandler
    {
        public Action<PointerEventData> onClick;
        public Action<PointerEventData> onDoubleClick;
        public Action<PointerEventData> onMouseUp;
        public Action<PointerEventData> onMouseDown;
        public Action<PointerEventData> onEnter;
        public Action<PointerEventData> onExit;
        public Action<PointerEventData> onInitializePotentialDrag;
        public Action<PointerEventData> onBeginDrag;
        public Action<PointerEventData> onDrop;
        public Action<PointerEventData> onDrag;
        public Action<PointerEventData> onEndDrag;
        public Action<PointerEventData> onScroll;
        public Action<BaseEventData> onSelect;
        public Action<BaseEventData> onUpdateSelected;
        public Action<BaseEventData> onSubmit;
        public Action<BaseEventData> onCancel;
        public Action<AxisEventData> onMove;
        public Action<BaseEventData> onDeselect;
    
        public static EventListener Get(GameObject go)
        {
            EventListener listener = go.GetComponent<EventListener>();
            if (listener == null) listener = go.AddComponent<EventListener>();
            return listener;
        }
    
        public static void SetFocus(GameObject go)
        {
            EventSystem.current.SetSelectedGameObject(go);
        }
    
        void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
        {
            SetFocus(gameObject);
            if(eventData.clickCount == 1)
            {
                if (onClick != null) onClick(eventData);
            }
            else if(eventData.clickCount == 2)
            {
                if (onDoubleClick != null) onDoubleClick(eventData);
            }
        }
    
        void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
        {
            if (onMouseUp != null) onMouseUp(eventData);
        }
    
        void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
        {
            SetFocus(gameObject);
            if (onMouseDown != null) onMouseDown(eventData);
        }
    
        void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
        {
            if (onEnter != null)
                onEnter(eventData);
        }
    
        void IPointerExitHandler.OnPointerExit(PointerEventData eventData)
        {
            if (onExit != null)
                onExit(eventData);
        }
    
        void IInitializePotentialDragHandler.OnInitializePotentialDrag(PointerEventData eventData)
        {
            SetFocus(gameObject);
            if (onInitializePotentialDrag != null)
                onInitializePotentialDrag(eventData);
        }
    
        void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
        {
            if (onBeginDrag != null)
                onBeginDrag(eventData);
        }
    
        void IDragHandler.OnDrag(PointerEventData eventData)
        {
            if (onDrag != null)
                onDrag(eventData);
        }
    
        void IDropHandler.OnDrop(PointerEventData eventData)
        {
            if (onDrop != null)
                onDrop(eventData);
        }
    
        void IEndDragHandler.OnEndDrag(PointerEventData eventData)
        {
            SetFocus(gameObject);
            if (onEndDrag != null)
                onEndDrag(eventData);
        }
    
        void IScrollHandler.OnScroll(PointerEventData eventData)
        {
            if (onScroll != null)
                onScroll(eventData);
        }
    
        void ISelectHandler.OnSelect(BaseEventData eventData)
        {
            if (onSelect != null)
                onSelect(eventData);
        }
    
        void IUpdateSelectedHandler.OnUpdateSelected(BaseEventData eventData)
        {
            if (onUpdateSelected != null)
                onUpdateSelected(eventData);
        }
    
        void ISubmitHandler.OnSubmit(BaseEventData eventData)
        {
            if (onSubmit != null)
                onSubmit(eventData);
        }
    
        void ICancelHandler.OnCancel(BaseEventData eventData)
        {
            if (onCancel != null)
                onCancel(eventData);
        }
    
        void IMoveHandler.OnMove(AxisEventData eventData)
        {
            if (onMove != null)
                onMove(eventData);
        }
    
        void IDeselectHandler.OnDeselect(BaseEventData eventData)
        {
            if (onDeselect != null)
                onDeselect(eventData);
        }
    }



    展开全文
  • @EventListener注解使用及源码解析

    万次阅读 2019-07-29 15:54:20
    一、简介 @EventListener是一种事件驱动编程在spring4.2的时候开始有的,早期可以实现ApplicationListener接口, 想了解下ApplicationListener的可以参考下这篇文章...内部实现原...
    一、简介
    • @EventListener是一种事件驱动编程在spring4.2的时候开始有的,早期可以实现ApplicationListener接口, 想了解下ApplicationListener的可以参考下这篇文章https://blog.csdn.net/baidu_19473529/article/details/86683365Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
    • 比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。
    二、使用@EventListener注解
    • 建立事件对象,当调用publishEvent方法是会通过这个bean对象找对应事件的监听。AddDataEvent.java
    package com.rw.article.pay.event.bean;
    
    import org.springframework.context.ApplicationEvent;
    
    /**
     * @author Zhou Zhong Qing
     * @Title: ${file_name}
     * @Package ${package_name}
     * @Description: 新增mongodb数据事件
     * @date 2018/10/18 16:26
     */
    public class AddDataEvent extends ApplicationEvent {
    
        public AddDataEvent(Object source) {
            super(source);
        }
        public AddDataEvent(Object source, Class clz, Object data) {
            super(source);
            this.clz = clz;
            this.data = data;
        }
    
        public AddDataEvent(Object source, Class clz, Object data, String modelName, String userAgent) {
            super(source);
            this.clz = clz;
            this.data = data;
            this.modelName = modelName;
            this.userAgent = userAgent;
        }
    
    
    
        /** 要更新的表对象 **/
        private Class clz;
    
        /** 操作的数据**/
        private Object data;
    
    
        /** 模块名称**/
        private String modelName;
    
        /** 浏览器标识 **/
        private String userAgent;
    
    
        public Class getClz() {
            return clz;
        }
    
        public void setClz(Class clz) {
            this.clz = clz;
        }
    
        public Object getData() {
            return data;
        }
    
        public void setData(Object data) {
            this.data = data;
        }
    
        public String getModelName() {
            return modelName;
        }
    
        public void setModelName(String modelName) {
            this.modelName = modelName;
        }
    
        public String getUserAgent() {
            return userAgent;
        }
    
        public void setUserAgent(String userAgent) {
            this.userAgent = userAgent;
        }
    }
    
    
    • 对应的监听AddDataEventListener .java
    package com.rw.article.pay.event.listener;
    import com.alibaba.fastjson.JSON;
    import com.rw.article.pay.event.bean.AddDataEvent;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import org.springframework.context.event.EventListener;
    import org.springframework.stereotype.Component;
    
    /**
     * @author Zhou Zhong Qing
     * @Title: ${file_name}
     * @Package ${package_name}
     * @Description: 新增数据的事件监听
     * @date 2018/10/18 16:29
     */
    @Component
    public class AddDataEventListener {
        private static Logger log = LoggerFactory.getLogger(AddDataEventListener.class);
    
        /*
        * 在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了BeanDefinition 对应的是EventListenerMethodProcessor对象   , AnnotationConfigUtils在AnnotationConfigServletWebServerApplicationContext构造方法里被加载
        * */
    
     	/**
    	 * DefaultListableBeanFactory#中preInstantiateSingletons -> (beanName为org.springframework.context.event.internalEventListenerProcessor时得到EventListenerMethodProcessor)EventListenerMethodProcessor#afterSingletonsInstantiated this.processBean(factories, beanName, type)
    	 * 然后把要执行的方法封装为ApplicationListenerMethodAdapter -> 添加到listener中 AbstractApplicationEventMulticaster#addApplicationListener
    	 * */
     	// 该方法在 ApplicationListenerMethodAdapter 利用反射执行
        /**
         * 处理新增数据的事件
         **/
        @EventListener
        public void handleAddEvent(AddDataEvent event) {
            log.info("发布的data为:{}  ", JSON.toJSONString(event));
            
        }
    }
    
    • 建立测试类
    package com.rw.article.pay.action;
    
    import com.rw.article.pay.event.bean.AddDataEvent;
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.annotation.Resource;
    
    /**
     * @author Zhou Zhong Qing
     * @Title: ${file_name}
     * @Package ${package_name}
     * @Description: 测试的controller
     * @date 2019/7/24 17:13
     */
    @Controller
    @RequestMapping("/test")
    public class TestController {
    
    
       @Resource
       private ApplicationContext applicationContext;
    
    
       @ResponseBody
       @RequestMapping("/testListener")
       public String testListener(){
          applicationContext.publishEvent(new AddDataEvent(this,TestController.class,"test"));
          return "success";
       }
    }
    
    • 结果是能够监听到的
      在这里插入图片描述
    • 如果要使用异步加上@EnableAsync注解,方法上加@Async注解,如下spring boot项目配置
    @SpringBootApplication
    @EnableAsync
    public class XApplication{
        public static void main(String[] args) {
            ConfigurableApplicationContext run = new SpringApplicationBuilder(XApplication.class).web(true).run(args);
            run.publishEvent("test");
        }
    }
    
        @Async
        @EventListener
        public void test(String wrapped){
            System.out.println("当前线程 "+Thread.currentThread().getName());
            System.out.println(wrapped.getMchId());
        }
    
    • 还可以配置线程池taskExecutor
    @Configuration
    public class GenericConfiguration {
    
        @Bean
        public Executor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            //核心线程数:线程池创建时候初始化的线程数
            //最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
            //缓冲队列:用来缓冲执行任务的队列
            //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
            //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
            //线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
            executor.setCorePoolSize(5);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(20);
            executor.setKeepAliveSeconds(60);
            executor.setThreadNamePrefix("taskExecutor-");
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            return executor;
        }
    }
    
    
    三、源码解析
    • 原理还得从org.springframework.context.event.internalEventListenerProcessor
      说起。
    • 在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了BeanDefinition 对应的是EventListenerMethodProcessor对象 , 而AnnotationConfigUtils是在AnnotationConfigServletWebServerApplicationContext构造方法里被加载。这里要提一下AnnotationConfigServletWebServerApplicationContext,他是spring boot启动入口的重要类(我这里用的是spring boot所以是这个类),可以相当于以前用xml的ClassPathXmlApplicationContext。
     public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
          "org.springframework.context.event.internalEventListenerProcessor";
    
    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    			BeanDefinitionRegistry registry, @Nullable Object source) {
    
    		 ................... 
    
    		// 注册EventListenerMethodProcessor对象
    		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    		}
    		...........................
    
    		return beanDefs;
    	}
    
    • 注册的EventListenerMethodProcessor对象会在初始化非懒加载对象的时候运行它的afterSingletonsInstantiated方法。
      AbstractApplicationContext#finishBeanFactoryInitialization
     protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
     
       ............. 
       // 初始化非懒加载对象
       beanFactory.preInstantiateSingletons();
    }
    
    • DefaultListableBeanFactory#preInstantiateSingletons
     @Override
    public void preInstantiateSingletons() throws BeansException {
        ..................
    
       // 触发所有适用bean的初始化后回调 主要是afterSingletonsInstantiated方法
       for (String beanName : beanNames) {
    //如果beanName传入org.springframework.context.event.internalEventListenerProcessor 因为已经上面代码已经初始化,将从缓存中得到一个EventListenerMethodProcessor对象
          Object singletonInstance = getSingleton(beanName);
          if (singletonInstance instanceof SmartInitializingSingleton) {
             final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
             if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                   smartSingleton.afterSingletonsInstantiated();
                   return null;
                }, getAccessControlContext());
             }
             else {
    // 调用其afterSingletonsInstantiated方法
                smartSingleton.afterSingletonsInstantiated();
             }
          }
       }
    }
    
    • EventListenerMethodProcessor#afterSingletonsInstantiated
     @Override
    public void afterSingletonsInstantiated() {
       List<EventListenerFactory> factories = getEventListenerFactories();
       ConfigurableApplicationContext context = getApplicationContext();
       String[] beanNames = context.getBeanNamesForType(Object.class);
       for (String beanName : beanNames) {
          if (!ScopedProxyUtils.isScopedTarget(beanName)) {
             Class<?> type = null;
             try {
                type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName);
             }
             catch (Throwable ex) {
                // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                   logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                }
             }
             if (type != null) {
                if (ScopedObject.class.isAssignableFrom(type)) {
                   try {
                      Class<?> targetClass = AutoProxyUtils.determineTargetClass(
                            context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName));
                      if (targetClass != null) {
                         type = targetClass;
                      }
                   }
                   catch (Throwable ex) {
                      // An invalid scoped proxy arrangement - let's ignore it.
                      if (logger.isDebugEnabled()) {
                         logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
                      }
                   }
                }
                try {
    		// 重点是这个方法 处理bean
                   processBean(factories, beanName, type);
                }
                catch (Throwable ex) {
                   throw new BeanInitializationException("Failed to process @EventListener " +
                         "annotation on bean with name '" + beanName + "'", ex);
                }
             }
          }
       }
    }
    
    • EventListenerMethodProcessor#processBean;这里有一个重要的类就是ApplicationListenerMethodAdapter,spring把加入了@EventListener注解的方法封装进ApplicationListenerMethodAdapter对象里,然后我们publishEvent方法是,其实是调用的对应的ApplicationListenerMethodAdapter,然后里面是执行这个方法,这里可以看下ApplicationListenerMethodAdapter类的属性。
    public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
    
       protected final Log logger = LogFactory.getLog(getClass());
    
       private final String beanName;
    
       private final Method method;
    
       private final Method targetMethod;
    
       private final AnnotatedElementKey methodKey;
    
       private final List<ResolvableType> declaredEventTypes;
    
       @Nullable
       private final String condition;
    
       private final int order;
    
       @Nullable
       private ApplicationContext applicationContext;
    
       @Nullable
       private EventExpressionEvaluator evaluator;
    	..................................
    }
    
    protected void processBean(
          final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
    
       if (!this.nonAnnotatedClasses.contains(targetType)) {
          Map<Method, EventListener> annotatedMethods = null;
          try {
             // 拿到使用了@EventListener注解的方法
             annotatedMethods = MethodIntrospector.selectMethods(targetType,
                   (MethodIntrospector.MetadataLookup<EventListener>) method ->
                         AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
          }
          catch (Throwable ex) {
             // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
             if (logger.isDebugEnabled()) {
                logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
             }
          }
          if (CollectionUtils.isEmpty(annotatedMethods)) {
             this.nonAnnotatedClasses.add(targetType);
             if (logger.isTraceEnabled()) {
                logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
             }
          }
          else {
             // Non-empty set of methods
             ConfigurableApplicationContext context = getApplicationContext();
             for (Method method : annotatedMethods.keySet()) {
                for (EventListenerFactory factory : factories) {
                   // 判断是否支持该方法  这里用的DefaultEventListenerFactory spring5.0.8 写死的返回true
                   if (factory.supportsMethod(method)) {
                      //选择方法  beanName 这里是AddDataEventListener的beanName 默认是addDataEventListener
                      Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                      // 这里是创建一个ApplicationListenerMethodAdapter对象
                      ApplicationListener<?> applicationListener =
                            factory.createApplicationListener(beanName, targetType, methodToUse);
                      if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                         // 如果是ApplicationListenerMethodAdapter对象 就把context和evaluator传进去
                         ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                      }
    
                      // 添加到ApplicationListener事件Set集合中去
                      context.addApplicationListener(applicationListener);
                      break;
                   }
                }
             }
             if (logger.isDebugEnabled()) {
                logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                      beanName + "': " + annotatedMethods);
             }
          }
       }
    }
    
    • 后面就是触发事件监听了AbstractApplicationContext#publishEvent
     @Override
    public void publishEvent(ApplicationEvent event) {
       publishEvent(event, null);
    }
    
    
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    	 
    			..............................
    		// Multicast right now if possible - or lazily once the multicaster is initialized
    		if (this.earlyApplicationEvents != null) {
    			this.earlyApplicationEvents.add(applicationEvent);
    		}
    		else {
    		    // 进入multicastEvent
    			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    		}
    
    		// Publish event via parent context as well...
    		if (this.parent != null) {
    			if (this.parent instanceof AbstractApplicationContext) {
    				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
    			}
    			else {
    				this.parent.publishEvent(event);
    			}
    		}
    	}
    
    
    • SimpleApplicationEventMulticaster#multicastEvent->invokeListener->doInvokeListener
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
       try {
          listener.onApplicationEvent(event);
       }
       catch (ClassCastException ex) {
          String msg = ex.getMessage();
          if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) {
             // Possibly a lambda-defined listener which we could not resolve the generic event type for
             // -> let's suppress the exception and just log a debug message.
             Log logger = LogFactory.getLog(getClass());
             if (logger.isDebugEnabled()) {
                logger.debug("Non-matching event type for listener: " + listener, ex);
             }
          }
          else {
             throw ex;
          }
       }
    }
    
    • ApplicationListenerMethodAdapter#onApplicationEvent
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
       processEvent(event);
    }
    ApplicationListenerMethodAdapter#processEvent
     public void processEvent(ApplicationEvent event) {
       Object[] args = resolveArguments(event);
       if (shouldHandle(event, args)) {
          // 执行真正的方法
          Object result = doInvoke(args);
          if (result != null) {
             handleResult(result);
          }
          else {
             logger.trace("No result object given - no result to handle");
          }
       }
    }
    
    • ApplicationListenerMethodAdapter#doInvoke
     protected Object doInvoke(Object... args) {
       Object bean = getTargetBean();
       ReflectionUtils.makeAccessible(this.method);
       try {
          return this.method.invoke(bean, args);
       }
       catch (IllegalArgumentException ex) {
          assertTargetBean(this.method, bean, args);
          throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
       }
       catch (IllegalAccessException ex) {
          throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
       }
       catch (InvocationTargetException ex) {
          // Throw underlying exception
          Throwable targetException = ex.getTargetException();
          if (targetException instanceof RuntimeException) {
             throw (RuntimeException) targetException;
          }
          else {
             String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);
             throw new UndeclaredThrowableException(targetException, msg);
          }
       }
    }
    
    • ApplicationListenerMethodAdapter#getTargetBean
     protected Object getTargetBean() {
       Assert.notNull(this.applicationContext, "ApplicationContext must no be null");
       return this.applicationContext.getBean(this.beanName);
    }
    
    • 至此执行这个事件监听的方法执行完毕。如果文字有误的地方,希望批评指正,感谢您的观看。
    展开全文
  • EventListener TransactionalEventListener TransactionPhase
    EventListener
    TransactionalEventListener
    TransactionPhase
    展开全文
  • Unable to preventDefault inside passive event listener 最近做项目经常在 chrome 的控制台看到如下提示: Unable to preventDefault inside passive event listener due to target being ...

    Unable to preventDefault inside passive event listener

    最近做项目经常在 chrome 的控制台看到如下提示:

    Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080

    于是 Google 了一番,找到这篇文章,有了详细解释。Making touch scrolling fast by default

    简而言之:

    由于浏览器必须要在执行事件处理函数之后,才能知道有没有掉用过 preventDefault() ,这就导致了浏览器不能及时响应滚动,略有延迟。
    
    所以为了让页面滚动的效果如丝般顺滑,从 chrome56 开始,在 window、document 和 body 上注册的 touchstart 和 touchmove 事件处理函数,会默认为是 passive: true。浏览器忽略 preventDefault() 就可以第一时间滚动了。
    
    举例:
    wnidow.addEventListener('touchmove', func) 效果和下面一句一样
    wnidow.addEventListener('touchmove', func, { passive: true })

    这就导致了一个问题:

    如果在以上这 3 个元素的 touchstart 和 touchmove 事件处理函数中调用 e.preventDefault() ,会被浏览器忽略掉,并不会阻止默认行为。

    测试:

    body {
      margin: 0;
      height: 2000px;
      background: linear-gradient(to bottom, red, green);
    }
    
    // 在 chrome56 中,照样滚动,而且控制台会有提示,blablabla
    window.addEventListener('touchmove', e => e.preventDefault())

    那么如何解决这个问题呢?不让控制台提示,而且 preventDefault() 有效果呢?
    两个方案:
    1、注册处理函数时,用如下方式,明确声明为不是被动的
    window.addEventListener('touchmove', func, { passive: false })

    2、应用 CSS 属性 touch-action: none; 这样任何触摸事件都不会产生默认行为,但是 touch 事件照样触发。
    touch-action 还有很多选项,详细请参考touch-action

    [注]未来可能所有的元素的 touchstart touchmove 事件处理函数都会默认为 passive: true

    posted @ 2019-02-12 14:49 花儿为何那样红 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • 基于最新Spring 5.x,详细介绍了Spring @EventListener事件发布机制的实现原理!主要是initApplicationEventMulticaster从初始化事件广播器,registerListeners、ApplicationListenerDetector注册事件监听器,...
  • @EventListener 在消息服务和日志服务的使用 @EventListener介绍 在@EventListener出现之前,是通过实现ApplicationListener接口来实现Spring的监听-通知的。@EventListener出现之后,可以更方便的来使用这个功能。...
  • Spring EventListener注解原理及使用

    千次阅读 2019-10-09 18:17:14
    @EventListener注解原理 一、测试代码 测试用例 public class SpringEventTest { @Test public void test_listener() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext...
  • Spring源码解读:EventListener接口

    千次阅读 2017-05-05 11:05:32
    在spring中EventListener接口的源码 package java.util; /** * A tagging interface that all event listener interfaces must extend. * @since JDK1.1 */ public interface EventListener { } EventListener ...
  • js给eventListener传递参数

    千次阅读 2016-11-08 14:13:21
    项目中有多个img标签需要设置eventListener,其逻辑都是跳转url,考虑传入url值供eventListener中使用switch方式筛选,遇到eventListener传值问题,参考http://www.runoob.com/js/js-htmldom-eventlistener.html...
  • 在看@EventListener之前需要先知道 继承EventListener方式在底层是怎么实现了,可以参见前一篇博客Spring源码-事件监听机制(实现EventListener接口)。 先梳理一下,首先Ioc容器启动的时候,ApplicationContext的...
  • springboot事件监听(@EventListener) 应用:使用注解实现事件监听 ********************** 相关注解 @EventListener @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention...
  • @EventListener和@PostConstruct的使用

    千次阅读 2019-06-11 14:51:30
    @EventListener 是spring对事件监听的注解,在类上实现下面的代码,并重写方法也是可以实现事件监听的。 implements ApplicationListener @EventListener 后续是可以添加参数的,比如: @EventListener...
  • java.util.EventListener

    千次阅读 2018-05-11 10:57:36
    1.监听器--门的监听器import java.util.EventListener; /** * DoorListener */ public interface DoorListener extends EventListener { void onMessage(String message); }2.监听器主体--门/** * Door */ ...
  • 基于最新Spring 5.x,详细介绍了Spring的@EventListener事件发布机制的概念和使用方法,以及一些问题的解决办法!
  • package eventlistener; import java.util.EventListener; public interface ISwitchListener extends EventListener { public void switchEvent(SwitchEvent event); } package eventlistener; import jav...
  • vue项目non-passive event listener问题使用element-ui时出现警告[Violation] Added non-passive event listener to a scroll-blocking ‘mousewheel’ event. Consider marking event handler as ‘passive’ to ...
  • 监听器ApplicationListener用法写一个监听器发布事件ApplicationListener原理多播器注册监听器发布事件 监听器方法回调发布事件的流程@EventListener用法@EventListener原理 监听器的实现有两种方式: 实现...
  • 文章目录@EventListener的初始化工作@EventListener的转换 之前的“SpringFramework事件与监听机制”系列文章已经从接口层面上介绍了事件、监听器和发布器。然使用@EventListener也能达到ApplicationLister接口的...
  • 文章目录Pre概览@EventListener Pre Spring5源码 - 10 Spring事件监听机制_应用篇 Spring5源码 - 11 Spring事件监听机制_源码篇 Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析 通过上面三篇...
  • spring中EventListener使用

    千次阅读 2020-06-10 12:19:55
    spring中自带EventListener使用 首先了解下事件监听的基本原理,这里使用到的是设计模式中的“’'观察者模式"”模式。 监听监听监听事件发布者监听者A监听者B监听者C监听到后处理自己的逻辑监听到后处理自己的逻辑...
  • 自定义的EventListener在ScrollView的触发问题 自定义了一个点击监听 ClickEventListener.cs ClickEventListener 实现了 IPointerClickHandler, IPointerDownHandler, IPointerUpHandler 接口 如果在ScrollView中...
  • 看看注释:由应用事件监听器实现的接口,基于观察者设计模式。 方法是处理应用事件。 /** 由应用事件监听器实现的接口,基于观察者设计模式 ... * Based on the standard {@code java.util.EventListener} int...
  • 遗漏的知识点:addEventListener的第二个参数不光可以传入一个函数,还可以传入一个实现了EventListener 接口的对象。 文档中的描述 listener当所监听的事件类型触发时,会接收到一个事件通知(实现了 Event 接口的...
  • Spring注解系列三十:@EventListener原理

    千次阅读 2019-06-16 11:55:38
    一、@EventListener @Service public class UserService { @EventListener(classes={ApplicationEvent.class}) public void listen(ApplicationEvent event){ System.out.println("UserService。。监听到的...
  • 滑动时候警告:Unable to preventDefault inside passive event listener Unable to preventDefault inside passive event listener
  • 43、扩展原理-@EventListener与SmartInitializingSingleton 还可以使用 @EventListener; 来监听事件 原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener; EventListenerMethodProcessor ...
  • 话不多少,直接实战——用法,想懂理论的自行百度~ 1.主要用了spring的发布消息、监听事件机制。... applicationEventPublisher发布事件→EventListener监听事件→执行异步操作。如图: 图1...
  • @EventListener是spring在4.2+推出的更好的使用spring事件架构的方式,并且异步方式也很好设定 但是在spring4.2.7版本上使用eventlistener的condition 的使用需要注意以下情况可能失效: condition使用例子如@...
  • 一、Event Listener presto事件监听器Event Listener,作为plugin监听以下事件: Query creation 查询建立相关信息 Query completion (success or failure) 查询执行相关信息,包含成功查询的细节信息,失败查询的...
  • 当需要响应事件时,就需要用到EventListenerEventListener的核心作用是存储发生Event时的回调函数,通过属性_fixedPriority判断回调执行先后顺序.所有的EventListener都存储于EventDispatcher中,关于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 113,563
精华内容 45,425
关键字:

eventlistener