首页 > 其他分享 >History API

History API

时间:2024-08-22 14:05:39浏览次数:10  
标签:url window popstate state API ._ History history

History API

API

  • history.back(); history.go(-1)
  • history.forward();history.go(1)
  • history.pushState(state,unused,url?),state:可序列化的js object.unused:历史原因,空字符串,url:可选,当页面恢复后有可能会加载它,但是必须同源。它会用来更新浏览器的地址栏,但是它不会加载那个页面。
  • history.replaceState(state,unused,url?)

事件

  • popstate
    当调用浏览器的前进/后退,或者history.forward|back|go,导致历史栈变更,并且state发生变化的时候会发布这个事件
  • hashChange
    当url只有fragment部分发生变化,会触发这个事件,在popstate 事件之后。

SPA

上面的APIpushState,replaceState,,事件popstate,这两者就是为了SPA的路由系统准备的。所有SPA的路由都是基于它们。

  • 用户点击link导致路由跳转,实际上并不是浏览器的路由跳转,内部就两个逻辑pushState({...state,navigationId},'',newurl);internalRouter();,
  • 同时SPA订阅了window.addEventListeners('popstate',(event)=>{render(event.state)})

下面是Angular源码中对于这一段的解析。

// Angular中通过location/history的操作是封装到了BrowserPlatformLocation 这个类中
export class BrowserPlatformLocation extends PlatformLocation{
    // 这个就是window.location
    public readonly location!:Location;
    // 这个就是window.history
    private _history!: History;

    constructor(@Inject(DOCUMENT) private _doc: any) {
        super();
        this._init();
    }
    _init() {
        (this as {location: Location}).location = window.location;
        this._history = window.history;
    }

    // 对浏览器的popState事件进行订阅,重点关注这个方法。这个方法是在LocationStragetry中被调用
    override onPopState(fn: LocationChangeListener): VoidFunction {
        const window = getDOM().getGlobalEventTarget(this._doc, 'window');
        window.addEventListener('popstate', fn, false);
        return () => window.removeEventListener('popstate', fn);
    }

    // 对浏览器的hashChange事件进行订阅
    override onHashChange(fn: LocationChangeListener): VoidFunction {
        const window = getDOM().getGlobalEventTarget(this._doc, 'window');
        window.addEventListener('hashchange', fn, false);
        return () => window.removeEventListener('hashchange', fn);
    }
    override pushState(state: any, title: string, url: string): void {
        if (supportsState()) {
        this._history.pushState(state, title, url);
        } else {
        this.location.hash = url;
        }
    }

    override replaceState(state: any, title: string, url: string): void {
        if (supportsState()) {
        this._history.replaceState(state, title, url);
        } else {
        this.location.hash = url;
        }
    }

    override forward(): void {
        this._history.forward();
    }

    override back(): void {
        this._history.back();
    }
}

// LocationStrategy 这个是Angular 对于路由形式的抽象,支持hash/h5路由。这个类使用了装饰者模式来管理底层事件的订阅与解订阅
export class PathLocationStrategy extends LocationStrategy implements OnDestroy {
    constructor(
      private _platformLocation: PlatformLocation,
      @Optional() @Inject(APP_BASE_HREF) href?: string)
    {}

    // 这个函数对BrowserPlatformLocation 中的popstate,hashchange进行了调用,这里也只是封装,最终的事件处理函数也不是这个类创建的
    override onPopState(fn: LocationChangeListener): void {
        this._removeListenerFns.push(
            this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn));
    }
}

// Location 这个类再次封装了LocationStrategy,提供了对history的操作,以及对于popstate 的订阅。它的出现是为了支持不同策略的支持
export class Location implements OnDestroy
{
    _subject: EventEmitter<any> = new EventEmitter();
    // 注入LocationStrategy
    constructor(locationStrategy: LocationStrategy) {
        this._locationStrategy = locationStrategy;
        const browserBaseHref = this._locationStrategy.getBaseHref();
        this._baseHref = stripTrailingSlash(_stripIndexHtml(browserBaseHref));

        // 这个地方就是对popState事件订阅的地方,它将事件转化成了流
        this._locationStrategy.onPopState((ev) => {
            this._subject.emit({
                'url': this.path(true),
                'pop': true,
                'state': ev.state,
                'type': ev.type,
            });
        });
    }

    // 这个类就是提供给Router来进行订阅popState的事件
    subscribe(
        onNext: (value: PopStateEvent) => void, onThrow?: ((exception: any) => void)|null,
        onReturn?: (() => void)|null): SubscriptionLike {
        return this._subject.subscribe({next: onNext, error: onThrow, complete: onReturn});
    }
}

