给你的网站加上一个弹窗公告-科技分享社区-生态服务-丹洋社区

给你的网站加上一个弹窗公告

引用一个JS文件来实现任意页面弹窗公告,弹窗公告代码JS文件本地化可放心使用。

效果展示

20250919211822614-image

公告能够在不同设备自适应显示

实现方法

1.在网站目录创建文件 itjs.js ,并且粘贴以下代码到你刚刚创建的这个JS文件里面。

文件名称可以自定义,引用的时候只需要改成你自定义的文件名称即可,如果是小白就跟着教程走吧。

// 公告弹窗
(function () {
    function showAnnounce() {
        const lastClose = localStorage.getItem('announceLastClose');
        if (!lastClose) return true;
        const oneDayAgo = Date.now() - (24 * 60 * 60 * 1000);
        return new Date(lastClose).getTime() < oneDayAgo;
    }

    if (!showAnnounce()) return;

    const cfg = window.announceConfig || {
        title: "公告通知",
        items: [
            {
                icon: "news",
                title: "最新公告",
                content: "本平台新增多项安全验证功能,建议您及时完善个人信息。"
            },
            {
                icon: "update",
                title: "功能更新",
                content: "新版移动端已上线,支持离线模式和数据同步功能。"
            }
        ],
        noShowText: "一天内不再显示",
        laterText: "稍后提醒",
        okText: "我知道了",
        mainColor: "#3b82f6",
        maxW: "500px",
        z: 9999
    };

    function addStyles() {
        const style = document.createElement('style');
        style.textContent = `
            .announce-mask {
                position: fixed;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(0,0,0,0.5);
                z-index: ${cfg.z - 1};
                opacity: 0;
                visibility: hidden;
                transition: opacity 0.3s;
                backdrop-filter: blur(4px);
            }
            
            .announce-mask.show {
                opacity: 1;
                visibility: visible;
            }
            
            .announce-box {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%) scale(0.95);
                background: white;
                border-radius: 10px;
                max-width: ${cfg.maxW};
                width: calc(100% - 30px);
                box-shadow: 0 5px 20px rgba(0,0,0,0.1);
                z-index: ${cfg.z};
                overflow: hidden;
                opacity: 0;
                visibility: hidden;
                transition: all 0.3s;
            }
            
            .announce-box.show {
                opacity: 1;
                visibility: visible;
                transform: translate(-50%, -50%) scale(1);
            }
            
            .announce-head {
                background: ${cfg.mainColor};
                color: white;
                padding: 15px 20px;
                display: flex;
                align-items: center;
                justify-content: space-between;
            }
            
            .announce-title {
                margin: 0;
                font-size: 1.2rem;
                display: flex;
                align-items: center;
                gap: 10px;
            }
            
            .announce-close {
                background: none;
                border: none;
                color: white;
                font-size: 1.5rem;
                cursor: pointer;
                width: 30px;
                height: 30px;
                display: flex;
                align-items: center;
                justify-content: center;
                border-radius: 50%;
            }
            
            .announce-close:hover {
                background: rgba(255,255,255,0.2);
            }
            
            .announce-body {
                padding: 20px;
            }
            
            .announce-list {
                margin: 0;
                padding: 0;
                list-style: none;
            }
            
            .announce-item {
                display: flex;
                gap: 12px;
                padding: 15px 0;
                border-bottom: 1px solid #f1f5f9;
            }
            
            .announce-item:last-child {
                border-bottom: none;
                padding-bottom: 0;
            }
            
            .announce-icon {
                width: 40px;
                height: 40px;
                border-radius: 8px;
                display: flex;
                align-items: center;
                justify-content: center;
                flex-shrink: 0;
            }
            
            .announce-icon.news {
                background: #e0f2fe;
            }
            
            .announce-icon.update {
                background: #e6f7ee;
            }
            
            .announce-icon svg {
                width: 20px;
                height: 20px;
            }
            
            .announce-icon.news svg {
                fill: #0284c7;
            }
            
            .announce-icon.update svg {
                fill: #059669;
            }
            
            .announce-text {
                flex: 1;
            }
            
            .announce-item-title {
                margin: 0 0 5px 0;
                font-size: 1rem;
                font-weight: 600;
                color: #1e293b;
            }
            
            .announce-item-desc {
                margin: 0;
                font-size: 0.9rem;
                color: #64748b;
                line-height: 1.5;
            }
            
            .announce-option {
                padding: 0 20px 15px;
            }
            
            .announce-check {
                display: flex;
                align-items: center;
                gap: 8px;
                cursor: pointer;
            }
            
            .announce-checkbox {
                width: 18px;
                height: 18px;
                accent-color: ${cfg.mainColor};
            }
            
            .announce-check-label {
                font-size: 0.9rem;
                color: #64748b;
            }
            
            .announce-foot {
                padding: 15px 20px;
                border-top: 1px solid #f1f5f9;
                display: flex;
                gap: 10px;
            }
            
            .announce-btn {
                padding: 9px 15px;
                border: none;
                border-radius: 6px;
                font-size: 0.9rem;
                cursor: pointer;
                flex: 1;
                transition: all 0.2s;
            }
            
            .announce-btn.later {
                background: #f1f5f9;
                color: #475569;
            }
            
            .announce-btn.later:hover {
                background: #e2e8f0;
            }
            
            .announce-btn.ok {
                background: ${cfg.mainColor};
                color: white;
            }
            
            .announce-btn.ok:hover {
                background: ${shadeColor(cfg.mainColor, -15)};
            }
            
            @media (max-width: 480px) {
                .announce-foot {
                    flex-direction: column;
                }
            }
        `;
        document.head.appendChild(style);
    }

    function shadeColor(color, percent) {
        let R = parseInt(color.substring(1, 3), 16);
        let G = parseInt(color.substring(3, 5), 16);
        let B = parseInt(color.substring(5, 7), 16);

        R = parseInt(R * (100 + percent) / 100);
        G = parseInt(G * (100 + percent) / 100);
        B = parseInt(B * (100 + percent) / 100);

        R = R < 255 ? R : 255;
        G = G < 255 ? G : 255;
        B = B < 255 ? B : 255;

        R = Math.round(R);
        G = Math.round(G);
        B = Math.round(B);

        const RR = (R.toString(16).length === 1) ? "0" + R.toString(16) : R.toString(16);
        const GG = (G.toString(16).length === 1) ? "0" + G.toString(16) : G.toString(16);
        const BB = (B.toString(16).length === 1) ? "0" + B.toString(16) : B.toString(16);

        return "#" + RR + GG + BB;
    }

    function closeAnnounce(mask, box, noShow) {
        mask.classList.remove('show');
        box.classList.remove('show');

        if (noShow) {
            localStorage.setItem('announceLastClose', new Date().toISOString());
        }

        setTimeout(() => {
            mask.remove();
            box.remove();
        }, 300);
    }

    function createItems(container) {
        const list = document.createElement('ul');
        list.className = 'announce-list';

        cfg.items.forEach(item => {
            const li = document.createElement('li');
            li.className = 'announce-item';

            const icon = document.createElement('div');
            icon.className = `announce-icon ${item.icon}`;

            let svg = '';
            if (item.icon === 'news') {
                svg = `
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                        <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zM7 7h5v5H7zm5 7H7v2h5zm2-4h2v2h-2zm0 4h2v2h-2z"/>
                    </svg>
                `;
            } else if (item.icon === 'update') {
                svg = `
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                        <path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8zm-2 8v3l4-4-4-4v3H6v2h4z"/>
                    </svg>
                `;
            }

            icon.innerHTML = svg;

            const text = document.createElement('div');
            text.className = 'announce-text';

            const title = document.createElement('h4');
            title.className = 'announce-item-title';
            title.textContent = item.title;

            const desc = document.createElement('p');
            desc.className = 'announce-item-desc';
            desc.textContent = item.content;

            text.appendChild(title);
            text.appendChild(desc);

            li.appendChild(icon);
            li.appendChild(text);
            list.appendChild(li);
        });

        container.appendChild(list);
    }

    function createAnnounce() {
        const mask = document.createElement('div');
        mask.className = 'announce-mask';

        const box = document.createElement('div');
        box.className = 'announce-box';

        const head = document.createElement('div');
        head.className = 'announce-head';

        const title = document.createElement('h3');
        title.className = 'announce-title';
        title.innerHTML = `
            <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
                <path d="M12 2c5.51 0 10 4.49 10 10s-4.49 10-10 10S2 17.51 2 12 6.49 2 12 2zm0 2c-4.41 0-8 3.59-8 8s3.59 8 8 8 8-3.59 8-8-3.59-8-8-8zm-1 3h2v6h-2zm0 8h2v2h-2z"/>
            </svg>
            ${cfg.title}
        `;

        const closeBtn = document.createElement('button');
        closeBtn.className = 'announce-close';
        closeBtn.textContent = '×';
        closeBtn.addEventListener('click', () => {
            closeAnnounce(mask, box, false);
        });

        head.appendChild(title);
        head.appendChild(closeBtn);

        const body = document.createElement('div');
        body.className = 'announce-body';
        createItems(body);

        const option = document.createElement('div');
        option.className = 'announce-option';

        const check = document.createElement('label');
        check.className = 'announce-check';

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.className = 'announce-checkbox';
        checkbox.id = 'noShow';

        const label = document.createElement('span');
        label.className = 'announce-check-label';
        label.textContent = cfg.noShowText;

        check.appendChild(checkbox);
        check.appendChild(label);
        option.appendChild(check);

        const foot = document.createElement('div');
        foot.className = 'announce-foot';

        const laterBtn = document.createElement('button');
        laterBtn.className = 'announce-btn later';
        laterBtn.textContent = cfg.laterText;
        laterBtn.addEventListener('click', () => {
            closeAnnounce(mask, box, false);
        });

        const okBtn = document.createElement('button');
        okBtn.className = 'announce-btn ok';
        okBtn.textContent = cfg.okText;
        okBtn.addEventListener('click', () => {
            closeAnnounce(mask, box, checkbox.checked);
        });

        foot.appendChild(laterBtn);
        foot.appendChild(okBtn);

        box.appendChild(head);
        box.appendChild(body);
        box.appendChild(option);
        box.appendChild(foot);

        document.body.appendChild(mask);
        document.body.appendChild(box);

        setTimeout(() => {
            mask.classList.add('show');
            box.classList.add('show');
        }, 100);

        mask.addEventListener('click', (e) => {
            if (e.target === mask) {
                closeAnnounce(mask, box, false);
            }
        });

        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') {
                closeAnnounce(mask, box, false);
            }
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            addStyles();
            createAnnounce();
        });
    } else {
        addStyles();
        createAnnounce();
    }
})();

 

