自定义导航网站(二)

上篇文章讲到了如何实现动态添加网页,这个功能和书签的功能差不多。

自定义导航网站可以比书签更好用一点,比如有一些经常访问的网站,前缀是一致的,URL 只是尾部略有不同。

举个不是很恰当的例子:使用百度搜索 test,点击搜索按钮后,打开的链接格式类似这样:https://www.baidu.com/s?wd=test。无论搜什么,前缀都是 https://www.baidu.com/s?wd=,只有尾部的搜索内容略有不同。

我们可以把这个前缀保存起来,在后面加个输入框,以后只用输入尾部的内容,点击回车就能打开前缀+输入内容拼接而成的链接了。

效果图

这个功能在实际工作中比较实用,比如切换不同的项目,或访问内网资源。考虑到项目的安全策略,所以本文以百度为例。

代码实现

本文基于上一篇文章的代码修改。

提取 pages.js

首先为了适当解耦,我们把脚本部分提到一个单独的 js 文件中,命名为 pages.js:

js 复制代码
// Load links when the page loads
loadLinks();
// Function to load links from localStorage
function loadLinks() {
    const savedPages = JSON.parse(localStorage.getItem('savedPages'));
    const linksList = document.getElementById('linksList');

    if (savedPages && savedPages.length > 0) {
        linksList.innerHTML = '';
        savedPages.forEach(page => {
            const listItem = document.createElement('li');

            const nameElement = document.createElement('span');
            nameElement.textContent = page.name;
            nameElement.style.cursor = 'pointer';
            nameElement.onclick = function (event) {
                event.stopPropagation();
                openPage(page.link);
            };

            const deleteButton = document.createElement('button');
            deleteButton.textContent = 'Delete';
            deleteButton.onclick = function (event) {
                event.stopPropagation();
                deletePage(page);
            };

            listItem.appendChild(nameElement);
            listItem.appendChild(deleteButton);
            linksList.appendChild(listItem);
        });
    } else {
        linksList.innerHTML = '<li>No saved pages</li>';
    }
}

// Function to delete a page
function deletePage(page) {
    const savedPages = JSON.parse(localStorage.getItem('savedPages'));
    const updatedPages = savedPages.filter(p => p.name !== page.name);
    localStorage.setItem('savedPages', JSON.stringify(updatedPages));
    loadLinks();
}

// Function to open a page in a new tab
function openPage(link) {
    window.open(link, '_blank');
}

// Function to handle form submission
document.getElementById('addPageForm').addEventListener('submit', function (event) {
    event.preventDefault();

    const pageName = document.getElementById('pageName').value;
    const pageLink = document.getElementById('pageLink').value;

    if (pageName && pageLink) {
        const savedPages = JSON.parse(localStorage.getItem('savedPages')) || [];
        savedPages.push({ name: pageName, link: pageLink });
        localStorage.setItem('savedPages', JSON.stringify(savedPages));

        loadLinks();

        // Reset form fields
        document.getElementById('pageName').value = '';
        document.getElementById('pageLink').value = '';
    } else {
        console.error('Page name and link are required.');
    }
});

// Function to clear all pages
function clearAll() {
    localStorage.removeItem('savedPages');
    loadLinks();
}

// Function to export all pages to a file
function exportAll() {
    const savedPages = JSON.parse(localStorage.getItem('savedPages'));

    if (savedPages && savedPages.length > 0) {
        const savedPagesJSON = JSON.stringify(savedPages, null, 4);
        const blob = new Blob([savedPagesJSON], { type: 'application/json' });
        const a = document.createElement('a');
        a.href = URL.createObjectURL(blob);
        a.download = 'savedPages.json';
        a.click();
    } else {
        console.error('No saved pages found.');
    }
}

// Function to handle file import
function importFile() {
    const fileInput = document.getElementById('fileInput');
    const file = fileInput.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function (event) {
            const importedPages = JSON.parse(event.target.result);
            if (Array.isArray(importedPages)) {
                const savedPages = JSON.parse(localStorage.getItem('savedPages')) || [];
                const updatedPages = savedPages.concat(importedPages);
                localStorage.setItem('savedPages', JSON.stringify(updatedPages));
                loadLinks();
                // Clear file input value
                fileInput.value = '';
            } else {
                console.error('Invalid JSON format.');
            }
        };
        reader.readAsText(file);
    } else {
        console.error('No file selected.');
    }
}

仿写 custom_links.js

照猫画虎,再写一个 custom_links.js 文件,实现添加前缀,删除前缀,展示前缀,清空/导入/导出前缀:

js 复制代码
// Load custom links when the page loads
loadCustomLinks();
// Function to load custom links from localStorage
function loadCustomLinks() {
    const customSavedCustomPages = JSON.parse(localStorage.getItem('savedCustomPages'));
    const customLinksList = document.getElementById('customLinksList');

    if (customSavedCustomPages && customSavedCustomPages.length > 0) {
        customLinksList.innerHTML = '';
        customSavedCustomPages.forEach(page => {
            const listItem = document.createElement('li');

            const nameElement = document.createElement('span');
            nameElement.textContent = page.name;
            nameElement.style.cursor = 'pointer';
            nameElement.onclick = function (event) {
                event.stopPropagation();
                openCustomPage(page.link);
            };

            const input = document.createElement('input');
            input.onkeydown = function (event) {
                if (event.key === 'Enter') {
                    openCustomPage(page.link + input.value);
                }
            }

            const deleteButton = document.createElement('button');
            deleteButton.textContent = 'Delete';
            deleteButton.onclick = function (event) {
                event.stopPropagation();
                deleteCustomPage(page);
            };

            listItem.appendChild(nameElement);
            listItem.appendChild(input);
            listItem.appendChild(deleteButton);
            customLinksList.appendChild(listItem);
        });
    } else {
        customLinksList.innerHTML = '<li>No saved pages</li>';
    }
}

