Typecho 文档:文章(日志)段落的点评(评论)功能
适用程序:Typecho
程序版本:1.2.1
文档作者:Lopwon
作者博客:Lopwon.com
发布页面:Lopwon.com/3508.html
许可方式:CC BY-NC-SA
注意:此文档源于作者在博客改造中的一些经验总结,转载还请署名。
敬告:此文档操作涉及程序核心文件的修改,作者不对你在使用中产生的任何问题造成的不良后果,承担责任。
文档说明
在 Typecho 论坛上看到一则需求帖子,虽然年代有些久远,源自2014年,但是觉得想法很是不错,就尝试着去实现它,在 ChatGPT 的协助下,完成了大部分的功能,除了没有涉及数据库外,基本满足了帖子提到的需求。
暂时没有做样式上优化,之后可能会做成插件,继续新增一些其他功能,比如:点击段落引用时,以弹窗的方式加载评论区;能够区分引用的和点评的内容;能够平滑滚动到锚点;引用段落显示小图标;段落被点评的次数……等等。
工作原理:Typecho 默认有 autoP 功能,以此作为段落的划分,这样就能对每个 <p>
添加 id 标记,用于引用和定位,另外,功能实现上也加入常用的引用元素 <blockquote>
主要功能:
1. 点击段落后,将该段落的截断内容(或图片)插入评论内容中,并跳至评论区。
2. 提交评论后,点击点评时引用的段落,也会跳至文章对应的段落。
3. 要注意的是,使用段落点评功能后,文章请勿再新增段落,否则,已提交引用且点评的段落会和编辑后文章段落的 id 对不上。当然,可以在保持段落位置和数量不变的情况下,对文章内容文字做编辑。
使用方法
A 涉及文件
usr/themes/***/footer.php
B 改造文件
作用:给文章段落添加点评功能
1. 后台》设置》评论,在(允许使用的HTML标签和属性)项里输入 <img src="">
2. 以上操作的作用是:让评论内容解析输出图片。
3. 打开你在用主题下的文件 footer.php 找个合适的位置添加以下代码(留意注释,以及按需修改):
<script>
const container = document.querySelector('.post-content'); // 获取文章内容的容器元素 post-content(根据自己的主题修改)
const paragraphs = container.querySelectorAll('p'); // 获取文章内容所有的 <p> 元素(依据 Typecho 默认的 autoP 功能)
const blockquotes = container.querySelectorAll('blockquote'); // 获取文章内容所有的 <blockquote> 元素(即:引用)
const comments = document.querySelectorAll('.comment-content p'); // 获取评论内容所有的 <p> 元素(根据自己的主题修改,通常为 .comment-content p)
const textarea = document.getElementById('textarea'); // 获取评论内容的表单 <textarea> (根据自己的主题修改,通常为 textarea)
paragraphs.forEach((p, index) => { // 遍历文章内容所有 <p> 元素,并分配 id
const id = `p${index + 1}`; // 自定义 p 为前缀
p.setAttribute('id', id); // 添加 id
const imgElement = p.querySelector('img'); // 查找 <p> 元素中的 <img> 元素
if (imgElement) { // 如果 <p> 包含 <img> 元素,则将图片信息添加到 <textarea>
const imageSrc = imgElement.getAttribute('src'); // 获取图片的 src 属性
const imageAlt = imgElement.getAttribute('alt'); // 获取图片的 alt 属性
p.addEventListener('click', () => { // 添加点击事件处理程序
const imgTag = `<img src="${imageSrc}" alt="${imageAlt}" />`; // 添加到 <textarea> 的内容结构,如果不想显示图片,则改为 `${imageAlt}`(即:只显示 alt 部分)
addToTextarea(id, imgTag); // 添加标记信息,并传递给 addToTextarea 函数
focusTextarea(); // 调用 focusTextarea() 方法,使 <textarea> 获取焦点
textarea.scrollIntoView({ behavior: 'smooth' }); // 滚动到 <textarea> 的位置
});
} else { // 如果 <p> 不包含 <img> 元素,则将文本内容添加到 <textarea>
p.addEventListener('click', () => { // 添加点击事件处理程序
const content = p.textContent; // 定义内容
const maxLength = 32; // 设置截取的最大字数
const truncatedContent = truncateString(content, maxLength); // 截断后的内容
addToTextarea(id, truncatedContent); // 添加标记信息,并传递给 addToTextarea 函数
focusTextarea(); // 调用 focusTextarea() 方法,使 <textarea> 获取焦点
textarea.scrollIntoView({ behavior: 'smooth' }); // 滚动到 <textarea> 的位置
});
}
});
blockquotes.forEach((blockquote, index) => { // 遍历所有的 <blockquote> 元素,并分配 id
const id = `blockquote${index + 1}`; // 自定义 blockquote 为前缀
blockquote.setAttribute('id', id); // 添加 id
blockquote.addEventListener('click', () => { // 添加点击事件处理程序
const content = blockquote.textContent // 定义内容
const maxLength = 32; // 设置截取的最大字数
const truncatedBlockquote = truncateString(content, maxLength); // 截断后的内容
addToTextarea(id, truncatedBlockquote); // 添加标记信息,并传递给 addToTextarea 函数
focusTextarea(); // 调用 focusTextarea() 方法,使 <textarea> 获取焦点
textarea.scrollIntoView({ behavior: 'smooth' }); // 滚动到 <textarea> 的位置
});
});
function truncateString(str, maxLength) { // 截取字符串到指定长度
if (str.length > maxLength) { // 截取内容
return str.substring(0, maxLength) + '...'; // 输出内容,多出的以 ... 代替
}
return str;
}
function focusTextarea() { // 使 <textarea> 获取焦点的函数
textarea.focus();
}
function addToTextarea(paragraphId, content) { // 添加内容到 <textarea> 同时记录标记信息
const existingContent = textarea.value; // 获取 <textarea> 中已有的内容
const newLine = existingContent ? '\n' : ''; // 判断是否已有内容,如果有则另起一行
textarea.value += newLine + '\n' + `引用 [${paragraphId}]:${content} \n\n`; // 使用中括号来标记唯一标识符,并插入内容及空行
}
comments.forEach((p) => { // 遍历所有的 <comments> 元素
p.addEventListener('click', () => { // 添加点击事件处理程序
const targetDataId = p.textContent.match(/\[(.*?)\]/)[1]; // 只保留方括号里的 id 编码
const targetParagraph = container.querySelector(`#${targetDataId}`); // 查找文章内容中对应的 id
if (targetParagraph) {
targetParagraph.scrollIntoView({ behavior: 'smooth' }); // 滚动到文章内容对应 id 的位置
}
});
});
</script>
至此,已经可以通过点击文章段落点评该段落内容(或图片)了。