Skip to main content
 首页 » 编程设计

JS模拟亚马逊左侧导航算法的tab选项卡,支持四个方向,支持tab键切换,兼容各浏览器

2022年07月16日177freeliver54

Javascript tab选项卡(一切为了更好的体验, God in details!!!)

这原本只是一道简单的面试题,做出一个tab选项卡,然后要支持键盘TAB键控制。然后最近亚马逊的那个左侧菜单栏监听鼠标轨迹技术挺热门的,就把这功能添加进来了,而且还支持四个方向,用的都是原生js。如有问题,欢迎讨论

    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
  • 0002
  • 0003
  • 0004
  • 0005
  • 0006
    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
  • 0002
  • 0003
  • 0004
  • 0005
  • 0006
    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
    • 1
    • 1
    • 1
    • 1
    • 1
  • 2222
    2222
  • 3333
  • 4444
    2222
  • 0001
 
<!DOCTYPE HTML> 
<html lang="en-US"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Javascript tab选项卡</title> 
    <style> 
        #menu { 
            float: left; 
            padding: 0; 
            margin-left: 20px; 
        } 
        #menu3 { 
            float: right; 
            padding: 0; 
            margin-left: 20px; 
        } 
        #menu2 { 
            overflow: hidden; 
            zoom: 1; 
        } 
        #menu li, #menu3 li { 
            width: 12em; 
        } 
        .menu { 
            list-style: none; 
            background: #bf8d04; 
            margin: 0; 
            padding: 0; 
            overflow: hidden; 
        } 
        #menu2 li, #menu4 li { 
            width: 8em; 
            float: left; 
        } 
        .menu li.on { 
            background: #ff6600; 
        } 
        #menu li a, #menu3 li a { 
            height: 3em; 
            line-height: 3em; 
        } 
        .menu li a { 
            display: block; 
            text-align: center; 
        } 
        #menu2 li a, #menu4 li a { 
            height: 5em; 
            line-height: 5em; 
        } 
        #tabCon { 
            float: left; 
            display: inline; 
            margin-left: 1em; 
        } 
        #tabCon2 { 
            height: 50em; 
        } 
        #tabCon3 { 
            float: right; 
        } 
    </style> 
</head> 
<body> 
<div style="overflow:hidden;zoom:1;"> 
    <ul class="menu" id="menu"> 
        <li><a href="javascript:" data-href="#tab1">1</a></li> 
        <li><a href="javascript:" data-href="#tab2">2</a></li> 
        <li><a href="javascript:" data-href="#tab3">3</a></li> 
        <li><a href="javascript:" data-href="#tab4">4</a></li> 
        <li><a data-href="#tab5" href="javascript:">5</a></li> 
        <li><a data-href="#tab6" href="javascript:">6</a></li> 
        <li><a data-href="#tab7" href="javascript:">7</a></li> 
        <li><a data-href="#tab8" href="javascript:">8</a></li> 
        <li><a data-href="#tab9" href="javascript:">9</a></li> 
        <li><a data-href="#tab10" href="javascript:">10</a></li> 
        <li><a href="javascript:" data-href="#tab11">11</a></li> 
        <li><a href="javascript:" data-href="#tab12">12</a></li> 
        <li><a href="javascript:" data-href="#tab13">13</a></li> 
        <li><a href="javascript:" data-href="#tab14">14</a></li> 
        <li><a data-href="#tab15" href="javascript:">15</a></li> 
    </ul> 
    <ul id="tabCon"> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
        <li>0002</li> 
        <li>0003</li> 
        <li>0004</li> 
        <li>0005</li> 
        <li>0006</li> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
    </ul> 
</div> 
 
<div> 
    <ul class="menu" id="menu2"> 
        <li><a href="javascript:" data-href="#tab1">1</a></li> 
        <li><a href="javascript:" data-href="#tab2">2</a></li> 
        <li><a href="javascript:" data-href="#tab3">3</a></li> 
        <li><a href="javascript:" data-href="#tab4">4</a></li> 
        <li><a data-href="#tab5" href="javascript:">5</a></li> 
        <li><a data-href="#tab6" href="javascript:">6</a></li> 
        <li><a data-href="#tab7" href="javascript:">7</a></li> 
        <li><a data-href="#tab8" href="javascript:">8</a></li> 
        <li><a data-href="#tab9" href="javascript:">9</a></li> 
        <li><a data-href="#tab10" href="javascript:">10</a></li> 
    </ul> 
    <ul id="tabCon2"> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
    </ul> 
</div> 
<div style="overflow:hidden;zoom:1;"> 
    <ul class="menu" id="menu3"> 
        <li><a href="javascript:" data-href="#tab1">1</a></li> 
        <li><a href="javascript:" data-href="#tab2">2</a></li> 
        <li><a href="javascript:" data-href="#tab3">3</a></li> 
        <li><a href="javascript:" data-href="#tab4">4</a></li> 
        <li><a data-href="#tab5" href="javascript:">5</a></li> 
        <li><a data-href="#tab6" href="javascript:">6</a></li> 
        <li><a data-href="#tab7" href="javascript:">7</a></li> 
        <li><a data-href="#tab8" href="javascript:">8</a></li> 
        <li><a data-href="#tab9" href="javascript:">9</a></li> 
        <li><a data-href="#tab10" href="javascript:">10</a></li> 
        <li><a href="javascript:" data-href="#tab11">11</a></li> 
        <li><a href="javascript:" data-href="#tab12">12</a></li> 
        <li><a href="javascript:" data-href="#tab13">13</a></li> 
        <li><a href="javascript:" data-href="#tab14">14</a></li> 
        <li><a data-href="#tab15" href="javascript:">15</a></li> 
    </ul> 
    <ul id="tabCon3"> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
        <li>0002</li> 
        <li>0003</li> 
        <li>0004</li> 
        <li>0005</li> 
        <li>0006</li> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
    </ul> 
</div> 
 
<div> 
    <ul style="height:200px;" id="tabCon4"> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
        <li> 
            <ul> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
                <li>1</li> 
            </ul> 
        </li> 
        <li>2222<br>2222</li> 
        <li>3333</li> 
        <li>4444<br>2222</li> 
        <li>0001</li> 
    </ul> 
    <ul class="menu" id="menu4"> 
        <li><a href="javascript:" data-href="#tab1">1</a></li> 
        <li><a href="javascript:" data-href="#tab2">2</a></li> 
        <li><a href="javascript:" data-href="#tab3">3</a></li> 
        <li><a href="javascript:" data-href="#tab4">4</a></li> 
        <li><a data-href="#tab5" href="javascript:">5</a></li> 
        <li><a data-href="#tab6" href="javascript:">6</a></li> 
        <li><a data-href="#tab7" href="javascript:">7</a></li> 
        <li><a data-href="#tab8" href="javascript:">8</a></li> 
        <li><a data-href="#tab9" href="javascript:">9</a></li> 
        <li><a data-href="#tab10" href="javascript:">10</a></li> 
    </ul> 
 
