admin 发表于 2025-7-10 17:22:05

Typecho主题制作总结

由于 Typecho 相比 WordPress,所提供的接口较少,所以有些地方需要注意下。

首页文章无限加载文章
首先在 functions.php 中加入一段判断 ajax 请求的方法:
function is_ajax()
{
    if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
      if ('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) {
            return true;
      }
    }
    return false;
}然后在首页模板 index.php 中加入判断,if (is_ajax ()): 则不输出 header footer 等信息。
最后一步,再模板公共 js 文件中加入以下代码:
var page = 1;
    var $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body');
    $('#blog_load_more').click(function(event) {
      $(this).hide();
      $('#spinner').show();
      $.ajax({
            type: 'get',
            url: SITE.default_url + '/page/' + parseInt(page + 1),
            success: function(data, textStatus, XMLHttpRequest) {
                page++;
                $('.w-blog-list').append(data);
                $('#spinner').hide();
                $('#blog_load_more').show();
            },
            error: function(MLHttpRequest, textStatus, errorThrown) {
                $('#spinner').hide();
                $.jGrowl('Network Error');
            }
      });
    });其中 #blog_load_more 为需要绑定的加载更多按钮,#spinner 为加载过程中的动画,.w-blog-list 为首页文章列表容器。
由于 Typecho 并没有 Ajax 钩子函数,所以需要在 functions.php 中加入以下代码:
function site_data()
{
    $array = array(
      'site_url'         => Helper::options()->siteUrl,
      'default_url'      => Helper::options()->siteUrl . 'index.php',
      'theme_images_url' => Helper::options()->themeUrl . '/assets/images/',
    );
    echo json_encode($array);
}之后在 footer.php 中引入该数据:
<script type="text/javascript">
var SITE = <?php site_data()?>;
</script>此处的 SITE 就是一个 JSON 对象,可以直接用了。Typecho实现add_filter功能比如想把文章中的图片都加上 rel="fancybox" 的属性,WordPress 可能使用的以下方法:add_filter('the_content', 'fancybox_replace');
function fancybox_replace($content)
{
    global $post;
    $pattern   = "/<a(.*?)href=('|\")([^>]*).(bmp|gif|jpeg|jpg|png)('|\")(.*?)>(.*?)<\/a>/i";
    $replacement = '<a$1href=$2$3.$4$5 target="_blank" rel="fancybox"$6>$7</a>';
    $content   = preg_replace($pattern, $replacement, $content);
    return $content;
}Typecho 中可以这么写:function themeInit($archive)
{
    if ($archive->is('single')) {
      $archive->content = fancybox_replace($archive->content);
    }
}获取文章第一张图片分为 markdown 和 html 两种方式function get_post_img($archive)
{
    $cid = $archive->cid;
    $db = Typecho_Db::get();
    $rs = $db->fetchRow($db->select('table.contents.text')
                               ->from('table.contents')
                               ->where('cid=?', $cid));
    $text = $rs['text'];
    if (0 === strpos($text, '')) {
      preg_match('/!\[[^\]]*]\([^\)]*\.(png|jpeg|jpg|gif|bmp)\)/i', $text, $img);
      if (empty($img)) {
            return 'none';
      } else {
            preg_match("/(?:\()(.*)(?:\))/i", $img, $result);
            $img_url = $result;
            return '<img src="' . $img_url . '"/>';
      }
    } else {
      preg_match_all("/\<img.*?src\=\"(.*?)\"[^>]*>/i", $text, $img);
      if (empty($img)) {
            return 'none';
      } else {
            $img_url = $img;
            return '<img src="' . $img_url . '"/>';
      }
    }
}评论列表加@
function get_comment_at($coid)
{
    $db   = Typecho_Db::get();
    $prow = $db->fetchRow($db->select('parent')->from('table.comments')
                                 ->where('coid = ? AND status = ?', $coid, 'approved'));
    $parent = $prow['parent'];
    if ($parent != "0") {
      $arow = $db->fetchRow($db->select('author')->from('table.comments')
                                     ->where('coid = ? AND status = ?', $parent, 'approved'));
      $author = $arow['author'];
      $href   = '<a href="#comment-' . $parent . '">@' . $author . '</a>';
      echo $href;
    } else {
      echo '';
    }
}非插件实现文章阅读次数统计在文章页面引入 get_post_view() 方法。//get_post_view($this)
function get_post_view($archive)
{
    $cid    = $archive->cid;
    $db   = Typecho_Db::get();
    $prefix = $db->getPrefix();
    if (!array_key_exists('views', $db->fetchRow($db->select()->from('table.contents')))) {
      $db->query('ALTER TABLE `' . $prefix . 'contents` ADD `views` INT(10) DEFAULT 0;');
      echo 0;
      return;
    }
    $row = $db->fetchRow($db->select('views')->from('table.contents')->where('cid = ?', $cid));
    if ($archive->is('single')) {
       $db->query($db->update('table.contents')->rows(array('views' => (int) $row['views'] + 1))->where('cid = ?', $cid));
    }
    echo $row['views'];
}判断移动端访问
function is_mobile()
{
    $user_agent   = $_SERVER['HTTP_USER_AGENT'];
    $mobile_browser = array(
      "mqqbrowser", //手机QQ浏览器
      "opera mobi", //手机opera
      "juc", "iuc", //uc浏览器
      "fennec", "ios", "applewebKit/420", "applewebkit/525", "applewebkit/532", "ipad", "iphone", "ipaq", "ipod",
      "iemobile", "windows ce", //windows phone
      "240x320", "480x640", "acer", "android", "anywhereyougo.com", "asus", "audio", "blackberry",
      "blazer", "coolpad", "dopod", "etouch", "hitachi", "htc", "huawei", "jbrowser", "lenovo",
      "lg", "lg-", "lge-", "lge", "mobi", "moto", "nokia", "phone", "samsung", "sony",
      "symbian", "tablet", "tianyu", "wap", "xda", "xde", "zte",
    );
    $is_mobile = false;
    foreach ($mobile_browser as $device) {
      if (stristr($user_agent, $device)) {
            $is_mobile = true;
            break;
      }
    }
    return $is_mobile;
}ajax评论AjaxComments有小bug,不太好用,直接食用以下的修改版代码,在公共js中调用 ajaxComments() 方法即可。function ajaxComment() {
    var selector = {
      commentMainFrame: '#comment',
      commentList: '#commentlist',
      commentNumText: '#comment h3',
      commentReplyButton: '#comment span.reply',
      submitForm: '#commentform',
      submitTextarea: '#textarea',
      submitButton: '#submit',
    };
    var parentId = '';
    bindCommentReplyButton();
    $(selector.submitTextarea).after('<div style="display:none;" id="ajaxCommentMsg"><\/div>');
    $msg = $('#ajaxCommentMsg');
    $(document).on('submit', selector.submitForm, function() {
      $msg.empty();
      $(selector.submitButton).val('发射中哦=A=');
      $(selector.submitButton).attr('disabled', true).fadeTo('slow', 0.5);
      if ($(selector.submitForm).find('#author')) {
            if ($(selector.submitForm).find('#author').val() == '') {
                message('昵称没填呢QAQ');
                enableCommentButton();
                return false;
            }
            if ($(selector.submitForm).find('#mail').val() == '') {
                message('邮箱没填呢QAQ');
                enableCommentButton();
                return false;
            }
            var filter = /^[^@\s<&>]+@(+\.)+{2,4}$/i;
            if (!filter.test($(selector.submitForm).find('#mail').val())) {
                message('邮箱地址不正确呢QAQ');
                enableCommentButton();
                return false;
            }
      }
      if ($(selector.submitForm).find(selector.submitTextarea).val() == '') {
            message('评论似乎什么也没写呢QAQ');
            enableCommentButton();
            return false;
      }
      $.ajax({
            url: $(this).attr('action'),
            type: $(this).attr('method'),
            data: $(this).serializeArray(),
            error: function() {
                message('发射失败,请重试!');
                setTimeout(NProgress.done, 500)
                enableCommentButton();
                return false;
            },
            success: function(data) {
                if (!$(selector.commentList, data).length) {
                  errorMsg = data.match(/.+/g).join().match(/\<div.+\>.+\<\/div\>/g).join().match(/[^\,]+/g);
                  $msg.html(errorMsg + errorMsg + errorMsg);
                  enableCommentButton();
                  return false;
                } else {
                  userCommentId = $(selector.commentList, data).html().match(/id=\"?comment-\d+/g).join().match(/\d+/g).sort(function(a, b) {
                        return a - b;
                  }).pop();
                  commentLi = '<li id="comment-' + userCommentId + '" class="comment">' + $('#comment-' + userCommentId, data).html(); + '<\/li>';
                  if (parentId) {
                        if ($('#' + parentId).find(".comment-children").length <= 0) {
                            $('#' + parentId).append("<ul class='children'></ul>");
                        }
                        $('#' + parentId + " .children:first").append(commentLi);
                        parentId = ''
                        $body.animate({
                            scrollTop: $('#comment-' + userCommentId).offset().top - 450
                        }, 900);
                  } else {
                        $(selector.commentList).prepend(commentLi)
                        $body.animate({
                            scrollTop: $('#comment-' + userCommentId).offset().top - 200
                        }, 900);
                  }
                  //$('#comment-' + userCommentId).slideDown('slow');

                  //console.log(userCommentId);
                  $(selector.commentNumText).length ? (n = parseInt($(selector.commentNumText).text().match(/\d+/)), $(selector.commentNumText).html($(selector.commentNumText).html().replace(n, n + 1))) : 0;
                  TypechoComment.cancelReply();
                  $(selector.submitTextarea).val('');
                  $(selector.commentReplyButton + ' b, #cancel-comment-reply-link').unbind('click');
                  bindCommentReplyButton();
                  enableCommentButton();

                }
            }
      });
      return false;
    });

    function bindCommentReplyButton() {
      $(document).on('click', selector.commentReplyButton, function() {
            parentId = $(this).parents('li.comment').attr("id");
            $(selector.submitTextarea).focus();
      });
      $(document).on('click', '#cancel-comment-reply-link', function() {
            parentId = '';
      });
    }

    function enableCommentButton() {
      $(selector.submitButton).attr('disabled', false).fadeTo('', 1);
      $(selector.submitButton).val('发射=A=');
    }

    function message(msg) {
      $msg.hide();
      $msg.html(msg).slideToggle('fast');
    }
}无限嵌套评论
function themeInit($archive)
{
    Helper::options()->commentsMaxNestingLevels = 999;
}非插件实现路由
function themeInit($archive)
{
    if ($archive->is('archive', 404))
    {
      $path_info = trim($archive->request->getPathinfo(), '/');
      if ($path_info == 'i/redirect')
      {
            $url = urldecode($archive->request->url);
            $archive->response->redirect($url);
            exit;
      }
    }
}原文地址:https://kotori.love/archives/typecho-theme-tips
页: [1]
查看完整版本: Typecho主题制作总结