
最后的效果图如上,大家不难发现这个回复的想法和知乎的回复模式差不多(因为我就是照着那个思路实现的 :) ),只是这里少实现了查看对话的功能。下面说说我实现这个过程中遇到的一些困难。
首先讲讲我的数据库的实现:
RId指的是每个评论的唯一id,这个R取得是review(评论)的意思
RTId指的是每条帖子的id
RRId指的是被回复的评论的id,如果有就是其id,无为0
ROwnerName指的是此条评论的人的名字
RTargetName指的是被回复的人的名字,可空
RComments指的是评论的内容
RTime指的是评论的时间
(1)如何实现点击图中的“回复”按钮,在评论下方就弹出一个输入框。
这个很好实现,主要涉及到的就是一些js的知识。
那么,到底该怎么实现点击“回复”,就在这个评论下方弹出一个输入框而不是在其他的输入框下弹出呢?
我们首先得给这个输入框所在的div分配一个唯一的id,这里我们可以使用评论的RId。
然后再给回复按钮添加监听函数,也就是设置其onclick属性,传入的参数就是输入框的id。每当点击按钮的时候,都改变输入框所在div的display属性
<button type="button" class="btn btn-secondary" onclick="hide('#{specificReview.RId}')">回复</button> <br />
<p class="cContent">#{specificReview.RComments}</p> <!--每个人回复的评论 --> <br />
<div class="comment-edit" id="#{specificReview.RId}" style=" display: none;">
<h:inputTextarea id="doubleComments"
class="form-control edit"
value="#{comment.RDComments}"
/>
<!--<h:message for="doubleComments" style="color:red"/>-->
<div class="preview">
<div class="buttons">
<h:commandButton immediate="true" class="btn btn-secondary" rendered="#{!login.isLogin()}" value="评论前请先登录" action="#{navBean.login}" />
<h:commandButton id="submitButton" rendered="#{login.isLogin()}" actionListener="#{discuss.setTopic(discuss.topic)}" action="#{comment.storeIntoDB(discuss.topic.TId, specificReview.RId, login.userName, specificReview.ROwnerName)}" class="btn btn-primary post broadcast" value="回复"/>
</div>
</div>
</div>
下面是javascript的代码
<script>
function hide(a) {
if (document.getElementById(a).style.display !== 'none')
{
document.getElementById(a).style.display = 'none';
}
else
{
document.getElementById(a).style.display = '';
}
}
</script>
可能有的猿友会疑惑那些 h: 和 #{} 是什么东西。
这个h:是JSF框架下的组件(应该不影响阅读吧,感觉和 HTML 的元素差不多),#{}是EL表达式。
(2)我们可以看到,有那么多输入框(只是很多的display都是none,并没有显示)。那么如何确保获取到的输入框的值恰巧是我们评论的输入框的值呢?
我们都不难想到使用EL表达式来取值,也就是上面代码中的<h:inputTextArea value="#{comment.RDComments}">
但是大家可能会遇到下面这个问题:在点击“评论”按钮时,相当于提交表单,而这里就会默认将你回复的评论下面的所有的<h:inputTextArea>(也就是我们的输入框)中的value=#{comment.RDComments}执行一遍,这就导致了我们获取的评论值总是为空的情况。
那么该怎么解决这个情况呢?
其实很简单,就是在set函数中判断一下,如果获取的值为空,就不赋值。
public void setRDComments(String RDComments) {
if (RDComments.length() > 0) {
this.RDComments = RDComments;
}
}
(3)如何实现评论判空,我有两个想法
1. 点击“评论”按钮会在其下面弹出唯一一个提示框,提示内容是“评论不能为空”。
2.评论为空时,将评论按钮disabled掉,这个给输入框添加onchange函数就行,在函数里使用getElementById获取到输入框的value,为空则disabled。
无论哪个想法,都绕不开给这个输入框分配一个唯一的id,因为我好像并没有找到获取到一个div的element,然后再获取其间的其他元素的js方法。说的有点绕
<div id="onlyOne">
<input name="inputText" type="text" />
<button name="submitButton" type="button">回复</button>
</div>
就是我知道这个div的id是"onlyOne",我能不能通过document.getElementById("onlyOne"),然后通过某种方法得到这个div中name为inputText或者为submitButton的组件的value呢?希望有路过的猿友能提示一下到底有没有这样一种方法。
<2020-05-13> 这个是可以的,我随手搜了一下,感觉 https://stackoverflow.com/a/5753895/10315163 这个就很不错。
先说一下,其实我并没有实现这个功能,只有几点关于给输入框分配唯一id的想法。
没实现的原因是在JSF框架下,其组件的id是变的(这个我就十分不理解)。
就像上面这个图中的id,前面的那个j_idt157怎么搞都搞不掉,后面那个10指的是这个页面第几个输入框(这个是自动生成的,0是第1个,10就是第11个),最后面的doubleComments才是设置的id。
为了让这个输入框的id唯一,我尝试了一个组合id的方法:
<div class="comment-edit" id="#{specificReview.RId}Div" style=" display: none;">
<h:inputTextarea id="#{specificReview.RId}doubleComments"
class="form-control edit"
value="#{comment.RDComments}"
/>
<!--<h:message for="doubleComments" style="color:red"/>-->
<div class="preview">
<div class="buttons">
<h:commandButton immediate="true" class="btn btn-secondary" rendered="#{!login.isLogin()}" value="评论前请先登录" action="#{navBean.login}" />
<h:commandButton id="submitButton" rendered="#{login.isLogin()}" actionListener="#{discuss.setTopic(discuss.topic)}" action="#{comment.storeIntoDB(discuss.topic.TId, specificReview.RId, login.userName, specificReview.ROwnerName)}" class="btn btn-primary post broadcast" value="回复"/>
</div>
</div>
</div>
就是将id扩展一下,将原来的div的id改为"#{specificReview.RId}Div"(这样亲测有效),然后把输入框的id扩展为"#{specificReview.RId}doubleComments",然而这样并没有啥用,这个输入框的id依然是系统自己给分配的。
然而,我依旧不信邪,既然div能实现组合id,那你这个输入框为啥不行,然后我就把这个输入框的id设置为"#{specificReview.RId}",然后它却报错了,报错原因是id不能为空。
不过我还有一个想法,就是不使用div布局了,改用table布局。给这个table分配唯一id为"#{specificReview.RId}",然后我们就有一个document.getElementById("tableId").rows[id].cells[1].innerText;来获取到其下的<td>的值。不过我没有具体了解这个js方法,能不能实现我也不能保证。
如果有猿友按照这个想法实现了,能不能劳烦通知我一声,毕竟我也想知道这玩意能不能成。
(4)如何获取到被回复的人的评论的id
这个可以通过添加函数action或者actionListener实现,然后将这个id作为调用函数的参数传进去,在调用的函数里保存这个id。
当然实现类似的回复功能的方法有很多,我的这个只能算是其中的比较基础的一个。我在查看知乎评论的页面源码的时候,好像还没有发现知乎的评论输入框都有一个id之类的,这也是让我很困惑的地方。
<2020-05-13> 这个东西是我好久以前做的,当时我们小组连版本管理都没有(我也不知道这个概念 XD),改完东西都是通过 U 盘拷贝来拷贝去的。依稀记得每次交换完最新代码我都是用类似 project1 等名称来命名那个文件夹,当时是清楚啥是啥,现在回去看都无法确定哪个是最新的。现在回头看来真的是感慨万千。
<2020-05-13> 我对这个项目依稀的记忆是基于 JSF 的,然后还有 Java Bean,企业 Bean 什么的,服务器是 Glassfish(至于为什么不是 tomcat,我姑且不知道),IDE 是 Netbeans。这些都是个什么东西我早就忘的一干二净了,就连怎么运行这个项目也不记得了。剩下的只是项目文件夹下 12 的无意义的文件,和这篇记录当时自己颠簸的文章。还有最上面那个演示的 GIF 里回复后自动回到顶部的奇怪 bug。所以源码是不会提供了...,而且只要思路清晰,写出代码是没有问题的。(这个观念是我最近看完《如何阅读一本书》后和自己经历对比后坚信的,书中说“一个人如果说他知道他在想些什么,却说不来,通常是他其实并不知道他自己在想些什么。”)
<2020-05-13> 刚刚看到了有人分享 MIT 的 [The Missing Semester of Your CS Education](https://missing.csail.mit.edu/) 这个课程,想到了自己一直不愿意直面的这篇文章,也想到了前几个月无意中逛到的几个人 ice1000、ibug...,想起了龙应台的目送:“你和他的缘分就是今生今世不断地在目送他的背影渐行渐远。你站在小路的这一端,看着他逐渐消失在小路转弯的地方,而且,他用背影默默地告诉你,追不上。”(有改)。