コード取得
[[iftags +_wikit组件]]
[[toc]]
+++ **//这是什么?//**
[[div class="card"]]
这是由[[*user Kakushi]]开发的维基搜索组件,作为已经不可用的Wikidot原生搜索的替代。 **本模块使用的样式与[[[https://projwikit.unitreaty.org/search:site|ProjectWikit]]]平台的搜索模块互通。**
[[/div]]
**目前Wikit Search可用的网站:**
[[div class="support"]]
* ubmh
* scp-wiki-cloud
* backroom-wiki-cn
* scr-wiki
* deep-forest-club
* rule-wiki
* asbackroom
* historyroom
* lostmedia
* if-backrooms
* three-backrooms
* backrooms-lh-wiki
* scp-wiki-mc
* pin-wiki
* rpc-wiki-cn
* backrooms-f
* backrooms-split-library
* backrooms-hn-cn
* write-on-paper
* backrooms-x-cn
* science-first
* yeebackrooms
* backroomss
* cas-wiki-cn
* pu-cn-wiki
* wikit-test
* skb-wiki-cn
* backrooms-mc-new
[[/div]]
[[collapsible show="+ 停止更新但仍可用的网站" hide="- 关闭"]]
这些网站是因**闭站**或**无有效内容**以及**严重不满足要求**等原因停止更新的网站。但数据仍旧会保留,并在api中可用。
[[div class="support"]]
* warma-world
* our-backrooms
* scp-wiki-three
* u-backrooms
* fog-wiki
[[/div]]
[[/collapsible]]
//后续将有更多维基获得支持//
@@@@
[[div class="card"]]
如果你对Wikit Search感兴趣、希望在你的维基使用本组件、希望对后续开发提供帮助和建议或在使用中遇到任何问题,请私信[[*user Kakushi]]
[[/div]]
-----
+++ **关联说明**
[[div class="card"]]
//Wikit Search不会收录网站隐藏的页面//
//Wikit Search每3-4小时就会进行一次拉取更新//
//Wikit Bot会不定期备份在列维基的所有公开内容[[footnote]] 使用[[[wikit-cli|Wikit命令行工具]]] [[/footnote]]//
[[/div]]
-----
+++ **使用方式**
在你想要使用Wikit Search组件的页面放入如下片段(通常是**search:site**):
[[div class="card"]]
@@[[include :wikkit:search@@
@@| wiki=@@##grey|你的维基子域名(如scp-wiki-cloud)##
@@]]@@
[[/div]]
//**示例:**点击[[[https://ubmh.wikidot.com/search:site|这里]]]跳转地下黑市站内搜索//
@@@@
@@@@
[[collapsible show="+ 附加说明" hide="- 关闭"]]
//你可以向[[*user Kakushi]]提交不希望抓取的页面或标签表//,标签筛选规则位于[[[https://github.com/WikitTeam/wikit_crawl_config/blob/main/tag_rules_config.json |此处]]]的公开仓库。
//你可以自定义搜索框架的样式和源代码,但必须保留某种形式上的Wikit Search支持声明并指向本站//
查看GraphQL API,于[[[graphql|此处]]]。
[[/collapsible]]
-----
@@@@
+++ **功能说明**
Wikit Search可以通过//**关键词检索**//(标题和内容)、//**作者搜索**//、//**标签搜索**//和//**时间检索**//四种方式来检索页面。上述四种方式可以**混合使用**。//Search结果将会显示包括页面的**标题**、**作者**、**评分**、**评论数**、**正文**、**标签**、**更新日期**、**创建日期**在内的数据。//
//**关键词检索**//支持多个关键词共同检索,每个关键词间需要使用空格分隔开。
[[/iftags]]
[[iftags -_wikit组件]]
[[html]]
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://wikit.unitreaty.org/wikidot/search.css">
</head>
<body>
<div class="w-search">
<div class="w-search-box">
<input id="q" class="w-search-input" type="text" placeholder="搜索文章标题或内容…">
</div>
<div class="w-search-filters">
<input id="author" class="w-search-filter" type="text" placeholder="作者">
<input id="tags" class="w-search-filter" type="text" placeholder="标签(空格分隔,- 排除)">
<div class="w-search-dates">
<input id="datefrom" class="w-search-filter w-search-date" type="date">
<span class="w-search-date-sep">–</span>
<input id="dateto" class="w-search-filter w-search-date" type="date">
</div>
</div>
<div id="total" class="w-search-total"></div>
<div id="results" class="w-search-results"></div>
<div id="more-wrap"></div>
<div class="w-search-footer">
<a href="https://wikkit.wikidot.com/search" target="_blank" rel="noopener">由 <img class="w-search-footer-icon" src="https://wikit.unitreaty.org/wikidot/wikit.png" alt="Wikit"> Wikit Search 支持搜索服务</a>
</div>
</div>
<script>
const WIKI = 'ubmh';
const BASE = '//wikit.unitreaty.org/wikidot/search';
const el = id => document.getElementById(id);
const resultsEl = el('results');
const totalEl = el('total');
const moreEl = el('more-wrap');
let seq = 0, page = 1, totalPages = 1;
function readParams() {
return {
q: el('q').value.trim(),
author: el('author').value.trim(),
tags: el('tags').value.trim(),
datefrom: el('datefrom').value,
dateto: el('dateto').value,
};
}
function hasCriteria(p) {
return !!(p.q || p.author || p.tags || p.datefrom || p.dateto);
}
function fmtRating(v) {
if (v === null || v === undefined || v === '') return null;
if (typeof v === 'number') return (v >= 0 ? '+' : '') + v;
return (String(v).startsWith('-') ? '' : '+') + v;
}
function parseTime(s) {
if (!s) return null;
let str = String(s).trim().replace(' ', 'T');
if (!/[zZ]|[+-]\d{2}:?\d{2}$/.test(str)) str += 'Z';
const d = new Date(str);
return isNaN(d.getTime()) ? null : d;
}
function relTime(s) {
const d = parseTime(s);
if (!d) return '';
let diff = Math.floor((Date.now() - d.getTime()) / 1000);
if (diff < 0) diff = 0;
const year = 31536000, month = 2592000, day = 86400, hour = 3600, min = 60;
if (diff >= year) return Math.floor(diff / year) + '年前';
if (diff >= month) return Math.floor(diff / month) + '个月前';
if (diff >= day) return Math.floor(diff / day) + '天前';
if (diff >= hour) return Math.floor(diff / hour) + '小时前';
if (diff >= min) return Math.floor(diff / min) + '分钟前';
return '刚刚';
}
function preciseTime(s) {
const d = parseTime(s);
return d ? d.toLocaleString() : '';
}
function highlight(text, kws) {
if (!kws || !kws.length) return text;
let out = text;
kws.forEach(w => {
const esc = w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
out = out.replace(new RegExp(esc, 'gi'), m => '<span class="highlight">' + m + '</span>');
});
return out;
}
function showSkeleton() {
let h = '';
for (let i = 0; i < 5; i++) {
h += '<div class="w-search-skeleton"><div class="w-search-sk-line w-search-sk-title"></div><div class="w-search-sk-line"></div><div class="w-search-sk-line w-search-sk-short"></div></div>';
}
resultsEl.innerHTML = h;
moreEl.innerHTML = '';
}
function showError(msg) {
resultsEl.innerHTML = '<div class="w-search-error">' + msg + '</div>';
totalEl.textContent = '';
moreEl.innerHTML = '';
}
function render(data, p) {
const kws = p.q ? p.q.split(/\s+/).filter(Boolean) : [];
if (page === 1) resultsEl.innerHTML = '';
totalEl.textContent = data.total_results ? '共 ' + data.total_results + ' 条结果' : '';
if (page === 1 && (!data.results || !data.results.length)) {
resultsEl.innerHTML = '<div class="w-search-empty">未找到匹配的文章。</div>';
moreEl.innerHTML = '';
return;
}
let html = '';
data.results.forEach(r => {
const rating = fmtRating(r.rating);
html += '<div class="w-search-result">' +
'<a class="w-search-result-title" href="' + r.url + '" target="_blank">' + highlight(r.title || '', kws) + '</a>' +
(r.content ? '<div class="w-search-result-excerpt">' + highlight(r.content, kws) + '</div>' : '') +
'<div class="w-search-result-meta">' +
'<span class="w-search-result-author">' + (r.author || '已注销用户') + '</span>' +
(r.created_at ? '<span class="w-search-result-date" title="' + preciseTime(r.created_at) + '">创建 ' + relTime(r.created_at) + '</span>' : '') +
(r.lastmod ? '<span class="w-search-result-date" title="' + preciseTime(r.lastmod) + '">更新 ' + relTime(r.lastmod) + '</span>' : '') +
(rating !== null ? '<span class="w-search-result-rating">' + rating + '</span>' : '') +
(r.comments != null ? '<span>' + r.comments + ' 条评论</span>' : '') +
(r.tags && r.tags.length ? '<span class="w-search-result-tags">' + r.tags.join(' ') + '</span>' : '') +
'</div>' +
'</div>';
});
resultsEl.insertAdjacentHTML('beforeend', html);
moreEl.innerHTML = page < totalPages ? '<button class="w-search-more" id="more">加载更多</button>' : '';
const mb = el('more');
if (mb) mb.onclick = () => { page++; run(false); };
}
function run(reset) {
const p = readParams();
if (!hasCriteria(p)) {
page = 1; totalPages = 1;
resultsEl.innerHTML = ''; totalEl.textContent = ''; moreEl.innerHTML = '';
return;
}
if (reset) page = 1;
const my = ++seq;
if (page === 1) { totalEl.textContent = ''; showSkeleton(); }
moreEl.innerHTML = '';
const url = BASE +
'?wiki=' + encodeURIComponent(WIKI) +
'&q=' + encodeURIComponent(p.q) +
'&author=' + encodeURIComponent(p.author) +
'&tags=' + encodeURIComponent(p.tags) +
'&datefrom=' + encodeURIComponent(p.datefrom) +
'&dateto=' + encodeURIComponent(p.dateto) +
'&page=' + page;
fetch(url).then(res => res.json()).then(data => {
if (my !== seq) return;
if (data.error) { showError('搜索失败,请稍后再试。'); return; }
totalPages = data.total_pages || 1;
render(data, p);
}).catch(() => {
if (my === seq) showError('搜索失败,请稍后再试。');
});
}
let debounce = null;
['q', 'author', 'tags', 'datefrom', 'dateto'].forEach(id => {
el(id).addEventListener('input', () => {
clearTimeout(debounce);
debounce = setTimeout(() => run(true), 300);
});
});
</script>
</body>
</html>
[[/html]]
[[/iftags]]
[[div class="blockquote"]]
[[collapsible show="+ 使用说明" hide="- 瞅完了吗"]]
[[size 120%]]//如果您遇到任何问题,请私信 [[*user Kakushi]]。//[[/size]]
[[/collapsible]]
[[/div]]ページリビジョン: 27, 最終更新: 17 May 2026 04:47
