适用于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和雨见的浏览器主页/