(十八)目录处理与文章浏览量的处理
说明
上节课我们把文章的详情信息已经渲染出来了,而且还为文章生成了目录,这节课我们将这个目录浮动起来,然后为我们的站点加上返回顶部的按钮,再把文章浏览功能做一下
返回顶部
这里可以直接参考我之前写的文章:jQuery实现一个优雅的返回顶部
- 用一个
div
做父容器并让其的position
为fixed
这样就可以固定位置了 - 将返回顶部的按钮及QQ联系的按钮放入容器并将到顶部的按钮隐藏
- 判断滚动条高度大于屏幕高度一半时展示到顶部的按钮
- 给顶部按钮一个滚动到滚动条到顶部的功能
<!--common.html-->
<style>
#lw-right-bottom-bar {
position: fixed;
bottom: 50px;
font-size: 18px;
right: 20px;
}
#lw-right-bottom-bar a {
margin-top: 4px;
display: block;
background-color: rgba(0, 0, 0, .5);
color: #fff;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
}
#lw-right-bottom-bar #lw-to-top {
opacity: 0;
}
</style>
<div id="lw-right-bottom-bar">
<a id="lw-to-top" href="javascript:void(0)"><i class="fa fa-arrow-up"></i></a>
<a target="_blank" th:href="${T(java.lang.String).format('tencent://message/?uin=%s&Site=&menu=yes',@webSite.qq)}"><i
class="fa fa-qq"></i></a>
</div>
</div>
<script>
$(function () {
$(window).scroll(function () {
let toTop = $(window).scrollTop()
let height = $(window).height()
if (toTop > height / 2) {
$('#lw-to-top').stop().animate({
opacity: 1
},500)
} else {
$('#lw-to-top').stop().animate({
opacity: 0
},500)
}
})
$('#lw-to-top').on('click',function () {
$('body,html').stop().animate({
scrollTop:0
})
})
})
</script>
文章目录处理
目录浮动
和上面思路差不多,只不过这里就稍微有一点逻辑了,我们此时判断的条件是滚动条滚动的高度大于标签云的底部时进行浮动
- 先定义一个浮动的样式确定样式
#lw-toc-parent.lw-toc-fixed {
position: fixed;
z-index: 999;
top: 10px;
width: 300px;
}
- 判断滚动条高度是否满足条件,如果满足直接给容器加上我们定义的浮动的样式
$(window).scroll(function () {
let toTop = $(window).scrollTop()
let tagCloud = $('.lw-right-item.lw-tag-cloud');
let tagBottom = tagCloud.offset().top + tagCloud.height()
if (toTop > tagBottom - 10) {
$('#lw-toc-parent').addClass('lw-toc-fixed')
}else{
$('#lw-toc-parent').removeClass('lw-toc-fixed')
}
})
滚动优化
我们点一下目录直接跳到对应位置难免有些生硬,所以我们可以为其加上过渡动画
- 取消目录
a
标签的href
,将对应目录的id
保存到data-id
的属性中
$('#lw-article-toc').append(`<li><a style="padding-left: ${left}px;" href="javascript:void(0)" data-id="${$(element).attr('id')}">${$(element).text()}</a></li>`)
- 注册
a
标签的点击事件,当点击时滚动到目录距顶部的高度
$('#lw-article-toc').on('click', 'li a', function () {
let id = $(this).data('id')
$('body,html').stop().animate({
scrollTop:$(`#${id}`).offset().top
})
})
基于Cookie的文章浏览量统计
文章的浏览量无非就是当用户查看文章详情时我们给浏览量加1,但此时我们需要处理一下,即一个用户在一段时间内浏览多次文章我们都应该认为是1次,我们确定一个用户的标准可以是一个浏览器这一个用户,借助浏览器的Cookie来保存浏览记录
- 我们先写更新浏览量的
Mapper
层代码
@Transactional
@Modifying
@Query(value = "update blog_article set views=views+1 where id=13",nativeQuery = true)
void viewsArticle();
- 在
Service
调用Mapper层代码
public void viewArticle(Integer id) {
mapper.viewsArticle(id);
}
- 在文章详情页去调用一下更新浏览量
- 我们先看看效果,发现会有我们上面说的问题,一个用户重复的去访问一篇文章,它会不停的刷新浏览量
- 我们这个时候来将文章的浏览记录放到
Cookie
中,当Cookie
中有这篇文章的浏览记录时我们就不更新
@GetMapping("/{id}.html")
public String detail(@PathVariable Integer id, Model model, HttpServletRequest request, HttpServletResponse response) {
Article article = articleService.detail(id);
if (Objects.isNull(CookieUtil.getCookie(request, Article.VIEW_PREFIX + id))) {
articleService.viewArticle(id);
CookieUtil.setCookie(response, Article.VIEW_PREFIX + id, "true");
}
//todo 当文章不存在时的处理
model.addAttribute("article", article);
return "detail";
}
Cookie工具类
package cn.kevinlu98.utils;
import lombok.SneakyThrows;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
public class CookieUtil {
public static String getCookie(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(cookieName)) {
return cookie.getValue();
}
}
}
return null;
}
public static void setCookie(HttpServletResponse response, String cookieName, String value, int cookieMaxAge) {
Cookie cookie = new Cookie(cookieName, value);
cookie.setPath("/");
cookie.setMaxAge(cookieMaxAge);
response.addCookie(cookie);
}
public static void setCookie(HttpServletResponse response, String cookieName, String value) {
setCookie(response, cookieName, value, 7 * 24 * 60 * 60);
}
public static void deleteCookie(HttpServletResponse response, String cookieName) {
setCookie(response, cookieName, null, 0);
}
}
独立页面的处理
独立页面我们就不显示浏览量、分类、标签还有文章目录的信息了
th:if="${article.type eq T(cn.kevinlu98.pojo.Article).TYPE_ARTICLE}"
看看
多谢大佬分享
强强强
感谢作者!
感谢!