示例参考
<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',
},
]);
登录后评论