// Function to delete a page
function deleteCustomPage(page) {
    const savedCustomPages = JSON.parse(localStorage.getItem('savedCustomPages'));
    const updatedPages = savedCustomPages.filter(p => p.name !== page.name);
    localStorage.setItem('savedCustomPages', JSON.stringify(updatedPages));
    loadCustomLinks();
}

// Function to open a page in a new tab
function openCustomPage(link) {
    window.open(link, '_blank');
}

// Function to handle form submission
document.getElementById('addCustomPageForm').addEventListener('submit', function (event) {
    event.preventDefault();

    const customPageName = document.getElementById('customPageName').value;
    const pagePrefix = document.getElementById('pagePrefix').value;

    if (customPageName && pagePrefix) {
        const savedCustomPages = JSON.parse(localStorage.getItem('savedCustomPages')) || [];
        savedCustomPages.push({ name: customPageName, link: pagePrefix });
        localStorage.setItem('savedCustomPages', JSON.stringify(savedCustomPages));

        loadCustomLinks();

        // Reset form fields
        document.getElementById('customPageName').value = '';
        document.getElementById('pagePrefix').value = '';
    } else {
        console.error('Page name and link are required.');
    }
});

// Function to clear all pages
function clearAllCustomPages() {
    localStorage.removeItem('savedCustomPages');
    loadCustomLinks();
}

// Function to export all pages to a file
function exportAllCustomPages() {
    const savedCustomPages = JSON.parse(localStorage.getItem('savedCustomPages'));

    if (savedCustomPages && savedCustomPages.length > 0) {
        const savedCustomPagesJSON = JSON.stringify(savedCustomPages, null, 4);
        const blob = new Blob([savedCustomPagesJSON], { type: 'application/json' });
        const a = document.createElement('a');
        a.href = URL.createObjectURL(blob);
        a.download = 'savedCustomPages.json';
        a.click();
    } else {
        console.error('No saved pages found.');
    }
}

// Function to handle file import
function importCustomPagesFile() {
    const customFileInput = document.getElementById('customFileInput');
    const file = customFileInput.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function (event) {
            const importedPages = JSON.parse(event.target.result);
            if (Array.isArray(importedPages)) {
                const savedCustomPages = JSON.parse(localStorage.getItem('savedCustomPages')) || [];
                const updatedPages = savedCustomPages.concat(importedPages);
                localStorage.setItem('savedCustomPages', JSON.stringify(updatedPages));
                loadCustomLinks();
                // Clear file input value
                customFileInput.value = '';
            } else {
                console.error('Invalid JSON format.');
            }
        };
        reader.readAsText(file);
    } else {
        console.error('No file selected.');
    }
}

引用两个 js 文件

然后在 html 文件中(不妨将其命名为 navigation.html),再抄一份表单,引用前两个 js 文件:

html 复制代码
<!DOCTYPE html>
<html lang="en">

</html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Navigation</title>
</head>

<body>
    <h1>Web Navigation</h1>
    <form id="addPageForm">
        <label for="pageName">Page Name:</label>
        <input type="text" id="pageName" name="pageName" required>
        <label for="pageLink">Page Link:</label>
        <input type="url" id="pageLink" name="pageLink" required>
        <button type="submit">Submit</button>
    </form>
    <h2>Saved Pages</h2>
    <ul id="linksList">
        <!-- Links will be dynamically added here -->
    </ul>
    <button onclick="clearAll()">Clear All</button>
    <button onclick="exportAll()">Export All</button><br><br>
    <input type="file" id="fileInput">
    <button onclick="importFile()">Import</button>

    <hr>

    <h2>Add Custom Link</h2>
    <form id="addCustomPageForm">
        <label for="customPageName">Page Name:</label>
        <input type="text" id="customPageName" name="customPageName" required>
        <label for="pagePrefix">Page Prefix:</label>
        <input type="text" id="pagePrefix" name="pagePrefix" required>
        <button type="submit">Submit</button>
    </form>
    <h2>Saved Pages</h2>
    <ul id="customLinksList">
        <!-- Links will be dynamically added here -->
    </ul>
    <button onclick="clearAllCustomPages()">Clear All</button>
    <button onclick="exportAllCustomPages()">Export All</button><br><br>
    <input type="file" id="customFileInput">
    <button onclick="importCustomPagesFile()">Import</button>

    <script src="pages.js"></script>
    <script src="custom_links.js"></script>


</body>

这样就实现了自定义链接前缀的功能。

完整代码已上传至 github:github.com/KevinWangJc...

相关推荐
非著名架构师1 小时前
js混淆的方式方法
开发语言·javascript·ecmascript
多多米10052 小时前
初学Vue(2)
前端·javascript·vue.js
敏编程2 小时前
网页前端开发之Javascript入门篇(5/9):函数
开发语言·javascript
柏箱2 小时前
PHP基本语法总结
开发语言·前端·html·php
看到请催我学习2 小时前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
XiaoYu20024 小时前
22.JS高级-ES6之Symbol类型与Set、Map数据结构
前端·javascript·代码规范
儒雅的烤地瓜4 小时前
JS | JS中判断数组的6种方法,你知道几个?
javascript·instanceof·判断数组·数组方法·isarray·isprototypeof
道爷我悟了4 小时前
Vue入门-指令学习-v-on
javascript·vue.js·学习
27669582924 小时前
京东e卡滑块 分析
java·javascript·python·node.js·go·滑块·京东
PleaSure乐事4 小时前
【Node.js】内置模块FileSystem的保姆级入门讲解
javascript·node.js·es6·filesystem