cms-themeblog

2018-11-15 07:42:40

模块cms-themeblog是官方提供的博客主题

插件依赖

因为主题插件都是独立的EggBorn模块,会持续的进行版本迭代

为了在版本迭代过程中保持代码一致性,从而避免版本冲突,主题需要显式声明依赖了哪些插件模块

通过声明插件模块的依赖关系,当安装主题模块时,相应的插件模块也会自动安装

cms-themeblog/package.json

{
  "name": "egg-born-module-cms-themeblog",
  "version": "1.1.3",
  "title": "cms:theme:blog",
  "eggBornModule": {
    "cms": {
      "name": "blog",
      "theme": true
    },
    "dependencies": {
      "a-instance": "1.0.0"
    }
  },
  ...
  "dependencies": {
    ...
    "egg-born-module-cms-pluginbase": "^1.1.0",
    "egg-born-module-cms-pluginarticle": "^1.0.0",
    "egg-born-module-cms-pluginsidebar": "^1.0.0",
    "egg-born-module-cms-pluginmarkdowngithub": "^1.0.0",
    "egg-born-module-cms-plugintrack": "^1.0.1"
  }
}
  • "theme": true: 声明是主题模块

安装主题

$ npm i egg-born-module-cms-themeblog

渲染模版

15

名称 说明 渲染时机 备注
assets 资源文件 一次构建
layout 布局目录 中间文件 layout不是官方强制定义的目录。主题可根据自己的需要添加,规划自己的页面元素
main 主渲染模版目录 两个渲染时机
main/article.ejs 文章渲染模版 当需要渲染文章时使用此模版文件
main/index 首页渲染模版目录 当需要渲染首页时使用此目录中的模版文件。为什么是目录?在一个复杂的站点中,根据场景需要可以有多个类首页模版文件
static 静态文件目录 一次构建 如文件articles.ejs,通过ajax调用后端API获取文章清单,从而可以集中实现目录标签搜索等功能
  • 主题cms-themeblog提供了三个主渲染模版:
    • static/articles.ejs:用于集中实现目录标签搜索等功能
    • main/article.ejs:用于文章的渲染
    • main/index/index.ejs:用于首页的渲染
  • assets是资源目录:包含CSS、JS和Image等资源
  • layout是布局目录:包含布局元素的渲染模版

其实,layout中大多数渲染模版文件内容很精简,为何不合并成一个渲染文件,而要拆分这么细致?

  • 布局元素拆分细致,是为了在主题的实际使用当中,自定义环节可以做更少的变更,也便于更快的升级到主题的更新版本

主渲染模版

static/articles.ejs

<%- await include('../layout/header.ejs') %>
<div class="row">
  <div class="col-sm-8">
    <section>
      <%- await include('../layout/breadcrumb.ejs') %>
      <ul class="article-list media-list">
      </ul>
    </section>
  </div>
  <div class="col-sm-4">
    <%- await include('../layout/sidebar.ejs') %>
  </div>
</div>
<%- await include('../layout/footer.ejs') %>

main/article.ejs

<%- await include('../layout/header.ejs') %>
<div class="row">
  <div class="col-sm-8">
    <article>
      <%- await include('../layout/breadcrumb.ejs') %>
      <%- await include('../layout/article/title.ejs')%>
      <%- article.html %>
      <%- await include('../layout/article/attachments.ejs') %>
      <%- await include('../layout/article/stat.ejs') %>
      <%- await include('../layout/article/brothers.ejs') %>
      <%- await include('../layout/article/comments.ejs') %>
    </article>
  </div>
  <div class="col-sm-4">
    <%- await include('../layout/sidebar.ejs') %>
  </div>
</div>
<%- await include('../layout/footer.ejs') %>

main/index/index.ejs

