Typecho 无插件实现即时搜索
3年前
在functions.php最后面添加以下,通过每次访问判断文件间隔时间来达到更新缓存的目的。上方js里的search_a路径需要填写完整路径+/caches/cache.json
/**
* 静态缓存类
*/
class cacheFile
{
private $_dir;
const EXT = '.json';
public function __construct()
{
$this->_dir = dirname(__FILE__).'/caches/';
}
public function cacheData($key, $value = '', $path = '')
{
$filePath = $this->_dir.$path.$key.self::EXT;
if ($value !== '') {
// 如果设置为 null,则删除缓存文件
if (is_null($value)) {
return unlink($filePath);
}
$dir = dirname($filePath);
if (!is_dir($dir)) {
mkdir($dir, 0777);
}
// 该函数将返回写入到文件内数据的字节数,失败时返回FALSE
return file_put_contents($filePath, $value);
}
// 如果已经存在该文件,直接返回文件里面的内容
if (!is_file($filePath)) {
return false;
} else {
echo $filePath;
// The function returns the read data 或者在失败时返回 FALSE.
return json_decode(file_get_contents($filePath), true);
}
}
}
if(!file_exists($flag)) {
touch($flag);
$TheFile = dirname(__FILE__).'/caches/cache.json';
$cacheFile = new cacheFile();
$vowels = array("[", "{","]","}","<",">","\r\n", "\r", "\n","-","'",'"','`'," ",":",";",'\\'," ");
Typecho_Widget::widget('Widget_Contents_Post_Recent','pageSize=10000')->to($archives);
while($archives->next()):
$output .= '{"this":"post","link":"'.$archives->permalink.'","title":"'.$archives->title.'","comments":"'.$archives->commentsNum0.'","text":"'.str_replace($vowels, "",$archives->text).'"},';
endwhile;
Typecho_Widget::widget('Widget_Contents_Page_List')->to($pages);
while($pages->next()):
$output .= '{"this":"page","link":"'.$pages->permalink.'","title":"'.$pages->title.'","comments":"'.$pages->commentsNum0.'","text":"'.str_replace($vowels, "",$pages->text).'"},';
endwhile;
Typecho_Widget::widget('Widget_Metas_Tag_Cloud','ignoreZeroCount=1&limit=10000')->to($tags);
while ($tags->next()):
$output .= '{"this":"tag","link":"'.$tags->permalink.'","title":"'.$tags->name.'","comments":"0","text":"'.str_replace($vowels, "",$tags->description).'"},';
endwhile;
Typecho_Widget::widget('Widget_Metas_Category_List')->to($category);
while ($category->next()):
$output .= '{"this":"category","link":"'.$category->permalink.'","title":"'.$category->name.'","comments":"0","text":"'.str_replace($vowels, "",$category->description).'"},';
endwhile;
$output = substr($output,0,strlen($output)-1);
$data = '['.$output.']';
if (file_exists($TheFile)) {
if ( time() - filemtime( $TheFile) > 1800){
$cacheFile->cacheData('cache', $data);
}; //5分钟300秒,时间可以自己调整
} else {
$cacheFile->cacheData('cache', $data);
};
}
HTML结构:
<div class="ins-search" id="search">
<div class="ins-search-mask">
</div>
<div class="ins-search-container">
<div class="ins-input-wrapper">
<form id="search-form" method="post" action="./" role="search">
<input id="search-input" type="text" name="s" class="ins-search-input" placeholder="想要查找什么...">
</form>
<span id="close" class="ins-close ins-selectable">×</span>
</div>
<div class="ins-section-wrapper">
<a id="Ty" href="#"></a>
<div class="ins-section-container" id="PostlistBox">
<section class="ins-section"><header class="ins-section-header">文章</header>
<div class="ins-selectable ins-search-item" data-url="/">
<header>测试</header>
<p class="ins-search-preview">
及时搜索结果
</p>
</div>
</section><section class="ins-section"><header class="ins-section-header">页面</header>
<div class="ins-selectable ins-search-item" data-url="/">
<header>测试</header>
</div>
</section><section class="ins-section"><header class="ins-section-header">分类</header>
<div class="ins-selectable ins-search-item" data-url="/">
<header>测试<span class="ins-slug">测试</span></header>
</div>
</section><section class="ins-section"><header class="ins-section-header">标签</header>
<div class="ins-selectable ins-search-item" data-url="/">
<header>测试<span class="ins-slug">测试</span></header>
</div>
</section>
</div>
</div>
</div>
</div>
CSS:
.ins-search{display:none;z-index:999}
.ins-search a{-webkit-transition:none;transition:none}
.ins-search header{position:unset;width:auto}
.ins-selectable{cursor:pointer}
.ins-search-container,.ins-search-mask{position:fixed}
.ins-search-mask{top:0;left:0;width:100%;height:100%;z-index:100;background:rgba(0,0,0,.85)}
.ins-input-wrapper{position:relative}
.ins-search-input{width:100%;border:none;outline:0;font-size:16px;-webkit-box-shadow:none;box-shadow:none;font-weight:200;border-radius:0;background:#fff;line-height:20px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:12px 40px 12px 20px;border-bottom:1px solid #e2e2e2}
.ins-close{top:50%;right:10px;width:20px;height:20px;font-size:16px;margin-top:-15px;position:absolute;text-align:center;display:inline-block;font:22px/30px Arial,Helvetica Neue,Helvetica,sans-serif;color:#888;font-weight:300}
.ins-close:hover{color:#000}
.ins-search-container{left:50%;top:100px;z-index:101;bottom:100px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:540px;margin-left:-270px;border:1px solid #ccc;border-radius:.28571429rem;background:#fff;-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.08);box-shadow:0 1px 3px 0 rgba(0,0,0,.08)}
@media screen and (max-width:559px),screen and (max-height:479px){.ins-search-container{top:0;left:0;margin:0;width:100%;height:100%;background:#f7f7f7}
}
.ins-section-wrapper{left:0;right:0;top:45px;bottom:0;overflow-y:auto;position:absolute}
.ins-section-container{position:relative;background:#f7f7f7}
.ins-section{font-size:14px;line-height:16px}
.ins-section .ins-search-item,.ins-section .ins-section-header{padding:8px 15px}
.ins-section .ins-section-header{color:#9a9a9a;border-bottom:1px solid #e2e2e2}
.ins-section .ins-slug{margin-left:5px;color:#9a9a9a}
.ins-section .ins-slug:before{content:'('}
.ins-section .ins-slug:after{content:')'}
.ins-section .ins-search-item .ins-search-preview,.ins-section .ins-search-item header{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:#616161}
.ins-section .ins-search-item header i{margin-right:8px}
.ins-section .ins-search-item .ins-search-preview{height:15px;font-size:12px;color:#9a9a9a;margin:5px 0 0 20px}
.ins-section .ins-search-item.active,.ins-section .ins-search-item:hover{color:#fff;background:#006bde}
.ins-section .ins-search-item.active .ins-search-preview,.ins-section .ins-search-item.active .ins-slug,.ins-section .ins-search-item:hover .ins-search-preview,.ins-section .ins-search-item:hover .ins-slug,.ins-section .ins-search-item:hover header{color:#fff}
JS:
var QueryStorage = [];
search_a("这里填写生成的json链接");
var otxt = document.getElementById("search-input"),
list = document.getElementById("PostlistBox"),
Record = list.innerHTML;
document.all ? otxt.onpropertychange = function() {
query(QueryStorage, otxt.value, Record)
} : otxt.oninput = function() {
query(QueryStorage, otxt.value, Record)
};
function search_a(val) {
var _xhr = new XMLHttpRequest();
_xhr.open("GET", val, true);
_xhr.setRequestHeader("Content-Type", "application/json");
_xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
_xhr.send(val);
_xhr.onreadystatechange = function() {
if (_xhr.readyState == 4 && _xhr.status == 200) {
json = _xhr.responseText;
if (json != "") {
QueryStorage = JSON.parse(json)
}
}
}
}
if (!Object.values) Object.values = function(obj) {
if (obj !== Object(obj)) throw new TypeError('Object.values called on a non-object');
var val = [],
key;
for (key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
val.push(obj[key])
}
}
return val
}
function a(a) {
document.getElementById("Ty").href = a.getAttribute("href"), document.getElementById("Ty").click()
}
function query(a, b, c) {
var n, o, p, q, d = "",
e = "",
f = "",
g = "",
h = "",
i = '<div class="ins-selectable ins-search-item" onclick="a(this)" href="',
j = '<section class="ins-section"><header class="ins-section-header">',
k = "</header>",
l = "</section>",
m = Cx(a, b);
for (n = 0; n < Object.keys(m).length; n++) switch (o = m[n].this) {
case "post":
e = e + i + m[n].link + '"><header>' + m[n].title + '</header><p class="ins-search-preview">' + m[n].comments + m[n].text + "</p></div>";
break;
case "tag":
f = f + i + m[n].link + '"><header>' + m[n].title + '<span class="ins-slug">' + m[n].text + "</span></header></div>";
break;
case "category":
g = g + i + m[n].link + '"><header>' + m[n].title + '<span class="ins-slug">' + m[n].text + "</span></header></div>";
break;
case "page":
h = h + i + m[n].link + '"><header>' + m[n].title + '</header><p class="ins-search-preview">' + m[n].comments + m[n].text + "</p></div>"
}
e && (d = d + j + "文章" + k + e + l), h && (d = d + j + "页面" + k + h + l), g && (d = d + j + "分类" + k + g + l), f && (d = d + j + "标签" + k + f + l), p = document.getElementById("PostlistBox"), q = document.getElementById("search-input"), p.innerHTML = "" == q.value ? c : d
}
function Cx(arr, q) {
i = arr.filter(v = > Object.values(v).some(v = > new RegExp(q + '').test(v)));
return I
}