如何用更少的 Javascript 行来表达这一点?
How do I express this in fewer lines of Javascript?
我正在使用一些 JS 来计算自上次 post(即 "Posted 2 hours ago")以来的时间:
function ago(date) {
function render(n, unit) {
return n + " " + unit + ((n == 1) ? "" : "s") + " ago";
}
var seconds = Math.floor((new Date() - date) / 1000);
var interval = Math.floor(seconds / (60 * 60 * 24 * 30 * 365));
if (Math.floor(seconds / (60 * 60 * 24 * 30 * 365)) >= 1) {
return render(interval, "year");
}
interval = Math.floor(seconds / (60 * 60 * 24 * 30));
if (interval >= 1) {
return render(interval, "month");
}
interval = Math.floor(seconds / (60 * 60 * 24));
if (interval >= 1) {
return render(interval, "day");
}
interval = Math.floor(seconds / (60 * 60));
if (interval >= 1) {
return render(interval, "hour");
}
interval = Math.floor(seconds / 60);
if (interval >= 1) {
return render(interval, "minute");
}
interval = Math.floor(seconds);
return render(interval, "second");
}
然后将其包含在索引页中,紧挨着每个 post:
var date =
Date.parse(document.getElementById("postedon").getAttribute("datetime"));
document.getElementById("postedago").innerHTML = ago(date);
这里是 HTML:
<time id="{{ post.postedon }}" datetime="{{ post.date | date_to_xmlschema }}">
<span id="{{ post.postedago }}"></span>
</time>
请注意,我正在使用 Liquid & YAML(使用 Jekyll)在每个 post 的前文中设置元素的 ID 和属性:
---
date: 2018-1-4 02:00:00 +0100
postedago: postedago-post1
postedon: postedon-post2
---
问题是我必须像这样手动设置每个 post 的 JS 代码:
var date =
Date.parse(document.getElementById("postedon").getAttribute("datetime"));
document.getElementById("postedago").innerHTML = ago(date);
var date =
Date.parse(document.getElementById("postedon2").getAttribute("datetime"));
document.getElementById("postedago2").innerHTML = ago(date);
var date =
Date.parse(document.getElementById("postedon3").getAttribute("datetime"));
document.getElementById("postedago3").innerHTML = ago(date);
否则它不会显示所有 post 的时间,只显示一个。
我尝试将 JS 中的元素 id 设置为 front matter 参数但它不起作用(本质上是让 Jekyll 替换 JS 文件中的 liquid 标签):
var date =
Date.parse(document.getElementById("{{ post.postedon }}").getAttribute("datetime"));
document.getElementById("{{ post.postedago }}").innerHTML = ago(date);
我尝试在 js 文件的顶部添加前面的破折号,但它仍然不起作用(如 SO 此处所引用:)
---
---
//rest of your JavaScript
也许还有其他我没想到的方法?
感谢您花时间阅读本文,非常感谢您的帮助!
PS:参考 timeago 每个 post 页面上的脚本实现(不在包含所有 post 的索引页面上) : https://hejnoah.com/posts/timeago.html
这很简单,你可以使用一些 JS(/javascript-time-ago) 准备好..
仅用作下面的示例..
timeAgo.format(new Date()) ---> will output // "just now"
如果你要给它日期格式,会给出多少时间之前。
你应该给你的 HTML 元素一个 class
属性,这样你就可以使用 getElementsByClassName()
.
在一个循环中迭代所有这些元素
HTML:
<time class="postedon" id="{{ post.postedon }}" datetime="{{ post.date | date_to_xmlschema }}">
<span class="postedago" id="{{ post.postedago }}"></span>
</time>
JS:
const timeElems = document.getElementsByClassName('postedon');
for (let i = 0, len = timeElems.length; i < len; i++) {
let date = Date.parse(timeElems[i].getAttribute("datetime"));
timeElems[i].firstElementChild.innerHTML = ago(date);
}
现在您不必为每个 post 手动写出 JS。您可以类似地使用 getElementsByTagName('time')
假设这是您使用该标签的唯一地方。
首先,您的 ago
功能可以简化和减少。
然后我会使用 属性以 开头的选择器和 querySelectorAll
来获取元素,并使用 .forEach()
来设置 textContent
来自属性。
function render(n, unit) {
return n + " " + unit + ((n == 1) ? "" : "s") + " ago";
}
const labels = ["year", "month", "day", "hour", "minute", "second"];
const products = [1, 60, 60, 24, 30, 365]
.map((n, i, a) => a.slice(0, a.length-i).reduce((p, n) => p * n, 1));
function ago(date) {
var seconds = Math.floor((new Date() - Date.parse(date)) / 1000);
return labels.reduce((res, lab, i) => {
const interval = Math.floor(seconds / products[i]);
return res ? res : interval >= 1 ? render(interval, lab) : "";
}, "");
}
document.querySelectorAll("[id^=postedon]").forEach(el =>
el.querySelector('#' + el.id.replace('postedon', 'postedago'))
.textContent = ago(el.getAttribute("datetime"))
);
<time id="postedon0" datetime="2018-1-4 02:00:00 +0100">
<span id="postedago0"></span>
</time>
<time id="postedon1" datetime="2018-1-7 02:00:00 +0100">
<span id="postedago1"></span>
</time>
<time id="postedon2" datetime="2018-1-9 02:00:00 +0100">
<span id="postedago2"></span>
</time>
<time id="postedon3" datetime="2018-1-13 02:00:00 +0100">
<span id="postedago3"></span>
</time>
另请注意,我使用的是 .textContent
而不是 .innerHTML
,因为您实际上并未设置任何 HTML 内容。
另请注意,Date.parse
不适用于 Firefox 中的该日期格式。
另一个关于如何计算时间的例子。
function ago(date) {
var units = [
{ name : 'year', ms: 1000 * 60 * 60 * 24 * 30 * 365 },
{ name : 'month', ms: 1000 * 60 * 60 * 24 * 30 },
{ name : 'fortnight', ms : 1000 * 60 * 60 * 24 * 14 }, // yep.. I head that was a thing.
{ name : 'day', ms: 1000 * 60 * 60 * 24 },
{ name : 'hour', ms: 1000 * 60 * 60 },
{ name : 'second', ms: 1000 *60 },
];
var ms = new Date() - date;
var item = units.find( item => ms / item.ms > 1 );
if (!item) item = units[ units.length - 1 ]; // if not found, use the last one.
var value = Math.floor( ms / item.ms );
return value + " " + item.name + ((value == 1) ? "" : "s") + " ago";
}
我正在使用一些 JS 来计算自上次 post(即 "Posted 2 hours ago")以来的时间:
function ago(date) {
function render(n, unit) {
return n + " " + unit + ((n == 1) ? "" : "s") + " ago";
}
var seconds = Math.floor((new Date() - date) / 1000);
var interval = Math.floor(seconds / (60 * 60 * 24 * 30 * 365));
if (Math.floor(seconds / (60 * 60 * 24 * 30 * 365)) >= 1) {
return render(interval, "year");
}
interval = Math.floor(seconds / (60 * 60 * 24 * 30));
if (interval >= 1) {
return render(interval, "month");
}
interval = Math.floor(seconds / (60 * 60 * 24));
if (interval >= 1) {
return render(interval, "day");
}
interval = Math.floor(seconds / (60 * 60));
if (interval >= 1) {
return render(interval, "hour");
}
interval = Math.floor(seconds / 60);
if (interval >= 1) {
return render(interval, "minute");
}
interval = Math.floor(seconds);
return render(interval, "second");
}
然后将其包含在索引页中,紧挨着每个 post:
var date =
Date.parse(document.getElementById("postedon").getAttribute("datetime"));
document.getElementById("postedago").innerHTML = ago(date);
这里是 HTML:
<time id="{{ post.postedon }}" datetime="{{ post.date | date_to_xmlschema }}">
<span id="{{ post.postedago }}"></span>
</time>
请注意,我正在使用 Liquid & YAML(使用 Jekyll)在每个 post 的前文中设置元素的 ID 和属性:
---
date: 2018-1-4 02:00:00 +0100
postedago: postedago-post1
postedon: postedon-post2
---
问题是我必须像这样手动设置每个 post 的 JS 代码:
var date =
Date.parse(document.getElementById("postedon").getAttribute("datetime"));
document.getElementById("postedago").innerHTML = ago(date);
var date =
Date.parse(document.getElementById("postedon2").getAttribute("datetime"));
document.getElementById("postedago2").innerHTML = ago(date);
var date =
Date.parse(document.getElementById("postedon3").getAttribute("datetime"));
document.getElementById("postedago3").innerHTML = ago(date);
否则它不会显示所有 post 的时间,只显示一个。
我尝试将 JS 中的元素 id 设置为 front matter 参数但它不起作用(本质上是让 Jekyll 替换 JS 文件中的 liquid 标签):
var date =
Date.parse(document.getElementById("{{ post.postedon }}").getAttribute("datetime"));
document.getElementById("{{ post.postedago }}").innerHTML = ago(date);
我尝试在 js 文件的顶部添加前面的破折号,但它仍然不起作用(如 SO 此处所引用:
---
---
//rest of your JavaScript
也许还有其他我没想到的方法?
感谢您花时间阅读本文,非常感谢您的帮助!
PS:参考 timeago 每个 post 页面上的脚本实现(不在包含所有 post 的索引页面上) : https://hejnoah.com/posts/timeago.html
这很简单,你可以使用一些 JS(/javascript-time-ago) 准备好..
仅用作下面的示例..
timeAgo.format(new Date()) ---> will output // "just now"
如果你要给它日期格式,会给出多少时间之前。
你应该给你的 HTML 元素一个 class
属性,这样你就可以使用 getElementsByClassName()
.
HTML:
<time class="postedon" id="{{ post.postedon }}" datetime="{{ post.date | date_to_xmlschema }}">
<span class="postedago" id="{{ post.postedago }}"></span>
</time>
JS:
const timeElems = document.getElementsByClassName('postedon');
for (let i = 0, len = timeElems.length; i < len; i++) {
let date = Date.parse(timeElems[i].getAttribute("datetime"));
timeElems[i].firstElementChild.innerHTML = ago(date);
}
现在您不必为每个 post 手动写出 JS。您可以类似地使用 getElementsByTagName('time')
假设这是您使用该标签的唯一地方。
首先,您的 ago
功能可以简化和减少。
然后我会使用 属性以 开头的选择器和 querySelectorAll
来获取元素,并使用 .forEach()
来设置 textContent
来自属性。
function render(n, unit) {
return n + " " + unit + ((n == 1) ? "" : "s") + " ago";
}
const labels = ["year", "month", "day", "hour", "minute", "second"];
const products = [1, 60, 60, 24, 30, 365]
.map((n, i, a) => a.slice(0, a.length-i).reduce((p, n) => p * n, 1));
function ago(date) {
var seconds = Math.floor((new Date() - Date.parse(date)) / 1000);
return labels.reduce((res, lab, i) => {
const interval = Math.floor(seconds / products[i]);
return res ? res : interval >= 1 ? render(interval, lab) : "";
}, "");
}
document.querySelectorAll("[id^=postedon]").forEach(el =>
el.querySelector('#' + el.id.replace('postedon', 'postedago'))
.textContent = ago(el.getAttribute("datetime"))
);
<time id="postedon0" datetime="2018-1-4 02:00:00 +0100">
<span id="postedago0"></span>
</time>
<time id="postedon1" datetime="2018-1-7 02:00:00 +0100">
<span id="postedago1"></span>
</time>
<time id="postedon2" datetime="2018-1-9 02:00:00 +0100">
<span id="postedago2"></span>
</time>
<time id="postedon3" datetime="2018-1-13 02:00:00 +0100">
<span id="postedago3"></span>
</time>
另请注意,我使用的是 .textContent
而不是 .innerHTML
,因为您实际上并未设置任何 HTML 内容。
另请注意,Date.parse
不适用于 Firefox 中的该日期格式。
另一个关于如何计算时间的例子。
function ago(date) {
var units = [
{ name : 'year', ms: 1000 * 60 * 60 * 24 * 30 * 365 },
{ name : 'month', ms: 1000 * 60 * 60 * 24 * 30 },
{ name : 'fortnight', ms : 1000 * 60 * 60 * 24 * 14 }, // yep.. I head that was a thing.
{ name : 'day', ms: 1000 * 60 * 60 * 24 },
{ name : 'hour', ms: 1000 * 60 * 60 },
{ name : 'second', ms: 1000 *60 },
];
var ms = new Date() - date;
var item = units.find( item => ms / item.ms > 1 );
if (!item) item = units[ units.length - 1 ]; // if not found, use the last one.
var value = Math.floor( ms / item.ms );
return value + " " + item.name + ((value == 1) ? "" : "s") + " ago";
}