标签 js 下的文章

JavaScript 页面加载与卸载相关事件

适用范围事件触发时机适用场景特性/注意点
windowload页面所有资源(HTML、图片、样式等)加载完成需要确保所有资源加载后再执行逻辑DOMContentLoaded 晚,等待资源加载
beforeunload页面即将卸载时(导航到新页面或关闭标签)提示用户保存数据或防止意外离开可显示离开确认对话框,设置 event.returnValue
unload页面完全卸载时(文档和资源从内存中清除)清理资源(如 WebSocket 连接、定时器等)现代浏览器限制较多,无法异步执行逻辑
focus/blur页面获得或失去焦点时触发检测用户切换到其他窗口或标签页可结合 document.hidden 检测可见性变化
documentDOMContentLoadedHTML 完全解析完成,资源(图片、样式表等)未必加载完成操作 DOM 元素,不依赖资源加载load 更早触发,常用于脚本初始化
readystatechangedocument.readyState 改变时触发,包括 loadinginteractivecomplete监控页面加载状态适合实时监控文档解析和加载的不同阶段
visibilitychange页面的可见性状态改变(如切换标签、最小化窗口)检测页面切换状态,节省资源或暂停功能状态通过 document.hiddenvisibilityState 获取
Chrome 插件 Content Scriptrun_at: "document_start"页面开始加载时(HTML 解析前)插入代码以修改页面的初始状态不适合操作 DOM,适合拦截初始 HTML
run_at: "document_end"HTML 完全解析完成(等同于 DOMContentLoaded操作已解析的 DOM,初始化插件逻辑脚本逻辑不会等待资源加载
run_at: "document_idle"HTML 解析完成,大部分资源已加载(页面处于空闲时运行)插件的默认运行时机,适用于大部分场景保证 DOM 和大部分资源已准备好
window 或特定元素error资源加载失败时(如图片、脚本、样式表)捕获资源加载错误或执行失败的脚本可在 window 或特定元素(如图片)上监听

(function () {
    const originalOpen = XMLHttpRequest.prototype.open;
    const originalSend = XMLHttpRequest.prototype.send;
    const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
let urls = ['api/user']

    XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
        this._method = method;
        this._url = url;
        this._async = async;
        originalOpen.apply(this, arguments);
    };

    XMLHttpRequest.prototype.setRequestHeader = function (header, value) {
        // 调用原始的 setRequestHeader 方法,而不是重写后的方法
        originalSetRequestHeader.call(this, header, value);
    };

    XMLHttpRequest.prototype.send = function (body) {
        const xhr = this;

        // 监听 `readystatechange` 事件
        xhr.addEventListener("readystatechange", function () {
            if (xhr.readyState === 3 && urls.filter(u=>xhr._url.includes(u)).length>0) {
                try {
                    // 拦截并修改响应数据
                    const originalResponse = xhr.responseText;


                    const jsonResponse = JSON.parse(originalResponse);
                                        console.log("原始响应数据:", jsonResponse);
if (jsonResponse && jsonResponse.data && jsonResponse.data.adInfos) {
                        jsonResponse.data.adInfos.forEach((order) => {
                            order.modified = true;
                            if (order.bid) order.bid = `${Number(order.bid) * 1.2}`;
                            if (order.ecpRoiGoal) order.ecpRoiGoal = order.ecpRoiGoal * 0.8;
                        });

                        const modifiedResponse = JSON.stringify(jsonResponse);

                        console.log("修改后的响应数据:", jsonResponse);

                        // 重新定义 responseText,确保页面访问的是修改后的数据
                        Object.defineProperty(xhr, "responseText", {
                            get: function () {
                                return modifiedResponse;
                            },
                        });
                    }
                } catch (error) {
                    console.error("解析或修改响应数据时出错:", error);
                }
            }
        });

        // 调用原始 send 方法
        originalSend.apply(this, arguments);
    };
})();

fetch

