[: currentTime | date:'mm:ss' :] [: timeLeft | date:'mm:ss' :]

示例参考

结果
HTML
CSS
JS
运行
整页预览
<main>
  <h1>背背山论坛</h1>
  <div>
    <div class="timeline"></div>
  </div>
</main>
:root {
  font-family: sans-serif;
  color: #444;
  font-size: 15px;
}

img {
  max-width: 100%;
}

body {
  margin: 0;
}

input, button {
  padding: .6rem;
  border: 1px solid rgba(0, 0, 0, .1);
  outline: 0;
  font-size: .8rem;
}

input:focus,
button:focus {
  outline: 2px solid #cfa8ff;
}

form label,
form input {
  display: block;
  width: 100%;
  margin: .3rem 0;
}

main {
  max-width: 60em;
  margin-left: auto;
  margin-right: auto;
  padding: 1em;
}

[hidden] {
  display: none !important;
}

:root {
  background: #ff8e8e;
}

h1 {
  color: #fff;
}

main {
  max-width: 450px;
}

.post {
  background: #fff;
  padding: .5em;
  margin-bottom: 1em;
  border-radius: 3px;
  -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .2);-moz-box-shadow: 0 0 3px rgba(0, 0, 0, .2);box-shadow: 0 0 3px rgba(0, 0, 0, .2);
}

.post > * {
  margin-bottom: .5em;
}

.post.text {
  background: #c7e6ff;
}

.post.image {
  background: #ffeda1;
}

.post > *:last-child {
  margin-bottom: 0;
}
/**
 * 时间线
 */
class Timeline {
  /**
   * @param {string} selector 时间线应该插到页面中的哪个位置
   * @param {Array} list
   */
  constructor (selector, list) {
    this.el = document.querySelector(selector);

    // 原始数据
    this.$raw = list;

    // 转换为Post实例的数据
    this.$list = [];

    // 将所有this.$raw元素转换为Post实例
    this.normalize();

    // 开始渲染
    this.render();
  }

  /**
   * 常规化
   */
  normalize () {
    // 清空上一次转换的数据
    this.$list = [];

    // 循环原始数据
    this.$raw.forEach(it => {
      // 通过帖子的类型动态获取对应的Post类(TextPost还是ImagePost)
      let SelectedPost = postProducer(it.type);

      // 将实例化的帖子推入this.$list中
      this.$list.push(new SelectedPost(it));
    });
  }

  /**
   * 渲染时间线
   */
  render () {
    // 循环每一条帖子并追加到时间线上
    this.$list.forEach(it => {
      this.el.appendChild(it.render());
    });
  }
}

/**
 * 帖子
 */
class Post {
  /**
   * @param {Object} data 如:{type: 'text', content: 'xxx', ...}
   */
  constructor (data) {
    this.$raw = data;
    this.el   = null;
  }

  /**
   * 渲染自己
   * @return {HTMLElement} 渲染好的自己
   */
  render () {

    // 创建容器
    this.el = document.createElement('div');

    // 缓存数据
    let raw = this.$raw;

    // 填充内容
    this.el.innerHTML = `
    <div class="post ${raw.type}">
        <div class="header"><strong>${raw.user}</strong></div>
        <div class="body"></div>
        <div class="footer">
          <small>发布于 ${raw.createdAt}</small>
        </div>
      </div>
    `;

    // 缓存.body,方便后续调用
    this.body = this.el.querySelector('.body');

    return this.el;
  }
}

/**
 * 文字类帖子
 */
class TextPost extends Post {
  /**
   * 渲染自己
   * @return {null}
   */
  render () {
    // 当父级渲染好框架后
    super.render();

    // 个性化渲染文字内容
    this.body.innerHTML = this.$raw.content;
    return this.el;
  }
}

/**
 * 图片类帖子
 */
class ImagePost extends Post {
  /**
   * 渲染自己
   * @return {null}
   */
  render () {
    // 当父级渲染好框架后
    super.render();

    // 个性化渲染图片内容
    let imageList = '';
    this.$raw.content.forEach(it => {
      imageList += `<img src="${it}">`;
    });

    this.body.innerHTML = `
    <div class="title">${this.$raw.desc}</div>
    <div class="images">${imageList}</div>
    `;

    this.body.addEventListener('click', e => {
      this.body.style.position = 'fixed';
      this.body.style.top      = '0';
      this.body.style.left     = '0';
      this.body.style.maxWidth = '200px';
    });
    return this.el;
  }
}

/**
 * 通过帖子类型动态返回对应的类
 * @param {string} type 如:'text|image'
 * @return {Post}
 */
function postProducer (type) {
  switch (type) {
    case 'text':
      return TextPost;
    case 'image':
      return ImagePost;
  }
}

/*
|--------------------------------------------------------------------------
| 业务逻辑
|--------------------------------------------------------------------------
*/

new Timeline('.timeline', [
  {
    type      : 'text',
    content   : 'Lorem ipsum dolor sit amet, consectetur',
    user      : '李拴蛋',
    createdAt : '9:30',
  },
  {
    type      : 'image',
    desc      : '#关爱动物# 一只冻僵的猫',
    content   : [
      'https://public.biaoyansu.com/29.x/29.35/cat-frozened-to-death.jpg',
    ],
    user      : '王花花',
    createdAt : '9:00',
  },
]);
登录后评论