</div> 
<div style="height:500px;"></div> 
<script> 
    (function(window){ 
        /** 
         * tab选项类 
         * @param {String} eventType 事件类型,可以指定'click', 'mouseover'事件 
         * @param {Element} menu 菜单包裹器元素,必须是ul或者ol的标签元素 
         * @param {Element} container 选项卡包裹器内容,必须是ul或者ol的标签元素 
         * @param {Boolean} TabKeyCtrl 是否开启键盘tab键控制,缺省为true,开启 
         */ 
        var TabChange = function (eventType, menu, container, TabKeyCtrl) { 
            this.eventType = eventType; 
            this.menu = menu; 
            this.container = container; 
            // 菜单元素的链接数组 
            this.menuLinks = menu.getElementsByTagName('a'); 
            // 设置延迟定时器,防止鼠标移到tab内容经过菜单时的切换 
            this.timeout = null; 
            // 记录鼠标移动时的坐标数组 
            this.mouseLocs = []; 
            // 菜单栏的固定点1, 根据菜单栏和内容的位置而改变 
            this.firstSlope = null; 
            // 菜单栏的固定点2, 根据菜单栏和内容的位置而改变 
            this.secondSlope = null; 
            // 记录内容栏相对于菜单栏的位置 
            this.relatedPos = ''; 
            // 返回内容栏相对于菜单栏的位置, 保存在this.relatedPos属性里 
            this.contentPosRelate(); 
            // 根据内容栏相对于菜单栏的位置, 返回菜单栏的固定点1,和固定点2 
            this.ensureTriangleDots(); 
 
            // 默认开启TAB键控制 
            TabKeyCtrl = TabKeyCtrl || true; 
            if (TabKeyCtrl) { 
                // 启动tab键切换 
                this.tabKeyCtrl(this.menuLinks); 
            } 
            // 初始化事件 
            this.initEvent(); 
        }; 
 
 
        TabChange.prototype = (function(){ 
            /** 
             * 显示隐藏切换方法 
             * @param {Array} elementArray 元素集数组,是tab内容li元素集 
             * @param {Number} index 当前序号 
             */ 
            var toggleDisplay = function (elementArray, index) { 
                // 显示当前序号的元素 
                elementArray[index].style.display = ''; 
                // 隐藏非当前序号的元素 
                for (var i = 0, len = elementArray.length; i < len; i++) { 
                    if (i === index) { 
                        continue; 
                    } 
                    elementArray[i].style.display = 'none'; 
                } 
            }; 
 
            /** 
             * 获取元素相对于浏览器左上角的坐标位置,为正值 
             * @param element 
             * @return {{x: Number, y: Number}} 
             * @constructor 
             */ 
            var LocFromdoc = function (element) { 
                var left = element.offsetLeft, 
                        top = element.offsetTop; 
                element = element.offsetParent; 
                while (element !== null) { 
                    left += element.offsetLeft; 
                    top += element.offsetTop; 
                    element = element.offsetParent; 
                } 
                return { 
                    x: left, 
                    y: top 
                }; 
            }; 
 
            /** 
             * 类名转换方法,确保当前序号的类名,删除其他序号的类名 
             * @param {Array} elementArray 元素集数组 存放tab菜单li元素集 
             * @param {Number} index 当前序号 
             * @param {String} className 要添加的类名 
             */ 
            var toggleClass = function (elementArray, index, className) { 
                var pattern = new RegExp(' ' + className + ' '); 
                for (var i = 0, len = elementArray.length; i < len; i++) { 
                    // 前后添加空格,且确保不能有连续空格 
                    var temp = ' ' + elementArray[i].className.replace(/^\s+|\s+$/, '').replace(/\s+/, ' ') + ' '; 
                    // 当前序号 
                    if (i === index) { 
                        // 如果当前序号的元素没有该类名,则添加类名 
                        if (temp.indexOf(' ' + className + ' ') === -1) { 
                            elementArray[i].className += (elementArray[i].className ? ' ' : '') + 'on'; 
                        } 
                        // 跳到下一个循环 
                        continue; 
                    } 
 
                    // 非当前序号,删除类名,去掉多余空格 
                    elementArray[i].className = temp.replace(pattern, '').replace(/^\s+|\s+$/, '').replace(/\s+/, ' '); 
                } 
            }; 
 
            return { 
                /** 
                 * 根据内容栏相对于菜单栏的位置,判断移动过程中的点是否在三角形内 
                 * @param {Object} p1 开始位置 
                 * @param {Object} p2 菜单栏固定点1 
                 * @param {Object} p3 菜单栏固定点2 
                 * @param {Object} m 结束位置 
                 * @return {*} 
                 */ 
                proPosInTriangle: function (p1, p2, p3, m) { 
                    // 结束时鼠标坐标位置 
                    var x = m.x, 
                            y = m.y, 
                    // 开始鼠标坐标位置 
                            x1 = p1.x, 
                            y1 = p1.y, 
                    // 菜单栏包裹层右上角坐标 
                            x2 = p2.x, 
                            y2 = p2.y, 
                    // 右下角坐标 
                            x3 = p3.x, 
                            y3 = p3.y, 
                    // (y2 - y1) / (x2 - x1)为两坐标连成直线的斜率 
                    // 因为直线的公式为y=kx+b;当斜率相同时,只要比较 
                    // b1和b2的差值就可以知道该点是在 
                    // (x1,y1),(x2,y2)的直线的哪个方向 
                    // 当r1大于0,说明该点在直线右侧,其它以此类推 
                            r1 = y - y1 - (y2 - y1) / (x2 - x1) * (x - x1), 
                            r2 = y - y2 - (y3 - y2) / (x3 - x2) * (x - x2), 
                            r3 = y - y3 - (y1 - y3) / (x1 - x3) * (x - x3), 
                            compare; 
 
                    // 根据位置不同,判定公式也不同,因为找不到通用的办法 
                    // 只好各个对比 
                    switch (this.relatedPos) { 
                        case 'left': 
                            compare = (r1 * r2 * r3 > 0) && (r1 > 0); 
                            break; 
                        case 'right': 
                        case 'down': 
                            compare = (r1 * r2 * r3 < 0) && (r1 > 0); 
                            break; 
                        case 'up': 
                            compare = (r1 * r2 * r3 > 0) && (r1 < 0); 
                            break; 
                        default: 
                            break; 
                    } 
                    // 返回是否在三角形内的结果 
                    return compare; 
                }, 
                /** 
                 * 记录元素的位置信息 
                 * @param element 
                 * @return {{top: *, topAndHeight: number, left: *, leftAndWidth: number}} 
                 */ 
                info: function (element) { 
                    var location = LocFromdoc(element); 
                    return { 
                        top: location.y, 
                        topAndHeight: location.y + element.offsetHeight, 
                        left: location.x, 
                        leftAndWidth: location.x + element.offsetWidth 
                    }; 
                }, 
                /** 
                 * 记录内容栏相对于菜单栏的位置,因为后面还要用刀,使用this.relatedPos记录信息 
                 * @param {Number} deviation 容许的差值,或者偏差 
                 */ 
                contentPosRelate: function (deviation) { 
                    deviation = deviation || 0; 
                    var ele1 = this.info(this.menu), 
                            ele2 = this.info(this.container); 
 
                    // ele2左边距离的浏览器左侧的距离大于 
                    // ele1左边距离的浏览器左侧的距离加上本身的宽 
                    // 说明ele2在ele1的右侧,其他以此类推 
                    if (ele2.left >= (ele1.leftAndWidth + deviation)) { 
                        this.relatedPos = 'right'; 
                    } else if (ele1.left >= (ele2.leftAndWidth + deviation)) { 
                        this.relatedPos = 'left'; 
                    } else if (ele2.top >= (ele1.topAndHeight + deviation)) { 
                        this.relatedPos = 'down'; 
                    } else if(ele1.top >= (ele2.topAndHeight + deviation)) { 
                        this.relatedPos = 'up'; 
                    } 
 
                }, 
                /** 
                 * 根据内容栏相对于菜单栏的位置, 返回菜单栏的固定点1,和固定点2,保存在this.firstSlope和this.secondSlope对象里 
                 */ 
                ensureTriangleDots: function () { 
                    var x1, y1, x2, y2; 
                    var info = this.info(this.menu); 
                    switch (this.relatedPos) { 
                        case 'right': 
                            x1 = info.leftAndWidth; 
                            y1 = info.top; 
                            x2 = x1; 
                            y2 = info.topAndHeight; 
                            break; 
                        case 'left': 
                            x1 = info.left; 
                            y1 = info.top; 
                            x2 = x1; 
                            y2 = info.topAndHeight; 
                            break; 
                        case 'down': 
                            x1 = info.left; 
                            y1 = info.topAndHeight; 
                            x2 = info.leftAndWidth; 
                            y2 = y1; 
                            break; 
                        case 'up': 
                            x1 = info.left; 
                            y1 = info.top; 
                            x2 = info.leftAndWidth; 
                            y2 = y1; 
                            break; 
                        default: 
                            break; 
                    } 
 
                    this.firstSlope = { 
                        x: x1, 
                        y: y1 
                    }; 
                    this.secondSlope = { 
                        x: x2, 
                        y: y2 
                    }; 
                }, 
                /** 
                 * 键盘tab键控制tab菜单切换 
                 * @param {Element} menuLinks tab菜单的链接数组,因为只有链接可以被键盘tab切换 
                 */ 
                tabKeyCtrl: function (menuLinks) { 
                    var that = this; 
                    // 侦听document的keyup事件 
                    EventUtil.addEvent(document, 'keyup', function (event) { 
                        event = EventUtil.getEvent(event); 
                        // 获取当前元素 
                        var target = EventUtil.getTarget(event), 
                        // 获取当前元素的data-href属性 
                                href = target.getAttribute('data-href'); 
                        // 当按下的是tab键时且data-href属性值包含"#tab"字符 
                        if ((event.keyCode === 9) && href && (href.indexOf('#tab') > -1)) { 
                            // 获取对应数字,表示显示的tab菜单的相应序号 
                            var index = parseInt(href.split('#tab')[1], 10) - 1; 
                            // 触发当前序号的tab菜单事件,切换tab 
                            EventUtil.triggerEvent(menuLinks[index], that.eventType); 
                        } 
                    }); 
 
                }, 
                /** 
                 * 初始化事件,主要是注册tab菜单的事件侦听器 
                 */ 
                initEvent: function () { 
                    var that = this, 
                            menuLinks = this.menuLinks, 
                            clickRegistration; 
 
                    // 给tab菜单的链接注册侦听器 
                    function toggle(array1, array2, index, className) { 
                        // 类名切换 
                        toggleClass(array1, index, className); 
                        // 显示切换 
                        toggleDisplay(array2, index); 
                    } 
 
                    for (var i = 0, len = menuLinks.length; i < len; i++) { 
                        // 当为mouseover事件时,给mouseout注册事件侦听器 
                        // 防止鼠标移到tab内容经过菜单时的切换 
                        if (this.eventType === 'mouseover') { 
                            EventUtil.addEvent(menuLinks[i], 'mouseover', (function (index) { 
                                return function (event) { 
                                    // 捕捉第一次初始化的错误 
                                    try { 
                                        // 是否在指定三角形内 
                                        var diff = that.proPosInTriangle(that.mouseLocs[0], that.firstSlope, that.secondSlope, that.mouseLocs[2]); 
                                    } catch (ex) { 
                                    } 
 
                                    // 是就启动延迟显示, 
                                    // 否则不延迟 
                                    if (diff) { 
                                        that.timeout = setTimeout(function () { 
                                            toggle(that.menu.children, that.container.children, index, 'on'); 
                                        }, 300); 
                                    } else { 
                                        toggle(that.menu.children, that.container.children, index, 'on'); 
                                    } 
                                }; 
                            })(i)); 
                            // 记录鼠标在菜单栏中移动的最后三个坐标位置 
                            EventUtil.addEvent(menuLinks[i], 'mousemove', function (event) { 
                                that.mouseLocs.push({ 
                                    x: EventUtil.eventPage(event).x, 
                                    y: EventUtil.eventPage(event).y 
                                }); 
                                if (that.mouseLocs.length > 3) { 
                                    // 移除超过三项的数据 
                                    that.mouseLocs.shift(); 
                                } 
                            }); 
 
                            // 鼠标移出的时候,清除延时器 
                            EventUtil.addEvent(menuLinks[i], 'mouseout', function (event) { 
                                if (that.timeout) { 
                                    clearTimeout(that.timeout); 
                                } 
                            }); 
                        } else { 
                            // 其它事件侦听器,例如“click” 
                            EventUtil.addEvent(menuLinks[i], this.eventType, clickRegistration = (function (index) { 
                                return function (event) { 
                                    clearTimeout(that.timeout); 
                                    // 启动延时显示 
                                    that.timeout = setTimeout(function () { 
                                        toggle(that.menu.children, that.container.children, index, 'on'); 
                                    }, 80); 
                                    // 阻止默认行为 
                                    EventUtil.preventDefault(event); 
                                }; 
                            })(i)); 
                        } 
                    } 
 
                    // 触发第一个菜单链接的事件 
                    EventUtil.triggerEvent(menuLinks[0], this.eventType); 
                } 
            }; 
        }()); 
 
 
        /** 
         * 跨浏览器event对象处理对象 
         * @type {{addEvent: Function, getEvent: Function, getTarget: Function, preventDefault: Function, triggerEvent: Function}} 
         */ 
        var EventUtil = { 
            /** 
             * 注册事件侦听器 
             * @param element 
             * @param type 
             * @param listener 
             */ 
            addEvent: function (element, type, listener) { 
                if (element.addEventListener) { 
                    element.addEventListener(type, listener, false); 
                } else { 
                    element['e' + type + listener] = listener; 
                    element[type + listener] = function () { 
                        element['e' + type + listener](window.event); 
                    }; 
                    element.attachEvent('on' + type, element[type + listener]); 
                } 
            }, 
            removeEvent: function (element, type, listener) { 
                if (element.removeEventListener) { 
                    //W3C 方法 
                    element.removeEventListener(type, listener, false); 
                    return true; 
                } else if (element.detachEvent) { 
                    //MSIE方法 
                    element.detachEvent("on" + type, element[type + listener]); 
                    element['e' + type + listener] = null; 
                    element[type + listener] = null; 
                    return true; 
                } 
                //若两种方法都不具备则返回false 
                return false; 
            }, 
            /** 
             * 获取event对象 
             * @param event 
             * @return {*|Event} 
             */ 
            getEvent: function (event) { 
                return event || window.event; 
            }, 
            /** 
             * 获取目标元素 
             * @param event 
             * @return {EventTarget|Object} 
             */ 
            getTarget: function (event) { 
                event = this.getEvent(event); 
                return event.target || event.srcElement; 
            }, 
            /** 
             * 阻止默认行为 
             * @param event 
             */ 
            preventDefault: function (event) { 
                event = this.getEvent(event); 
                if (event.preventDefault) { 
                    event.preventDefault(); 
                } else { 
                    event.returnValue = false; 
                } 
            }, 
            /** 
             * 触发事件 
             * @param element 
             * @param type 
             */ 
            triggerEvent: function (element, type) { 
                var ua = navigator.userAgent; 
                if (ua.indexOf('MSIE') && parseInt(ua.split('MSIE')[1], 10) < 9) { 
                    element.fireEvent("on" + type); 
                } else { 
                    var e = document.createEvent('MouseEvent'); 
                    e.initEvent(type, false, false); 
                    element.dispatchEvent(e); 
                } 
            }, 
            eventPage: function (event) { 
                event = this.getEvent(event); 
                return { 
                    x: event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)), 
                    y: event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) 
                }; 
            } 
        }; 
 
 
        var TabFactory = { 
            create: function (eventType, menu, container, TabKeyCtrl) { 
                return new TabChange(eventType, menu, container, TabKeyCtrl); 
            } 
        }; 
 
        window.TabFactory = TabFactory; 
    }(window)); 
 
var menu = document.getElementById('menu'), 
        container = document.getElementById('tabCon'), 
        menu2 = document.getElementById('menu2'), 
        container2 = document.getElementById('tabCon2'), 
        menu3 = document.getElementById('menu3'), 
        container3 = document.getElementById('tabCon3'), 
        menu4 = document.getElementById('menu4'), 
        container4 = document.getElementById('tabCon4'); 
 
// 实例化对象 
TabFactory.create('mouseover', menu, container); 
TabFactory.create('mouseover', menu2, container2); 
TabFactory.create('mouseover', menu3, container3); 
TabFactory.create('mouseover', menu4, container4); 
</script> 
</body> 
</html> 

本文参考链接:https://www.cnblogs.com/webFrontDev/archive/2013/03/05/2943994.html