Typecho 无插件实现即时搜索

在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结构:


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

}

发表新评论