• anu


    import { document } from "./browser";
    import { isFn, noop, options } from "./util";
    
    var globalEvents = {};
    export var eventPropHooks = {}; //用于在事件回调里对事件对象进行
    export var eventHooks = {}; //用于在元素上绑定特定的事件
    //根据onXXX得到其全小写的事件名, onClick --> click, onClickCapture --> click,
    // onMouseMove --> mousemove
    
    export var eventLowerCache = {
        onClick: "click",
        onChange: "change",
        onWheel: "wheel"
    };
    /**
     * 判定否为与事件相关
     *
     * @param {any} name
     * @returns
     */
    export function isEventName(name) {
        return /^on[A-Z]/.test(name);
    }
    
    export var isTouch = "ontouchstart" in document;
    
    export function dispatchEvent(e, type, end) {
        //__type__ 在injectTapEventPlugin里用到
        e = new SyntheticEvent(e);
        if (type) {
            e.type = type;
        }
        var bubble = e.type;
    
        var hook = eventPropHooks[bubble];
        if (hook && false === hook(e)) {
            return;
        }
    
        var paths = collectPaths(e.target, end || document);
        var captured = bubble + "capture";
        options.async = true;
        triggerEventFlow(paths, captured, e);
    
        if (!e._stopPropagation) {
            triggerEventFlow(paths.reverse(), bubble, e);
        }
        options.async = false;
        options.flushBatchedUpdates();
    }
    
    function collectPaths(from, end) {
        var paths = [];
        do {
            if (from === end) {
                break;
            }
            var events = from.__events;
            if (events) {
                paths.push({ dom: from, events: events });
            }
    
        } while ((from = from.parentNode) && from.nodeType === 1);
        // target --> parentNode --> body --> html
        return paths;
    }
    
    function triggerEventFlow(paths, prop, e) {
        for (var i = paths.length; i--;) {
            var path = paths[i];
            var fn = path.events[prop];
            if (isFn(fn)) {
                e.currentTarget = path.dom;
                fn.call(path.dom, e);
                if (e._stopPropagation) {
                    break;
                }
            }
        }
    }
    
    export function addGlobalEvent(name) {
        if (!globalEvents[name]) {
            globalEvents[name] = true;
            addEvent(document, name, dispatchEvent);
        }
    }
    
    export function addEvent(el, type, fn, bool) {
        if (el.addEventListener) {
            // Unable to preventDefault inside passive event listener due to target being
            // treated as passive
            el.addEventListener(
                type,
                fn,
                bool || false
            );
        } else if (el.attachEvent) {
            el.attachEvent("on" + type, fn);
        }
    }
    
    
    var rcapture = /Capture$/;
    export function getBrowserName(onStr) {
        var lower = eventLowerCache[onStr];
        if (lower) {
            return lower;
        }
        var camel = onStr.slice(2).replace(rcapture, "");
        lower = camel.toLowerCase();
        eventLowerCache[onStr] = lower;
        return lower;
    }
    
    
    eventPropHooks.click = function (e) {
        return !e.target.disabled;
    };
    
    /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120
                firefox DOMMouseScroll detail 下3 上-3
                firefox wheel detlaY 下3 上-3
                IE9-11 wheel deltaY 下40 上-40
                chrome wheel deltaY 下100 上-100 */
    /* istanbul ignore next  */
    const fixWheelType =
        "onmousewheel" in document
            ? "mousewheel"
            : document.onwheel !== void 666 ? "wheel" : "DOMMouseScroll";
    const fixWheelDelta =
        fixWheelType === "mousewheel"
            ? "wheelDetla"
            : fixWheelType === "wheel" ? "deltaY" : "detail";
    eventHooks.wheel = function (dom) {
        addEvent(dom, fixWheelType, function (e) {
            var delta = e[fixWheelDelta] > 0 ? -120 : 120;
            var deltaY = ~~dom.__wheel + delta;
            dom.__wheel = deltaY;
            e = new SyntheticEvent(e);
            e.type = "wheel";
            e.deltaY = deltaY;
            dispatchEvent(e);
        });
    };
    
    var fixFocus = {};
    "blur,focus".replace(/w+/g, function (type) {
        eventHooks[type] = function () {
            if (!fixFocus[type]) {
                fixFocus[type] = true;
                addEvent(
                    document,
                    type,
                    dispatchEvent,
                    true
                );
            }
        };
    });
    /**
     * 
    DOM通过event对象的relatedTarget属性提供了相关元素的信息。这个属性只对于mouseover和mouseout事件才包含值;
    对于其他事件,这个属性的值是null。IE不支持realtedTarget属性,但提供了保存着同样信息的不同属性。
    在mouseover事件触发时,IE的fromElement属性中保存了相关元素;
    在mouseout事件出发时,IE的toElement属性中保存着相关元素。
    但fromElement与toElement可能同时都有值
     */
    function getRelatedTarget(e) {
        if (!e.timeStamp) {
            e.relatedTarget = e.type === "mouseover" ? e.fromElement : e.toElement;
        }
        return e.relatedTarget;
    }
    
    function contains(a, b) {
        if (b) {
            while ((b = b.parentNode)) {
                if (b === a) {
                    return true;
                }
            }
        }
        return false;
    }
    
    String("mouseenter,mouseleave").replace(/w+/g, function (type) {
        eventHooks[type] = function (dom, name) {
            var mark = "__" + name;
            if (!dom[mark]) {
                dom[mark] = true;
                var mask = name === "mouseenter" ? "mouseover" : "mouseout";
                addEvent(dom, mask, function (e) {
                    let t = getRelatedTarget(e);
                    if (!t || (t !== dom && !contains(dom, t))) {
                        var common = getLowestCommonAncestor(dom, t);
                        //由于不冒泡,因此paths长度为1 
                        dispatchEvent(e, name, common);
                    }
                });
            }
        };
    });
    
    function getLowestCommonAncestor(instA, instB) {
        var depthA = 0;
        for (var tempA = instA; tempA; tempA = tempA.parentNode) {
            depthA++;
        }
        var depthB = 0;
        for (var tempB = instB; tempB; tempB = tempB.parentNode) {
            depthB++;
        }
    
        // If A is deeper, crawl up.
        while (depthA - depthB > 0) {
            instA = instA.parentNode;
            depthA--;
        }
    
        // If B is deeper, crawl up.
        while (depthB - depthA > 0) {
            instB = instB.parentNode;
            depthB--;
        }
    
        // Walk in lockstep until we find a match.
        var depth = depthA;
        while (depth--) {
            if (instA === instB) {
                return instA;
            }
            instA = instA.parentNode;
            instB = instB.parentNode;
        }
        return null;
    }
    
    
    if (isTouch) {
        eventHooks.click = noop;
        eventHooks.clickcapture = noop;
    }
    
    export function createHandle(name, fn) {
        return function (e) {
            if (fn && fn(e) === false) {
                return;
            }
            dispatchEvent(e, name);
        };
    }
    
    var changeHandle = createHandle("change");
    var doubleClickHandle = createHandle("doubleclick");
    
    //react将text,textarea,password元素中的onChange事件当成onInput事件
    eventHooks.changecapture = eventHooks.change = function (dom) {
        var mask = /text|password/.test(dom.type) ? "input" : "change";
        addEvent(document, mask, changeHandle);
    };
    
    eventHooks.doubleclick = eventHooks.doubleclickcapture = function () {
        addEvent(document, "dblclick", doubleClickHandle);
    };
    
    export function SyntheticEvent(event) {
        if (event.nativeEvent) {
            return event;
        }
        for (var i in event) {
            if (!eventProto[i]) {
                this[i] = event[i];
            }
        }
        if (!this.target) {
            this.target = event.srcElement;
        }
        this.fixEvent();
        this.timeStamp = new Date() - 0;
        this.nativeEvent = event;
    }
    
    var eventProto = (SyntheticEvent.prototype = {
        fixEvent: function () { }, //留给以后扩展用
        preventDefault: function () {
            var e = this.nativeEvent || {};
            e.returnValue = this.returnValue = false;
            if (e.preventDefault) {
                e.preventDefault();
            }
        },
        fixHooks: function () { },
        stopPropagation: function () {
            var e = this.nativeEvent || {};
            e.cancelBubble = this._stopPropagation = true;
            if (e.stopPropagation) {
                e.stopPropagation();
            }
        },
        persist: noop,
        stopImmediatePropagation: function () {
            this.stopPropagation();
            this.stopImmediate = true;
        },
        toString: function () {
            return "[object Event]";
        }
    });
    /* istanbul ignore next  */
    //freeze_start
    Object.freeze ||
        (Object.freeze = function (a) {
            return a;
        });
    //freeze_end
  • 相关阅读:
    [UWP 开发] 一个简单的Toast实现
    纯MarkDown博客阅读体验优化
    [沈航软工教学] 3、4班最终成绩排行榜
    [沈航软工教学] 期末附加作业
    [沈航软工教学] 前十三周3,4班排行榜
    [沈航软工教学] 前十二周3,4班排行榜
    [沈航软工教学] 前八周3,4班排行榜
    BugPhobia准备篇章:Beta阶段前后端接口文档
    BugPhobia回顾篇章:团队Alpha阶段工作分析
    BugPhobia贡献篇章:团队贡献分值与转会确定
  • 原文地址:https://www.cnblogs.com/dhsz/p/7560081.html
Copyright © 2020-2023  润新知