分页: 1 / 1

typecho无插件实现实时搜索(更新静态缓存版)

发表于 : 2019年 4月 28日 05:16
远.山
另寻以前的友链,博主原网址 https://sa.bi 主机因为隐匿一年没有进行续费,挂了... 还留有小弟友链的,希望能恢复.


第一步: 将一下html加到主题header.php里

代码: 全选

    <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>



第二步: 将下方js代码随便压缩一下,新建个js文件丢进去并引入到主题里。

代码: 全选

    var QueryStorage = [];//json储存器
    search_a("这里填写新建的独立页面链接,如:index.html");
   
    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);  //以get方式获取
   
    _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);//将$json转化为json格式
   
    };
   
    };
   
    };
   
    }
   
    //增加函数 filter
   
    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;}


第三步: 在主题里新建个php文件,随意命名,把下方php代码丢进去,然后进入后台新建页面,把链接填写到上方js里。

代码: 全选

    <?php 
   
    /** 
   
    * 搜索索引
   
    * 
   
    * @package custom 
   
    */ 
   
    ?> 
   
    <?php
   
    $vowels = array("[", "{","]","}","<",">","\r\n", "\r", "\n","-","'",'"','`'," ",":",";",'\\',"  ");
   
    $this->widget('Widget_Contents_Post_Recent')->to($archives);
   
        while($archives->next()):
   
        $output .= '{"this":"post","link":"'.$archives->permalink.'","title":"'.$archives->title.'","comments":"'.$archives->commentsNum0.'","text":"'.str_replace($vowels, "",$archives->text).'"},';
   
        endwhile;
   
    $this->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;
   
    $this->widget('Widget_Metas_Tag_Cloud')->to($tags); 
   
    while ($tags->next()):
   
    $output .= '{"this":"tag","link":"'.$tags->permalink.'","title":"'.$tags->name.'","comments":"0","text":"'.str_replace($vowels, "",$tags->description).'"},';
   
    endwhile;
   
    $this->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);
   
        echo '['.$output.']';
   
    ?>





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-mask,
    .ins-search-container {
      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: none;
      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-section-header,
    .ins-section .ins-search-item {
      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 header,
    .ins-section .ins-search-item .ins-search-preview {
      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:hover,
    .ins-section .ins-search-item.active {
      color: #fff;
      background: #006bde;
    }
    .ins-section .ins-search-item:hover .ins-slug,
    .ins-section .ins-search-item.active .ins-slug,
    .ins-section .ins-search-item:hover .ins-search-preview,
    .ins-section .ins-search-item.active .ins-search-preview,
    .ins-section .ins-search-item:hover header {
      color: #fff;
    }


没了 就这么简单...适合有基础的博主!css啥的原出处我也不清楚,我看到好几个主题都有这个,就扒下来了,我也是个小杂鱼,大佬勿喷


静态缓存版:(上面的第三步改为如下)

在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 !== '') {

         if (is_null($value)) {
            return unlink($filePath);
         }
         $dir = dirname($filePath);
         if (!is_dir($dir)) {
            mkdir($dir, 0777);
         }
         return file_put_contents($filePath,$value);
      }
      if (!is_file($filePath)) {
         return false;
      } else {
         echo $filePath;
         return json_decode(file_get_contents($filePath), true);
      }
   }
}



$TheFile = dirname(__FILE__).'/caches/cache.json';
$cacheFile = new cacheFile();

$vowels = array("[", "{","]","}","<",">","\r\n", "\r", "\n","-","'",'"','`'," ",":",";",'\\',"   ");

Typecho_Widget::widget('Widget_Contents_Post_Recent')->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')->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) > 300){
  $cacheFile->cacheData('cache', $data);
  }; //5分钟300秒,判断文件时间可以自己调整
} else {
  $cacheFile->cacheData('cache', $data);
};


Re: typecho无插件实现实时搜索

发表于 : 2019年 4月 28日 05:17
远.山
https://blog.moe.sb 这套操作下来跟本站一样了,我原本目的就是为了不装任何插件减少请求,所以才搞这么个破玩意

Re: typecho无插件实现实时搜索

发表于 : 2019年 4月 28日 09:43
Lopwon
这个不错,如果实时显示的文章的搜索关键词能高亮,会不会更好些。

Re: typecho无插件实现实时搜索

发表于 : 2019年 4月 28日 21:01
远.山
Lopwon 写了:这个不错,如果实时显示的文章的搜索关键词能高亮,会不会更好些。


改改JS就可以了