单页面SPA应用路由原理 history hash

<!DOCTYPE html>
<html lang="zh">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>单页面SPA应用路由原理</title>
        <style type="text/css">
            .api,
            .hash {
                color: blue;
                display: block;
                cursor: pointer;
            }
        </style>
    </head>

    <body>
        <a class='api a'>a.html</a>
        <a class='api b'>b.html</a>
        <p>
        </p>
        <a class='hash a'>#a.html</a>
        <a class='hash b'>#b.html</a>
        <script type="text/javascript">
            // 注册路由
            // 说明:document.querySelectorAll('.api') 返回的是类数组对象NodeList,这个NodeList可以使用数组的方法forEach
            // NodeList只有数组的forEach方法,其他方法map/filter等方法没有
            document.querySelectorAll('.api').forEach(item => {
                item.addEventListener('click', (e) => {
                    // 阻止默认事件
                    e.preventDefault();
                    let link = item.textContent;
                    // pushState有3个参数,第一个参数是跳转url的状态信息,第二个参数是页面标题,第三个参数是跳转链接
                    // 
                    window.history.pushState({
                            name: 'api'
                        },
                        '页面标题',
                        link
                    )
                }, false) // false 表示冒泡阶段执行
            });
            // 监听路由
            // popstate 属于window事件
            window.addEventListener('popstate', (e) => {
                console.log({
                    location: location.href,
                    state: e.state
                })
            })


            // 注册路由
            document.querySelectorAll('.hash').forEach(item => {
                item.addEventListener('click', (e) => {
                    e.preventDefault();
                    let link = item.textContent;
                    window.location.hash = link
                }, false)
            });
            // 监听路由
            // hashchange 属于window事件
            window.addEventListener('hashchange', (e) => {
                console.log({
                    location: location.href,
                    state: e.state
                })
            })
      // hash改变的方法:
      // window.location.assign('#a')
      // window.location.replace('#b')
</script> </body> </html>

说明:pushstate和replacestate不能监听到路由变化,可以重写pushstate和replacestate,这样就获取到了pushState 和 replaceState 的参数。

// Add this:
var _wr = function(type) {
    var orig = history[type];
    return function() {
        var rv = orig.apply(this, arguments);
        var e = new Event(type);
        e.arguments = arguments;
        window.dispatchEvent(e);
        return rv;
    };
};
history.pushState = _wr('pushState');
history.replaceState = _wr('replaceState');

// Use it like this:
window.addEventListener('pushState', function(e) {
    console.warn('THEY DID IT AGAIN!');
});
window.addEventListener('replaceState', function(e) {
    console.warn('THEY DID IT AGAIN!');
});

  

hash和history的区别:

hash:

(1)丑

(2)hash会占用锚点功能

(3)兼容性较好

history:

(1)路由与后端无异

(2)IE10级以上

(3)需要后端支持

(4)popstate仅仅在前进或者后退时才触发。

onpopstate
原文地址:https://www.cnblogs.com/mengfangui/p/10101562.html