Google
、Bing
、Baidu
popup.html
设置,黑暗模式,新开页面按钮popup.html
,所以创建部分目录。my-new-tab/
├── images/ # 存放静态资源,如图片、字体等
│ ├── download.svg
│ ├── icon16.png
│ ├── icon48.png
│ ├── icon128.png
├── css/ # 页面样式
│ ├── clock.css # 时间样式
│ ├── newtab.css # 标签页样式
│ ├── popup.css # 弹出页样式
├── js/ # 页面脚本
│ ├── clock.js # 时间脚本
│ ├── newtab.js # 标签页脚本
│ ├── popup.js # 弹出页脚本
├── background.js # 后台管理脚本(移动到 js 目录)
├── manifest.json # Chrome 扩展基础配置文件
├── newtab.html # 新标签页内容
└── popup.html # 弹出页内容
newtab.html
添加内容 <div id="search-container">
<select id="search-engine">
<option value="https://www.google.com/search?q=">Google</option>
<option value="https://www.bing.com/search?q=">Bing</option>
<option value="https://www.baidu.com/s?wd=">百度</option>
</select>
<input type="text" id="search-box" placeholder="输入关键字搜索">
<button id="search-btn">搜索</button>
</div>
newtab.css
添加内容#search-container {
margin: 80px 0 0 0;
top: 150px;
display: flex;
gap: 0;
background: rgba(255, 255, 255, 0.7);
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
width: 650px;
}
#search-engine {
height: 45px;
padding: 0 20px;
border: none;
background: transparent;
font-size: 14px;
color: rgba(0, 0, 0, 0.9);
cursor: pointer;
}
#search-box {
flex: 1;
height: 45px;
padding: 0 15px;
border: none;
background: transparent;
font-size: 14px;
color: rgba(0, 0, 0, 0.9);
}
#search-box:focus {
outline: none;
box-shadow: none;
}
#search-btn {
width: 100px;
height: 45px;
padding: 0 25px;
/* background: linear-gradient(135deg, #4a90e2, #357abd); */
background: #409eff;
border: none;
color: white;
font-size: 15px;
cursor: pointer;
transition: all 0.3s ease;
}
/* 统一交互效果 */
#search-engine:hover,
#search-box:hover {
background-color: rgba(74, 144, 226, 0.05);
}
#search-btn:hover {
background: #357abd;
}
#search-container:focus-within {
box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.3);
}
#search-engine option {
color: black;
/* color: white; */
}
/* 移动端适配 */
@media (max-width: 480px) {
#search-container {
width: calc(100% - 40px);
left: 20px;
}
#search-engine {
padding-right: 30px;
background-position: right 8px center;
}
}
newtab.js
内容document.getElementById("search-btn").addEventListener("click", function () {
const engine = document.getElementById("search-engine").value;
const query = document.getElementById("search-box").value.trim();
if (query) {
window.location.href = engine + encodeURIComponent(query);
}
});
document.getElementById("search-box").addEventListener("keypress", function (event) {
if (event.key === "Enter") {
document.getElementById("search-btn").click();
}
});
newtab.html
添加时间内容,分为时间、日期 <div id="time"></div>
<div id="date"></div>
newtab.css
创建时间样式#time {
margin-top: 20px;
font-size: 48px;
color: rgba(255, 255, 255, 0.8);
}
#date {
font-size: 22px;
color: rgba(255, 255, 255, 0.8);
}
newtab.js
function updateClock() {
var date = new Date();
// 年、月、日
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
// 时、分、秒
var hour = date.getHours();
var minute = date.getMinutes();
var second = date.getSeconds();
// 格式化时间为两位数
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute : minute;
second = second < 10 ? '0' + second : second;
// 获取星期几
var weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var weekDay = weekDays[date.getDay()];
// 实时显示
var element = document.getElementById('time');
element.innerHTML = hour + ':' + minute + ':' + second;
var dateElement = document.getElementById('date');
dateElement.innerHTML = year + '年' + month + '月' + day + '日 ' + weekDay;
}
// 每秒更新一次时间
setInterval(updateClock, 1000);
// 初始化显示时间
updateClock();
background.js
更新,发起请求
// 天气请求参数
const apiKey = "key"; // 你的API Key
const city = "110000"; // 北京 adcode
const cacheKey = "weather_cache";
const updateInterval = 30 * 60 * 1000; // 30分钟
// 天气请求
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
...
if (request.action === "getWeather") {
chrome.storage.local.get(cacheKey, (result) => {
const cachedData = result[cacheKey];
if (cachedData && (Date.now() - cachedData.updateTime < updateInterval)) {
sendResponse(cachedData);
} else {
fetchWeather();
setTimeout(() => {
chrome.storage.local.get(cacheKey, (newResult) => {
sendResponse(newResult[cacheKey] || { error: "数据获取失败" });
});
}, 2000); // 给 API 一点时间返回数据
}
});
return true; // 表示 sendResponse 是异步的
}
...
});
function fetchWeather() {
const url = `https://restapi.amap.com/v3/weather/weatherInfo?key=${apiKey}&city=${city}&extensions=base&output=json`;
fetch(url)
.then(response => response.json())
.then(data => {
if (data.status === "1") {
const weatherData = {
weather: data.lives[0].weather,
temperature: data.lives[0].temperature,
updateTime: Date.now()
};
chrome.storage.local.set({ [cacheKey]: weatherData });
}
})
.catch(() => {
console.error("天气请求失败");
});
}
// **定时更新天气**
setInterval(fetchWeather, updateInterval);
// fetchWeather(); // 立即执行一次
这里添加了请求方法fetchWeather()
,请求成功后设置缓存
设置了getWeather
方便新标签页调取
参数city
有城市编号,也可设置区号,这里放一下高德官方的地区编号文档。城市编码表
首页发起获取
newtab.html
<div id="weatherTitle">当前天气</div>
<div id="weatherInfo">加载中...</div>
newtab.js
发起添加请求并渲染
chrome.runtime.sendMessage({ action: "getWeather" }, (response) => {
if (response && !response.error) {
document.getElementById("weatherInfo").innerText =
`天气: ${response.weather}, 温度: ${response.temperature}°C`;
} else {
document.getElementById("weatherInfo").innerText = "获取天气失败";
}
});
newtab.css
#weatherTitle {
font-size: 16px;
margin-top: 10px;
color: rgba(255, 255, 255, 0.9);
}
font-size: 16px; margin-top: 10px; color: rgba(255, 255, 255, 0.9); }
这里使用了客观api,文档详细,大家可以自行查看随机一言api
这里就不用设置key了
background.js
更新,发起请求,设置缓存等
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
...
// 语录请求
if (request.action === "fetchQuote") { // 确保 action 名称正确
chrome.storage.local.get(quoteCacheKey, (result) => {
const cachedData = result[quoteCacheKey];
if (cachedData && Date.now() - cachedData.updateTime < cacheDuration) {
sendResponse({ quote: cachedData.quote });
} else {
fetchQuote().then(() => {
chrome.storage.local.get(quoteCacheKey, (newResult) => {
sendResponse(newResult[quoteCacheKey] || { error: "数据获取失败" });
});
});
}
});
return true; // 异步返回
}
...
});
function fetchQuote() {
fetch("https://api.keguan.org.cn/api/yiyan/api.php?type=json&c=i")
.then(response => response.json())
.then(data => {
const quoteData = {
quote: data, // API 返回的语录
updateTime: Date.now()
};
chrome.storage.local.set({ [quoteCacheKey]: quoteData });
})
.catch(() => {
console.error("语录请求失败");
});
}
// **定时更新语录**
setInterval(fetchQuote, cacheDuration);
// fetchQuote(); // 立即执行一次
fetchQuote()
,请求成功后设置缓存fetchQuote
方便新标签页调取首页发起获取
newtab.html
<div id="quote"></div>
newtab.js
// 如果你想添加动态内容,可以在这里做其他处理
// const quotes = [
// "生活就是不断的开始,又不断的结束。",
// "活在当下,珍惜每一刻。",
// "每天都是新的一天,充满新的希望。"
// ];
// document.getElementById('quote').innerText = quotes[Math.floor(Math.random() * quotes.length)];
chrome.runtime.sendMessage({ action: "fetchQuote" }, (response) => {
console.log(response);
if (response && !response.error) {
document.getElementById("quote").innerText = response.quote.text + " —— 《" + response.quote.from + "》";
} else {
document.getElementById("quote").innerText = "获取语录失败";
}
});
newtab.css
#quote {
font-size: 16px;
margin-top: 10px;
color: rgba(255, 255, 255, 0.9);
}
popup.html
设置,黑暗模式,新开页面按钮popup.html
配置内容popup.html
添加按钮,与黑夜模式开关。<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>新标签页扩展</title>
<link rel="stylesheet" href="/css/popup.css">
<script src="/js/popup.js" defer></script>
</head>
<body>
<label class="switch">
<input type="checkbox" id="toggleDarkMode">
<span class="slider"></span>
</label>
<span style="font-size: 15px;">黑暗模式</span>
<br>
<br>
<button id="openNewTab">打开新标签页</button>
</body>
</html>
popup.css
body {
width: 250px;
padding: 10px;
text-align: center;
}
button {
width: 75%;
padding: 10px;
margin-top: 10px;
border-radius: 5px;
background: #409eff;
color: white;
font-size: 15px;
border: none;
cursor: pointer;
}
/* 开关按钮样式 */
.switch {
position: relative;
display: inline-block;
width: 40px;
height: 20px;
margin-right: 10px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: 0.4s;
border-radius: 20px;
}
.slider:before {
position: absolute;
content: "";
height: 14px;
width: 14px;
left: 3px;
bottom: 3px;
background-color: white;
transition: 0.4s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #409eff;
}
input:checked+.slider:before {
transform: translateX(20px);
}
popup.js
document.getElementById("openNewTab").addEventListener("click", function () {
chrome.tabs.create({ url: "newtab.html" }); // 打开新标签页
});
chrome.storage.sync.get(["darkMode"], function (data) {
toggleDarkMode.checked = data.darkMode ?? false; // 默认关闭黑暗模式
if (toggleDarkMode.checked) {
document.body.classList.add("dark-mode");
}
});
// 监听用户开关(黑暗模式)
toggleDarkMode.addEventListener("change", function () {
chrome.storage.sync.set({ darkMode: toggleDarkMode.checked }, function () {
if (toggleDarkMode.checked) {
document.body.classList.add("dark-mode");
} else {
document.body.classList.remove("dark-mode");
}
});
});
黑暗模式添加后,添加部分样式
clock.css
.dark-mode #date {
color: rgba(0, 0, 0, 0.8);
}
.dark-mode #time {
color: rgba(0, 0, 0, 0.8);
}
newtab.css
.dark-mode #quote {
color: rgba(0, 0, 0, 0.9);
}
...
.dark-mode #weatherTitle {
color: rgba(0, 0, 0, 0.9);
}
.dark-mode #weatherInfo {
color: rgba(0, 0, 0, 0.9);
}
.dark-mode #search-container {
background: rgba(0, 0, 0, 0.7);
}
.dark-mode #search-engine {
color: rgba(255, 255, 255, 0.6);
}
.dark-mode #search-box {
color: rgba(255, 255, 255, 0.9);
}
.dark-mode #search-btn {
background: #357abd;
color: rgba(255, 255, 255, 0.8);
}