// 对于popstate事件感兴趣的是Router这个类,它可以主动的跳转路由,然后调用pushState,保存状态。
//它也可以被动的,当浏览器路状态变化时,动态的解析路由,然后调用路由跳转的逻辑。
export class Router{
    setUpLocationChangeListener(): void {
        // 对下面注释,我是有疑惑的,这个事件里面不是有setTimeout吗,它不是会自动触发cd吗,为什么还要下面的注释
        // 其实并不是有setTimeout就一定会触发变更,不能这么说,必须要在ngZone里面执行setTimeout,才有可能触发变更
        // Zone.current 如果没有代码执行,其实,它应该是root.当有Task执行的时候,它会临时被设置成Task创建的时候的
        // Zone. 所以必须要在window.addEventListeners 的时候,在ngZone里面,否则后面的所以操作都是没有意义的。


        // Don't need to use Zone.wrap any more, because zone.js
        // already patch onPopState, so location change callback will
        // run into ngZone
        if (!this.locationSubscription) {
        this.locationSubscription = this.location.subscribe(event => {
            const source = event['type'] === 'popstate' ? 'popstate' : 'hashchange';
            if (source === 'popstate') {
                // The `setTimeout` was added in #12160 and is likely to support Angular/AngularJS
                // hybrid apps.                
                setTimeout(() => {
                    const extras: NavigationExtras = {replaceUrl: true};
                    // Navigations coming from Angular router have a navigationId state
                    // property. When this exists, restore the state.
                    const state = event.state?.navigationId ? event.state : null;
                    if (state) {
                    const stateCopy = {...state} as Partial<RestoredState>;
                    delete stateCopy.navigationId;
                    delete stateCopy.ɵrouterPageId;
                    if (Object.keys(stateCopy).length !== 0) {
                        extras.state = stateCopy;
                    }
                    }
                    const urlTree = this.parseUrl(event['url']!);
                    //这个就是开始调用路由跳转的逻辑
                    this.scheduleNavigation(urlTree, source, state, extras);
                }, 0);
            }
        });
        }
    }
}

标签:url,window,popstate,state,API,._,History,history
From: https://www.cnblogs.com/kongshu-612/p/18373713

相关文章

  • 守护您的数字资产:API安全的最佳实践
    ​在数字化时代,API(应用程序编程接口)已成为企业与用户、服务与服务之间沟通的桥梁。然而,随着API的广泛应用,安全问题也日益凸显。本文将探讨API安全的重要性,并提供一些实用的安全措施,帮助您保护宝贵的数字资产。正文:1. API安全的重要性API是连接不同系统和应用程序的纽带,它们处......
  • 体育数据API纳米奥运会数据API:高阶数据包接口文档API示例⑦
    纳米体育数据的数据接口通过JSON拉流方式获取200多个国家的体育赛事实时数据或历史数据的编程接口,无请求次数限制,可按需购买,接口稳定高效;覆盖项目包括足球、篮球、网球、电子竞技、奥运等专题、数据内容。纳米数据API2.0版本包含http协议以及websocket协议,主要通过http获取数......
  • 海光 FTPM 运行报错:Fapi_Provision_Finish() ErrorCode (0x00060025) No EK certifica
    使用的是海光CPU提供的基于固件的FTPM,错误原因是海光没有给TPM提供相应的EK证书。从而导致Fapi_Provision()接口无法通过证书的校验。关于Fapi_Provision()接口的功能,官网提到是:RetrievetheEKtemplate,nonceandcertificate,verifythattheymatchtheTPM’sEK......
  • 身份证识别、护照OCR、python身份证四要素实名认证API
    翔云身份证实名认证与身份证识别接口让你的APP在众多竞品中脱颖而出,仅需一键上传,用户身份信息便能快速提取,精准核验,告别繁琐的手动输入与反复核验,简化身份验证流程,提升用户体验,现已被广泛应用于电商、在线教育、金融等各类生活服务类APP中。python身份证实名认证接口代码......
  • 霸王餐api接口对接怎么用
    美团技术服务合作中心推出的霸王餐API接口,确实为餐饮行业的数字化转型提供了重要支持,并针对行业面临的一些关键问题提供了有效的解决方案。以下是对霸王餐API接口的总结:背景与意义:霸王餐API接口旨在帮助商家解决营销活动中的成本分摊问题,同时促进用户评价的积累和运营效率......
  • 常用API
    目录一、API概念二、如何使用API帮助文档三、Math1.Math中方法的调用2.Math类的常用方法四、System类1.System类的常用方法2.拷贝数组五、Object类1.toString方法2.equals()方法六、BigInteger常用方法七、BigDecimal1.构造方法2.常用方法一、API概念  ......
  • Win11系统弹窗“advapi32.dll文件缺失”怎么办?Win11电脑系统提示缺少advapi32.dll的解
    在Win11系统中,若出现“advapi32.dll文件缺失”弹窗,可尝试从可靠渠道下载该文件并放置到正确系统目录。也可使用系统修复工具进行修复,同时检查系统更新。操作时务必谨慎,以免引发其他问题。本篇将为大家带来Win11系统弹窗“advapi32.dll文件缺失”怎么办的内容,感兴趣的小伙伴们一......
  • 看看人家那后端 API 接口写的,那叫一个优雅!
    文章来源:https://www.toutiao.com/article/6694404645827117572在移动互联网,分布式、微服务盛行的今天,现在项目绝大部分都采用的微服务框架,前后端分离方式,(题外话:前后端的工作职责越来越明确,现在的前端都称之为大前端,技术栈以及生态圈都已经非常成熟;以前后端人员瞧不起前端人员,那......
  • WebDriver API剖析----元素、鼠标、键盘的操作
    一、元素的操作1、清除元素的内容clear()方法用于清除元素中已有的内容。fromseleniumimportwebdriverfromtimeimportsleepfromselenium.webdriver.common.byimportBydriver=webdriver.Firefox()driver.get("https://www.baidu.com")driver.find_element(......
  • python 调用通义千问SDK API
    前言通义千问在线AI助手:https://tongyi.aliyun.com/qianwen/通义千问官网文档地址:https://help.aliyun.com/zh/dashscope/developer-reference/(通义千问2024.4.26更新模型的API-KEY收费,非限时免费开放模型,有使用Token数量的限制)支持python3.8或以上版本配置流程1......