在Firefox中,当通过window.location.hash更新哈希值时,iframe会不断重新加载

前端开发 2026-07-09

我试图通过将window.location.hash设置为 'hash/value/for/section' 来更新iframe页面的哈希值。

不过,一旦哈希被设置,iframe就会重新加载。加载到页面后,再次进行哈希更新时,又会重新加载。

跳到页面的不同部分时,页面不会跳转到该部分;相反,它会从头加载,然后停在所选的部分。

我使用的是不带 '#' 的哈希值,因为浏览器在设置时会忽略前导的 '#'.引用: https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-location-hash-dev

在Chrome中工作正常。这个问题仅在Firefox浏览器中出现。

有谁遇到过这种问题吗?或者知道原因或解决办法?

import { Dialog, DialogContent, DialogBody } from "/dialog";

const IframeDialog = ({ closeIFrame, accountId }) => (
    <Dialog isOpen onClose={closeIFrame} isCentered size="extraExtraLarge" fullSize
        fullHeight
    >
        <DialogContent hasClose>
            <DialogBody style={{ padding: "0px", margin: "10px" }}>
                <iframe
                    title="Access Child Organization"
                    src={`${window.location.origin}/zem/${accountId}?frameorigin=${window.location.origin}#`}
                    style={
                        {
                            width: "100%",
                            height: "100%",
                            border: "none"
                        }
                    }
                />
            </DialogBody>

        </DialogContent>
    </Dialog>
);

export default IframeDialog;

在iframe应用中,我将通过我们路由类实例的 push 方法来更新哈希。下面附有路由类的代码。

import Events from "@/custom-events";

function getHashPath () {
    const { href } = window.location;
    const hashIndex = href.indexOf("#");
    return hashIndex === -1 ? "" : href.substring(hashIndex + 1);
}

function pushHashPath (path) {
    window.location.hash = path;
}

function replaceHashPath (path) {
    const hashIndex = window.location.href.indexOf("#");
    window.location.replace(`${window.location.href.slice(0, hashIndex >= 0 ? hashIndex : 0)}#${path}`);
}

function stripLeadingSlash (path) {
    return path.charAt(0) === "/" ? path.substr(1) : path;
}

function stripTrailingSlash (path) {
    return path.charAt(path.length - 1) === "/" ? path.slice(0, -1) : path;
}

const decodeHashURL = function () {
    let hashStr = getHashPath();
    hashStr = stripTrailingSlash(hashStr);
    return stripLeadingSlash(hashStr).split("/").map((hashValue) => decodeURIComponent(hashValue));
};

const encodeHashURL = function (hashParams = []) {
    hashParams = hashParams.map((hashValue) => encodeURIComponent(hashValue));

    return hashParams.join("/");
};

const hash = "policyId/app/menu";
const HASH_CHANGE_EVENT = "hashchange";
class Router extends Events {
    state = [];

    routeParams = {};

    defaultRoute = "";

    pushSet = new Set();

    replaceSet = new Set();

    constructor (props = {}) {
        super();
        this.defaultRoute = props.route || hash;
        window.addEventListener(HASH_CHANGE_EVENT, this.handleHashChange, false);
    }

    getParams = () => {
        const params = decodeHashURL();
        const hashMap = this.defaultRoute.split("/");
        const p = {};
        hashMap.forEach((hsh, index) => {
            if (params.length >= index) {
                if (index === hashMap.length - 1) {
                    p[hsh] = params.slice(index).join("/");
                } else {
                    p[hsh] = params[index];
                }
            }
        });
        return p;
    };

    setDefaultRoutePath = (route) => {
        this.defaultRoute = route;
    };

    handleHashChange = (event) => {
        // ../../../custom-events/lib/js/init.js
        const href = event.newURL;
        const hashIndex = href.indexOf("#");
        const currentHash = hashIndex === -1 ? "" : href.substring(hashIndex + 1);
        if (this.pushSet.has(currentHash)) {
            this.pushSet.delete(currentHash);
            this.triggerEachAsync("push");
        } else if (this.replaceSet.has(currentHash)) {
            this.replaceSet.delete(currentHash);
            this.triggerEachAsync("replace");
        } else {
            this.trigger("HashChanged", this.getParams());
        }
    };

    push = (hashParams) => {
        const currentPath = getHashPath();
        const newPath = encodeHashURL(hashParams);
        if (newPath !== currentPath) {
            this.pushSet.add(newPath);
            pushHashPath(newPath);
        }
    };

    replace = (hashParams) => {
        const newPath = encodeHashURL(hashParams);
        this.replaceSet.add(newPath);
        replaceHashPath(newPath);
    };
}

const RouterInstance = new Router();

export { RouterInstance as default };

Firefox版本:150.0.2。Mac 64位

解决方案

据Gemini(下文引用),这是Firefox的自然行为。尽管你也可以 scrollTo 直接滚动到页面的片段;但如果坚持走URL的方式,可以使用 preventDefault

关键行为怪癖——同值重载: 与Chrome或 Safari不同,在Firefox中,将location.hash = location.hash会强制页面重新加载或滚回到锚点,即使哈希字符串保持相同。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章