上篇文章讲到了如何实现动态添加网页,这个功能和书签的功能差不多。
自定义导航网站可以比书签更好用一点,比如有一些经常访问的网站,前缀是一致的,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...