图片[2]-给你的网站加上一个弹窗公告-科技分享社区-生态服务-丹洋社区

这里的文本按照你的需求进行更改,其中 icon 为图标名称,小白切勿随意修改,否则图标将无法正常显示。

2.在需要弹窗公告的页面加上以下代码即可实现弹窗公告功能。

一般加在主页,也可以加在全局文件实现全部页面弹出公告,具体根据你的实际需求。

<script src="itjs.js"></script>

!小白请注意:src后的路径根据实际情况调整!

关于这段代码放在页面哪里比较好:

1.body标签的末尾(推荐)

注意:不是body标签后面!在body标签里面,放在</body>标签前。

优点:此时页面 DOM 加载完成后再执行公告脚本,避免因 DOM 未就绪导致的问题,同时不阻塞页面渲染
缺点:公告弹窗会比放在head中稍晚出现

2.head标签内,配合defer属性

<script src="itjs.js" defer></script>

优点:提前加载脚本,但会等待 DOM 就绪后再执行,不阻塞页面渲染
缺点:需要浏览器支持defer属性(现代浏览器都支持)

 

3.head标签内,不使用任何属性(不推荐)
缺点:会阻塞页面渲染,直到脚本加载并执行完成,影响页面加载速度

综合考虑,推荐放在body标签末尾,这种方式既能保证脚本正常运行,又不会影响页面的加载性能,公告弹窗会在页面内容渲染完成后适时出现,给用户更好的体验。
如果希望公告尽可能早地出现,但又不影响页面加载,可以选择第二种方式(head中加defer)

代码说明

模块化设计:采用立即执行函数表达式 (IIFE) 封装,避免全局变量污染,内部功能划分清晰(样式添加、元素创建、事件处理等)

响应式设计:在移动设备上自动调整布局,支持点击遮罩层、关闭按钮、ESC 键等多种关闭方式。

样式隔离:公告代码通过独特的类名前缀(announce-)避免样式冲突。

有任何问题可在评论区说明,博主随时在线,若你实在不会操作可以联系博主为你操作(有偿)。

此代码由IT技术博客原创,转载请说明。

© 版权声明
请登录后发表评论

    没有回复内容