(function () {
    const originalXMLHttpRequest = window.XMLHttpRequest;

    function CustomXMLHttpRequest() {
        this._method = null;
        this._url = null;
        this._headers = {};
        this._body = null;
        this.readyState = 0;
        this.status = 0;
        this.statusText = '';
        this.responseText = '';
        this.response = null;

        // 模拟事件处理器
        this.onreadystatechange = null;
    }

    // 模拟 XMLHttpRequest 的 open 方法
    CustomXMLHttpRequest.prototype.open = function (method, url, async, user, password) {
        this._method = method;
        this._url = url;
        this._async = async;
        this.readyState = 1; // 状态变为 OPENED
        if (this.onreadystatechange) {
            this.onreadystatechange();
        }
    };

    // 模拟 XMLHttpRequest 的 setRequestHeader 方法
    CustomXMLHttpRequest.prototype.setRequestHeader = function (header, value) {
        this._headers[header] = value;
    };

    // 模拟 XMLHttpRequest 的 send 方法
    CustomXMLHttpRequest.prototype.send = async function (body) {
        this._body = body;

        const fetchOptions = {
            method: this._method,
            headers: this._headers,
            body: ["GET", "HEAD"].includes(this._method.toUpperCase()) ? undefined : body, // 确保 GET/HEAD 无 body
        };

        try {
            const response = await fetch(this._url, fetchOptions);
            const clonedResponse = response.clone();

            // 解析响应数据
            let text = await clonedResponse.text();

            // 修改响应数据(根据实际需求)
            if (urls.filter(u=>this._url.includes(u)).length>0) {
                const jsonResponse = JSON.parse(text);
                console.log('修改获取列表之前', jsonResponse)
                jsonResponse.data.adInfos.forEach((order) => {
                    order.modified = true;
                    if (order.bid) order.bid = `${Number(order.bid) * 1.2}`;
                    if (order.ecpRoiGoal) order.ecpRoiGoal = order.ecpRoiGoal * 1.2;
                });
                // jsonResponse.data.adInfos = []
                text = JSON.stringify(jsonResponse);
                console.log('修改获取列表之后', jsonResponse)
                // text = 1111111
            }

            // 模拟响应
            this.responseText = text;
            this.response = text;
            this.status = clonedResponse.status;
            this.statusText = clonedResponse.statusText;
            this.readyState = 4;

            if (this.onreadystatechange) {
                this.onreadystatechange();
            }
        } catch (error) {
            console.error("Fetch 请求失败:", error);
            this.readyState = 4;
            this.status = 500;
            this.statusText = 'Internal Server Error';
            if (this.onreadystatechange) {
                this.onreadystatechange();
            }
        }
    };

    // 替换原生 XMLHttpRequest
    window.XMLHttpRequest = CustomXMLHttpRequest;
})();

let urls = ['api/user']

node 调用powershell

const {exec} = require("child_process");

const printByPowerShell = (filePath, printerName) => {
    const command = `Get-Content "${filePath}" | Out-Printer -Name "${printerName}"`;

    exec(`powershell.exe -Command "${command}"`, (error, stdout, stderr) => {
        if (error) {
            console.error(`Error executing command: ${error.message}`);
            return;
        }
        if (stderr) {
            console.error(`PowerShell Error: ${stderr}`);
            return;
        }
        console.log(`Output: ${stdout}`);
    });

}

module.exports = {
    printByPowerShell
}


// 监听 URL 变化
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
let lastUrl = window.location.href;

function handleUrlChange() {
  if (lastUrl !== window.location.href) {
    console.log("URL 发生变化:", window.location.href);
    window.location.reload();
  }
}

// 重写 pushState 和 replaceState 以监听 URL 改变
history.pushState = function (...args) {
  originalPushState.apply(history, args);
  handleUrlChange();
};

history.replaceState = function (...args) {
  originalReplaceState.apply(history, args);
  handleUrlChange();
};

// 监听浏览器的 popstate 事件(即用户通过浏览器的后退/前进按钮改变 URL)
window.addEventListener("popstate", handleUrlChange);