<%- await include('../../layout/header.ejs') %>
<div class="row">
  <div class="col-sm-8">
    <section>
      <%- await include('../../layout/breadcrumb.ejs') %>
      <ul class="article-list media-list">
        <%
          // options
          const options = {
            where: {
              'f.language': site.language.current,
            },
            orders: [
              [ 'f.sticky', 'desc' ],
              [ 'a.createdAt', 'desc' ],
            ],
            page: { index:0 },
            mode: 'list',
          };
          // select
          const data=await ctx.performAction({
            method:'get',
            url: '/a/cms/article/list',
            query: { options:JSON.stringify(options) },
          });
          // index
          env('index',{
            [_path]:data.index,
          });
          // list
          for(const item of data.list){
             const sticky = !item.sticky ? '' : '<span class="glyphicon glyphicon-pushpin"></span> ';
             const attachment = item.attachmentCount===0 ? '' : '<span class="glyphicon glyphicon-paperclip"></span> ';
             const media = !item.imageFirst ? '' : `
<div class="media-right">
      <a target="_blank" href="${url(item.url)}">
        <img class="media-object img-delay" data-src="${item.imageFirst}" data-width="125" data-height="100">
      </a>
</div>
        `;
        // tags
        let tagsText='';
        const tags=item.tags?JSON.parse(item.tags):null;
        if(tags && tags.length>0){
          tagsText+='<span class="num glyphicon glyphicon-tags"></span> ';
          for(const tag of tags){
            tagsText+=`<a target="_blank" href="${url('static/articles.html')}?tagId=${tag.id}&tagName=${tag.name}"><span class="num tag">${tag.name}</span></a>`;
          }
          tagsText+='';
        }
        // stat
        const stat=`
<div class="title stat" data-article-id="${item.atomId}">
<a target="_blank" href="${url('static/articles.html')}?categoryId=${item.categoryId}&categoryName=${item.categoryName}"><span class="num category">${item.categoryName}</span></a>
<span class="num date">${util.formatDateTime(item.createdAt)}</span>
<span class="glyphicon glyphicon-eye-open"></span><span class="num readCount"></span>
<span class="glyphicon glyphicon-heart"></span><span class="num starCount"></span>
<a target="_blank" href="${url(item.url)}#comments"><span class="glyphicon glyphicon-comment"></span><span class="num commentCount"></span></a>
${tagsText}
</div>
        `;

        const html= `
<li class="media">
    <div class="media-body">
      <h4 class="media-heading">${sticky}${attachment}<a target="_blank" href="${url(item.url)}">${item.atomName}</a></h4>
      ${item.description || item.summary}
      ${stat}
    </div>
    ${media}
</li>
        `;
          echo(html);
          }
        %>
      </ul>
    </section>
  </div>
  <div class="col-sm-4">
    <%- await include('../../layout/sidebar.ejs') %>
  </div>
</div>
<%- await include('../../layout/footer.ejs') %>

static/articles.ejs与main/index/index.ejs的区别

两个渲染模版的布局一致,为什么要分开实现?

为了兼顾SEO优化首页加载性能文章单独渲染性能,对不同场景的页面做了不同的渲染设计

  • 首页预先渲染第一页文章列表(默认为20篇),当向下滚动时,加载后续的文章列表
  • 目录标签搜索场景下,不需要预先渲染第一页文章列表
  • 因此,main/index/index.ejs需要支持两个渲染时机,而static/articles.ejs只需要一次构建

布局渲染模版

这里着重介绍headerfooter的渲染模版,其他内容请直接查看模块源码

layout/header.ejs

<!DOCTYPE html>
<html>
<head>
  <%- await include('./header/head.ejs') %>
</head>
<body>
  <header>
    <div class="container">
      <%- await include('./header/title.ejs') %>
      <%- await include('./header/menu.ejs') %>
    </div>
  </header>
  <div class="container container-site">

layout/header/head.ejs

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="generator" content="Cabloy-CMS" />
<link rel="shortcut icon" href="<%=url('assets/images/favicon.ico')%>" type="image/x-icon">

<%- await include('../../plugins/cms-pluginarticle/header/meta.ejs') %>

<%- await include('../../plugins/cms-pluginmarkdowngithub/header/css.ejs') %>
<%- await include('../../plugins/cms-pluginbase/header/css.ejs') %>
<%- await include('../../plugins/cms-pluginarticle/header/css.ejs') %>
<%- await include('../../plugins/cms-pluginsidebar/header/css.ejs') %>

<%- await include('../../plugins/cms-pluginbase/header/js.ejs') %>
<%- await include('../../plugins/cms-pluginarticle/header/js.ejs') %>
<%- await include('../../plugins/cms-pluginsidebar/header/js.ejs') %>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="_ _CSS_ _">
_ _ENV_ _

<!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->

<%
  // pluginbase init
  js('../../plugins/cms-pluginbase/assets/js/init.js.ejs');
  js('../../plugins/cms-pluginarticle/assets/js/init.js.ejs');
  js('../../plugins/cms-pluginsidebar/assets/js/init.js.ejs');
%>

<%
  // css
  css('../../assets/css/site.css.ejs');
  // js
  js('../../assets/js/site.js.ejs');
%>
  • 通过include包含插件的模版文件,如cms-pluginbase
  • 通过js声明使用的JS文件
  • 通过css声明使用的CSS文件
  • _ _CSS_ _: CSS文件占位符
  • _ _ENV_ _: 前端环境对象占位符

layout/footer.ejs

  </div> <!-- container -->
  <footer>
      <span class="small">Powered by <a target="_blank" href="https://cms.cabloy.org">Cabloy-CMS</a> | Theme - <a target="_blank" href="<%=site._theme.url%>"><%=site._theme.name%></a></span>
  </footer>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
  <script src="_ _JS_ _"></script>
  <%- await include('../plugins/cms-plugintrack/track.ejs') %>
</body>
</html>
  • _ _JS_ _: JS文件占位符


评论: