适用于via和雨见的浏览器主页

1905 字
10 分钟
适用于via和雨见的浏览器主页

logo html:

<script src="https://sdk.jinrishici.com/v2/browser/jinrishici.js" charset="utf-8"></script>
<div id="widget_wrapper">
<div id="poem_container" style="display: none;">
<div id="poem_sentence"></div>
<div id="poem_info"></div>
</div>
<div class="clock-container" id="clock_container" style="display: none;">
<div class="unit-group" id="hours">
<div class="flip-card">0</div><div class="flip-card">0</div>
</div>
<div class="separator">:</div>
<div class="unit-group" id="minutes">
<div class="flip-card">0</div><div class="flip-card">0</div>
</div>
<div class="separator">:</div>
<div class="unit-group" id="seconds">
<div class="flip-card">0</div><div class="flip-card">0</div>
</div>
</div>
</div>
<script>
(() => {
'use strict';
// ==========================================
// 【配置区】在这里修改您的设置
// ==========================================
const VIA_CONFIG = {
// 挂件类型:1 = 随机一言,2 = 今日诗词,3 = 翻页钟
widgetType: 3,
// 文字类挂件是否自动刷新(翻页钟无效)
autoRefresh: true,
// 刷新间隔(毫秒)
refreshInterval: 10000
};
const safeStorage = (() => {
try {
const testKey = '__via_test__';
localStorage.setItem(testKey, '1');
localStorage.removeItem(testKey);
return localStorage;
} catch (e) {
return {
getItem() { return null; },
setItem() {},
removeItem() {}
};
}
})();
const $ = (sel, root = document) => root.querySelector(sel);
const $$ = (sel, root = document) => root.querySelectorAll(sel);
document.addEventListener('DOMContentLoaded', () => {
const poemBox = $('#poem_container');
const clockBox = $('#clock_container');
const sentenceEl = $('#poem_sentence');
const infoEl = $('#poem_info');
// ==========================================
// 1. 挂件渲染逻辑
// ==========================================
if (VIA_CONFIG.widgetType === 1 || VIA_CONFIG.widgetType === 2) {
if (poemBox) poemBox.style.display = 'block';
const loadSentence = async () => {
try {
if (VIA_CONFIG.widgetType === 1) {
if (typeof fetch !== 'function') return;
const response = await fetch('https://v1.hitokoto.cn', { cache: 'no-store' });
if (!response.ok) return;
const data = await response.json();
if (sentenceEl) sentenceEl.innerHTML = data.hitokoto || '';
const author = data.from_who ? data.from_who + ' ' : '';
const source = data.from ? `《${data.from}》` : '';
if (infoEl) infoEl.innerHTML = (author || source) ? `—— ${author}${source}` : '';
} else {
if (typeof jinrishici === 'undefined' || !jinrishici.load) return;
jinrishici.load(result => {
try {
const data = result && result.data ? result.data : {};
const content = data.content || '';
const origin = data.origin || {};
if (sentenceEl) sentenceEl.innerHTML = content;
if (infoEl) {
infoEl.innerHTML = origin.title
? `—— [${origin.dynasty || ''}] · ${origin.author || ''}${origin.title}》`
: '';
}
} catch (e) {
console.error('今日诗词解析失败', e);
}
});
}
} catch (e) {
console.error('获取失败', e);
}
};
loadSentence();
if (VIA_CONFIG.autoRefresh) {
setInterval(loadSentence, Math.max(3000, VIA_CONFIG.refreshInterval || 10000));
}
} else if (VIA_CONFIG.widgetType === 3) {
// ==========================================
// 3. 翻页钟挂件
// ==========================================
if (clockBox) clockBox.style.display = 'inline-flex';
const unitCache = {
hours: $$('#hours .flip-card'),
minutes: $$('#minutes .flip-card'),
seconds: $$('#seconds .flip-card')
};
const lastValues = {
hours: '',
minutes: '',
seconds: ''
};
const updateUnit = (unitId, value) => {
const cards = unitCache[unitId];
if (!cards || cards.length < 2) return;
const strValue = String(value).padStart(2, '0');
if (lastValues[unitId] === strValue) return;
lastValues[unitId] = strValue;
for (let i = 0; i < 2; i++) {
const card = cards[i];
const num = strValue[i];
if (!card) continue;
if (card.innerText !== num) {
card.classList.remove('animate');
void card.offsetWidth;
card.innerText = num;
card.classList.add('animate');
}
}
};
const updateClock = () => {
const now = new Date();
updateUnit('hours', now.getHours());
updateUnit('minutes', now.getMinutes());
updateUnit('seconds', now.getSeconds());
};
updateClock();
setInterval(updateClock, 1000);
}
// ==========================================
// 2. 搜索框左侧切换搜索引擎逻辑
// ==========================================
const search_submit = $('#search_submit');
const search_input = $('#search_input');
if (!search_submit || !search_input) return;
const engines = {
i: { name: '默认', url: '' },
bd: { name: '百度', url: 'https://m.baidu.com/s?word=' },
gg: { name: '谷歌', url: 'https://www.google.com/search?q=' },
by: { name: '必应', url: 'https://cn.bing.com/search?q=' },
dd: { name: 'DuckGo', url: 'https://duckduckgo.com/?q=' },
// AI 类搜索
mt: { name: '秘塔', url: 'https://metaso.cn/?q=' },
km: { name: 'Kimi', url: 'https://kimi.moonshot.cn/' },
ai: { name: '文心一言', url: 'https://yiyan.baidu.com/' },
// 国内主流
gk: { name: '夸克', url: 'https://quark.sm.cn/s?q=' },
sg: { name: '搜狗', url: 'https://m.sogou.com/web/searchList.jsp?keyword=' },
hs: { name: '360', url: 'https://m.so.com/s?q=' },
sm: { name: '神马', url: 'https://yz.m.sm.cn/s?q=' },
// 垂直搜索
bb: { name: 'B站', url: 'https://m.bilibili.com/search?keyword=' },
bgm: { name: 'Bangumi', url: 'https://bangumi.tv/subject_search/' },
wb: { name: '微博', url: 'https://s.weibo.com/weibo/' },
tt: { name: '头条', url: 'https://so.toutiao.com/search?keyword=' },
zht: { name: '知乎', url: 'https://www.zhihu.com/search?type=content&q=' },
tb: { name: '贴吧', url: 'https://tieba.baidu.com/mo/q/hybrid/search?keyword=' },
// 国际/隐私向
yd: { name: 'Yandex', url: 'https://yandex.com/search/?text=' },
oh: { name: 'OceanHero', url: 'https://oceanhero.today/web?q=' }
};
let select = safeStorage.getItem('se') || 'i';
if (!engines[select]) select = 'i';
const switch_btn = document.createElement('button');
switch_btn.id = 'switch_btn';
switch_btn.type = 'button';
switch_btn.classList.add('url');
switch_btn.textContent = engines[select].name;
search_submit.parentElement.insertBefore(switch_btn, search_submit);
const switch_window = document.createElement('div');
switch_window.id = 'switch_window';
document.body.appendChild(switch_window);
const renderEngines = () => {
switch_window.innerHTML = Object.keys(engines).map(key => {
const isHidden = (key === 'm' && (!safeStorage.getItem('c') || select !== 'c')) ? 'style="display:none;"' : '';
return `<div class="url switch_engine ${key === select ? 'active' : ''}" data-key="${key}" ${isHidden}>${engines[key].name}</div>`;
}).join('');
};
renderEngines();
let layoutCache = null;
let barCache = null;
let rootCache = null;
let updateLayoutTimer = null;
const use_bar = () => {
const search_bar = barCache || $('.search_bar');
if (!search_bar) return;
barCache = search_bar;
const barStyle = window.getComputedStyle(search_bar);
const barRadius = barStyle.getPropertyValue('border-radius') || '15px';
const topRadius = Math.max(parseFloat(barRadius.split(' ')[0]) || 0, 5);
switch_btn.style.borderRadius = (topRadius - 2) + 'px';
const now = Date.now();
if (!layoutCache || now - layoutCache.timestamp > 100) {
const root = rootCache || getComputedStyle(document.documentElement);
rootCache = root;
const barRect = search_bar.getBoundingClientRect();
const btnRect = switch_btn.getBoundingClientRect();
layoutCache = {
timestamp: now,
engine_num: parseInt(root.getPropertyValue('--engine_num').trim() || '6', 10),
bar_width: search_bar.offsetWidth,
bar_left: barRect.left + window.scrollX,
bar_top: barRect.top + window.scrollY,
bar_height: barRect.height,
btn_left: btnRect.left + window.scrollX
};
}
const top_position = (layoutCache.bar_top + layoutCache.bar_height + 5) + 'px';
if (layoutCache.engine_num > 4) {
Object.assign(switch_window.style, {
width: layoutCache.bar_width + 'px',
left: layoutCache.bar_left + 'px',
transform: 'none',
top: top_position
});
} else {
Object.assign(switch_window.style, {
left: (layoutCache.btn_left - 6) + 'px',
transform: 'none',
width: 'auto',
top: top_position
});
}
};
use_bar();
window.addEventListener('resize', () => {
clearTimeout(updateLayoutTimer);
updateLayoutTimer = setTimeout(use_bar, 200);
}, { passive: true });
switch_btn.addEventListener('click', e => {
e.stopPropagation();
e.preventDefault();
const isActive = switch_btn.classList.contains('active');
switch_btn.classList.toggle('active', !isActive);
switch_window.classList.toggle('active', !isActive);
use_bar();
});
switch_window.addEventListener('click', e => {
const target = e.target;
if (!target.classList.contains('switch_engine')) return;
let new_key = target.dataset.key;
if (new_key === 'c' || new_key === 'm') {
let customUrl = prompt('请修改自定义地址\n注:取消可能会清空(′⊙ω⊙`)', safeStorage.getItem('c') || '');
customUrl = (customUrl || '').trim();
if (!customUrl) {
new_key = 'i';
} else {
safeStorage.setItem('c', customUrl);
engines.c.url = customUrl;
new_key = 'c';
}
select = new_key;
renderEngines();
}
safeStorage.setItem('se', new_key);
select = new_key;
switch_btn.textContent = engines[new_key].name;
$$('.switch_engine', switch_window).forEach(el => {
el.classList.toggle('active', el.dataset.key === new_key);
});
[switch_btn, switch_window].forEach(el => el.classList.remove('active'));
});
document.addEventListener('click', e => {
if (!switch_btn.contains(e.target) && !switch_window.contains(e.target)) {
[switch_btn, switch_window].forEach(el => el.classList.remove('active'));
}
}, { passive: true });
// ==========================================
// 3. 修复后的搜索逻辑
// 兼容 VIA 原搜索按钮/表单提交机制
// ==========================================
const originalSearch = (typeof window.search === 'function') ? window.search.bind(window) : null;
const buildSearchValue = (engineUrl, inputVal) => {
if (!engineUrl) return inputVal;
return /%[sS@]/.test(engineUrl)
? engineUrl.replace(/%[sS@]/g, inputVal)
: engineUrl + inputVal;
};
window.search = () => {
const input_val = search_input.value.trim();
if (!input_val) return false;
const current = safeStorage.getItem('se') || 'i';
const engine_url = current === 'c' ? (safeStorage.getItem('c') || '') : (engines[current]?.url || '');
let finalValue = input_val;
if (current !== 'i' && engine_url) {
finalValue = buildSearchValue(engine_url, input_val);
} else if (engine_url) {
finalValue = engine_url + input_val;
}
search_input.value = finalValue;
if (originalSearch) {
try {
return originalSearch();
} catch (e) {
console.warn('原搜索函数调用失败,尝试表单提交', e);
}
}
const form = search_input.form;
if (form) {
if (typeof form.requestSubmit === 'function') {
form.requestSubmit();
} else {
form.submit();
}
}
return false;
};
});
})();
</script>

自定义css:

:root {
/* 每行搜索引擎数量 */
--engine_num: 6;
/* 窗口最大高度 */
--max_height: 38vh;
}
body {
background-position: top center;
background-size: 100% auto;
}
/* ============================ */
/* 全局挂件容器样式 */
/* ============================ */
#widget_wrapper {
text-align: center;
margin: 0 auto 15px auto;
width: 85%;
max-width: 400px;
}
/* 挂件通用动画 */
@keyframes poem-fade-in {
0% { opacity: 0; transform: translateY(-10px); }
100% { opacity: 1; transform: translateY(0); }
}
/* ============================ */
/* 形态 1/2: 诗词一言 UI 样式 */
/* ============================ */
#poem_container {
color: #ffffff;
font-family: "PingFang SC Round", "Yuanti SC", "YouYuan", "Microsoft YaHei UI Rounded", sans-serif;
text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4);
animation: poem-fade-in 1s ease-out;
}
#poem_sentence {
font-size: 20px;
font-weight: 560;
letter-spacing: 1px;
margin-bottom: 6px;
line-height: 1.4;
}
#poem_info {
font-size: 13px;
font-weight: 400;
opacity: 0.85;
letter-spacing: 0.5px;
}
/* ============================ */
/* 形态 3: 翻页钟 UI 样式 */
/* ============================ */
.clock-container {
border-radius: 15px;
align-items: center;
gap: 8px;
animation: poem-fade-in 1s ease-out;
}
.unit-group {
display: flex;
gap: 3px;
}
.flip-card {
position: relative;
width: 36px;
height: 54px;
line-height: 54px;
background-color: rgba(40, 40, 40, 0.7);
backdrop-filter: blur(5px);
border-radius: 6px;
font-size: 32px;
font-weight: bold;
color: #fff;
text-align: center;
font-family: sans-serif;
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
}
.flip-card::after {
content: "";
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 1px;
background: rgba(0, 0, 0, 0.5);
z-index: 5;
}
.separator {
color: #fff;
font-size: 24px;
font-weight: bold;
padding-bottom: 5px;
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
}
.animate {
animation: flip 0.3s ease-in-out;
}
@keyframes flip {
0% { transform: scaleY(1); }
50% { transform: scaleY(0.4); opacity: 0.8; }
100% { transform: scaleY(1); }
}
/* ============================ */
/* 搜索引擎切换按钮及弹窗样式 */
/* ============================ */
#switch_btn, #switch_window {
outline: 0;
background: rgba(255,255,255,.15);
backdrop-filter: blur(10px);
user-select: none;
}
#switch_btn, .switch_engine {
width: auto;
white-space: nowrap;
font-size: 12px;
}
#switch_btn {
margin: 5px -2px 5px 6px;
padding: 8px 10px;
height: 36px;
border: 0;
align-items: center;
display: flex;
float: left;
}
#switch_btn::after {
content: "▼";
transition: .3s;
font-size: 6px;
margin-left: 2px;
}
#switch_btn.active::after {
rotate: 180deg;
}
#switch_window {
grid-template-columns: repeat(var(--engine_num), auto);
border: 1px solid rgba(255,255,255,.2);
position: absolute;
padding: 4px;
gap: 4px;
opacity: 0;
visibility: hidden;
display: grid;
z-index: 9999;
border-radius: 8px;
pointer-events: none;
overflow-y: auto;
max-height: 0;
transition: .3s;
box-sizing: border-box;
}
#switch_window.active {
max-height: var(--max_height);
visibility: visible;
opacity: 1;
pointer-events: auto;
transition: .3s;
}
.switch_engine {
border-radius: 6px;
height: auto;
transition: .2s;
padding: 5px 6px;
}
.switch_engine.active {
background: rgba(22,93,255,.3);
color: #fff;
font-weight: 500;
}
/* ============================ */
/* 主页搜索框及其他布局样式 */
/* ============================ */
#content {
position: fixed;
top: 20vh;
width: 100%;
}
#content .search_part .search_bar {
box-shadow: 0 0 5px rgba(70,70,40,0.255);
backdrop-filter: blur(5px);
background-color: rgba(255,255,255,.100);
border-radius: 15px;
display: table;
width: 85%;
height: 30px;
max-width: 400px;
margin: 20px auto;
text-align: center;
font-size: 30px;
border: 1px solid transparent;
outline: none;
font-weight: 560;
transition-duration: 0.2s;
animation: search-bar 1s;
box-sizing: border-box;
}
#content .search_part .search_bar span {
padding: 0;
}
#content .search_part .opSug_wpr,
#content .search_part .bdSug_wpr {
border-radius: 15px 15px 15px 15px;
border: 0 none #FFFFFF !important;
border-top: 10px solid transparent !important;
background: rgba(255,255,255,0.2) !important;
backdrop-filter: blur(5px);
width: 85% !important;
max-width: 400px !important;
margin: 0 auto !important;
left: 0 !important;
right: 0 !important;
transform: none !important;
box-sizing: border-box;
position: absolute;
}
@keyframes search-bar {
0% { max-width: 100px; }
100% { max-width: 400px; }
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

适用于via和雨见的浏览器主页
https://zno233.github.io/posts/适用via和雨见的浏览器主页/
作者
一杯清风不加糖
发布于
2026-05-25
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
一杯清风不加糖
天上地下,惟我独尊,舍我之外,皆为外物.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
15
分类
7
标签
28
总字数
18,786
运行时长
0
最后活动
0 天前

文章目录