header顶部菜单(前端)
补发大年初三学习笔记
1.黑白模式
使用开源的darkreader
yarn add darkreader
2.在src/components创建Layout/Hearder.vue
<template>
<header class="header has-background-white has-text-black">
<b-navbar class="container is-white" :fixed-top="true">
<template slot="brand">
<b-navbar-item tag="div">
<img :src="doubaoImg" alt="logo" />
</b-navbar-item>
<b-navbar-item class="is-hidden-desktop" tag="router-link" :to="{ path: '/' }">主页</b-navbar-item>
</template>
<template slot="start">
<b-navbar-item tag="router-link" :to="{ path: '/' }">🌐 主页</b-navbar-item>
</template>
<template slot="end">
<b-navbar-item tag="div">
<b-field position="is-centered">
<b-input
v-model="searchKey"
class="s_input"
width="80%"
placeholder="搜索帖子、标签和用户"
rounded
clearable
@keyup.enter.native="search()"
/>
<p class="control">
<b-button class="is-info" @click="search()">检索</b-button>
</p>
</b-field>
</b-navbar-item>
<b-navbar-item tag="div">
<b-switch
v-model="darkMode"
passive-type="is-warning"
type="is-dark"
>{{ darkMode ? "夜" : "日" }}</b-switch>
</b-navbar-item>
<b-navbar-item v-if="token == null || token === ''" tag="div">
<div class="buttons">
<b-button class="is-light" tag="router-link" :to="{ path: '/register' }">注册</b-button>
<b-button class="is-light" tag="router-link" :to="{ path: '/login' }">登录</b-button>
</div>
</b-navbar-item>
<b-navbar-dropdown v-else :label="user.alias">
<b-navbar-item tag="router-link" :to="{ path: `/member/${user.username}/home` }">🧘 个人中心</b-navbar-item>
<hr class="dropdown-divider" />
<b-navbar-item tag="router-link" :to="{ path: `/member/${user.username}/setting` }">⚙ 设置中心</b-navbar-item>
<hr class="dropdown-divider" />
<b-navbar-item tag="a" @click="logout">👋 退出登录</b-navbar-item>
</b-navbar-dropdown>
</template>
</b-navbar>
</header>
</template>
<script>
import {
disable as disableDarkMode,
enable as enableDarkMode
} from "darkreader";
import { getDarkMode, setDarkMode } from "@/utils/auth";
import { mapGetters } from "vuex";
export default {
name: "Header",
data() {
return {
logoUrl: require("@/assets/logo.png"),
doubaoImg: require("@/assets/image/doubao.png"),
searchKey: "",
darkMode: false
};
},
computed: {
...mapGetters(["token", "user"])
},
watch: {
// 监听Theme模式
darkMode(val) {
if (val) {
enableDarkMode({});
} else {
disableDarkMode();
}
setDarkMode(this.darkMode);
}
},
created() {
// 获取cookie中的夜间还是白天模式
this.darkMode = getDarkMode();
if (this.darkMode) {
enableDarkMode({});
} else {
disableDarkMode();
}
},
methods: {
async logout() {
this.$store.dispatch("user/logout").then(() => {
this.$message.info("退出登录成功");
setTimeout(() => {
this.$router.push({ path: this.redirect || "/" });
}, 500);
});
},
search() {
console.log(this.token);
if (this.searchKey.trim() === null || this.searchKey.trim() === "") {
this.$message.info({
showClose: true,
message: "请输入关键字搜索!",
type: "warning"
});
return false;
}
this.$router.push({ path: "/search?key=" + this.searchKey });
}
}
};
</script>
<style scoped>
input {
width: 80%;
height: 86%;
}
</style>
3.在App.vue引入
4.查看页面
存在问题,刷新后用户名不显示,初次登录显示
解决刷新不显示用户名
0.删除代码
删除viwes/log.vue中这一个代码
this.$store.dispatch("user/getInfo")
1.下载nprogress
刷新时显示顶部显示蓝色刷新进度条
yarn add nprogress
2./utils/创建get-page-title
const title = '小而美的智慧社区系统'
export default function getPageTitle(pageTitle) {
if (pageTitle) {
return `${pageTitle} - ${title}`
}
return `${title}`
}
3.src/创建permission.js
import router from './router'
import store from './store'
import getPageTitle from '@/utils/get-page-title'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'
import {getToken} from "@/utils/auth"; // progress bar style
NProgress.configure({showSpinner: false}) // NProgress Configuration
router.beforeEach(async (to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken();
if (hasToken) {
if (to.path === '/login') {
// 登录,跳转首页
next({path: '/'})
NProgress.done()
} else {
// 获取用户信息
await store.dispatch('user/getInfo')
next()
}
} else {
next()
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
4.main.js引入
import '@/permission.js'
5.查看效果
此时刷新页面用户名不会消失,刷新时显示顶部显示蓝色刷新进度条,页面显示 注册-小而美的智慧社区系统
退出登录后端
@GetMapping("/logout")
public ApiResult logout() {
return ApiResult.success(null, "注销成功");
}
退出登录前端
1.修改src\store\modules\user.js
已添加,看看就行
2.API接口
src\api\auth\auth.js添加注销接口
// 注销
export function logout() {
return request({
url: '/auth/user/logout',
method: 'get'
})
}
3.测试问题
当在首页退出登录,报下面这个问题(可以正常退出)
4.解决
在src\router\index.js添加
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err);
};
底部(前端)
1.src\components\创建Backtop\BackTop.vue
<template>
<el-backtop :bottom="60" :right="60">
<div title="回到顶部"
style="{
height: 100%;
width: 100%;
background-color: #f2f5f6;
box-shadow: 0 1px 0 0;
border-radius: 12px;
text-align: center;
line-height: 40px;
color: #167df0;
}"
>
<i class="fa fa-arrow-up"></i>
</div>
</el-backtop>
</template>
<script>
export default {
name: "BackTop"
}
</script>
<style scoped>
</style>
2.src\components\Layout创建\Footer.vue
<template>
<footer class="footer has-text-grey-light has-background-grey-darker">
<div class="container">
<div class="">
<span>简洁、实用、美观</span>
<span style="float: right">
<router-link :to="{path:'/admin/login'}">
管理员登录
</router-link>
|
<a href="/?lang=zh_CN">中文</a> |
<a href="/?lang=en_US">English</a>
</span>
</div>
<div>
<span>{{ title }} ALL RIGHTS RESERVED</span>
<div style="float: right">
<template>
<b-taglist attached>
<b-tag type="is-dark" size="is-normal">Design</b-tag>
<b-tag type="is-info" size="is-normal">{{ author }}</b-tag>
</b-taglist>
</template>
</div>
</div>
</div>
<back-top></back-top>
</footer>
</template>
<script>
// 回到顶部
import BackTop from "@/components/Backtop/BackTop";
export default {
name: "Footer",
components: {
BackTop
},
data() {
return {
title: "© " + new Date().getFullYear() + ' 豆约翰',
author: '豆约翰',
};
},
};
</script>
<style scoped>
footer {
margin-top: 120px;
height: 150px;
}
footer a{
color: #bfbfbf;
}
</style>
3.App.vue
帖子列表前端
1.下载格式时间
yarn add dayjs
2.src\main.js添加
// 国际化
import 'dayjs/locale/zh-cn'
const dayjs = require('dayjs');
// 相对时间插件
dayjs.extend(relativeTime)
dayjs.locale('zh-cn') // use locale globally
dayjs().locale('zh-cn').format() // use locale in a specific instance
Vue.prototype.dayjs = dayjs;//可以全局使用dayjs
Vue.filter('date', (date) => {
return format(new Date(date), 'yyyy-MM-dd')
})
3.新增src\api\post.js
import request from '@/utils/request'
// 列表
export function getList(pageNo, size, tab) {
return request(({
url: '/post/list',
method: 'get',
params: { pageNo: pageNo, size: size, tab: tab }
}))
}
4. 修改src\views\post\index.vue
替换即可
<template>
<div>
<el-card shadow="never">
<div slot="header" class="clearfix">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="最新主题" name="latest">
<article v-for="(item, index) in articleList" :key="index" class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="`https://cn.gravatar.com/avatar/${item.userId}?s=164&d=monsterid`" style="border-radius: 5px;">
</figure>
</div>
<div class="media-content">
<div class="">
<p class="ellipsis is-ellipsis-1">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{name:'post-detail',params:{id:item.id}}">
<span class="is-size-6">{{ item.title }}</span>
</router-link>
</el-tooltip>
</p>
</div>
<nav class="level has-text-grey is-mobile is-size-7 mt-2">
<div class="level-left">
<div class="level-left">
<router-link class="level-item" :to="{ path: `/member/${item.username}/home` }">
{{ item.alias }}
</router-link>
<span class="mr-1">
发布于:{{ dayjs(item.createTime).format("YYYY/MM/DD") }}
</span>
<span
v-for="(tag, index) in item.tags"
:key="index"
class="tag is-hidden-mobile is-success is-light mr-1"
>
<router-link :to="{ name: 'tag', params: { name: tag.name } }">
{{ "#" + tag.name }}
</router-link>
</span>
<span class="is-hidden-mobile">浏览:{{ item.view }}</span>
</div>
</div>
</nav>
</div>
<div class="media-right" />
</article>
</el-tab-pane>
<el-tab-pane label="热门主题" name="hot">
<article v-for="(item, index) in articleList" :key="index" class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="`https://cn.gravatar.com/avatar/${item.userId}?s=164&d=monsterid`" style="border-radius: 5px;">
</figure>
</div>
<div class="media-content">
<div class="">
<p class="ellipsis is-ellipsis-1">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{name:'post-detail',params:{id:item.id}}">
<span class="is-size-6">{{ item.title }}</span>
</router-link>
</el-tooltip>
</p>
</div>
<nav class="level has-text-grey is-mobile is-size-7 mt-2">
<div class="level-left">
<div class="level-left">
<router-link class="level-item" :to="{ path: `/member/${item.username}/home` }">
{{ item.alias }}
</router-link>
<span class="mr-1">
发布于:{{ dayjs(item.createTime).format("YYYY/MM/DD") }}
</span>
<span
v-for="(tag, index) in item.tags"
:key="index"
class="tag is-hidden-mobile is-success is-light mr-1"
>
<router-link :to="{ name: 'tag', params: { name: tag.name } }">
{{ "#" + tag.name }}
</router-link>
</span>
<span class="is-hidden-mobile">浏览:{{ item.view }}</span>
</div>
</div>
</nav>
</div>
<div class="media-right" />
</article>
</el-tab-pane>
<el-tab-pane label="最近修改" name="udpate">
<article v-for="(item, index) in articleList" :key="index" class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="`https://cn.gravatar.com/avatar/${item.userId}?s=164&d=monsterid`" style="border-radius: 5px;">
</figure>
</div>
<div class="media-content">
<div class="">
<p class="ellipsis is-ellipsis-1">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{name:'post-detail',params:{id:item.id}}">
<span class="is-size-6">{{ item.title }}</span>
</router-link>
</el-tooltip>
</p>
</div>
<nav class="level has-text-grey is-mobile is-size-7 mt-2">
<div class="level-left">
<div class="level-left">
<router-link class="level-item" :to="{ path: `/member/${item.username}/home` }">
{{ item.alias }}
</router-link>
<span class="mr-1">
发布于:{{ dayjs(item.createTime).format("YYYY/MM/DD") }}
</span>
<span
v-for="(tag, index) in item.tags"
:key="index"
class="tag is-hidden-mobile is-success is-light mr-1"
>
<router-link :to="{ name: 'tag', params: { name: tag.name } }">
{{ "#" + tag.name }}
</router-link>
</span>
<span class="is-hidden-mobile">浏览:{{ item.view }}</span>
</div>
</div>
</nav>
</div>
<div class="media-right" />
</article>
</el-tab-pane>
</el-tabs>
</div>
</el-card>
</div>
</template>
<script>
import { getList } from '@/api/post'
export default {
name: "TopicList",
data() {
return {
activeName: 'latest',
articleList: [],
};
},
created() {
this.init(this.tab)
},
methods: {
init(tab) {
getList(1, 10, tab).then((response) => {
const { data } = response
this.articleList = data.records
})
},
handleClick(tab) {
this.init(tab.name)
}
}
};
</script>
后端
实体类
BmsPost
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.util.Date;
@Data
@Builder
@TableName("bms_post")
@AllArgsConstructor
@NoArgsConstructor
public class BmsPost implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
/**
* 标题
*/
@NotBlank(message = "标题不可以为空")
@TableField(value = "title")
private String title;
/**
* markdown
*/
@NotBlank(message = "内容不可以为空")
@TableField("`content`")
private String content;
/**
* 作者ID
*/
@TableField("user_id")
private String userId;
/**
* 评论数
*/
@TableField("comments")
@Builder.Default
private Integer comments = 0;
/**
* 收藏数
*/
@TableField("collects")
@Builder.Default
private Integer collects = 0;
/**
* 浏览数
*/
@TableField("view")
@Builder.Default
private Integer view = 0;
/**
* 专栏ID,默认不分栏
*/
@TableField("section_id")
@Builder.Default
private Integer sectionId = 0;
/**
* 置顶
*/
@TableField("top")
@Builder.Default
private Boolean top = false;
/**
* 加精
*/
@TableField("essence")
@Builder.Default
private Boolean essence = false;
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
/**
* 修改时间
*/
@TableField(value = "modify_time", fill = FieldFill.UPDATE)
private Date modifyTime;
/**
* 描述
*/
@TableField("summary")
private String summary;
}
BmsPostTag
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@TableName("bms_post_tag")
@Accessors(chain = true)
public class BmsPostTag implements Serializable {
private static final long serialVersionUID = -5028599844989220715L;
@TableId(type = IdType.AUTO)
private Integer id;
@TableField("tag_id")
private String tagId;
@TableField("post_id")
private String postId;
}
BmsTag
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Builder
@TableName("bms_tag")
@Accessors(chain = true)
public class BmsTag implements Serializable {
private static final long serialVersionUID = 3257790983905872243L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@TableField("name")
private String name;
/**
* 当前标签下的话题个数
*/
@TableField("post_count")
@Builder.Default
private Integer postCount = 1;
}
Vo
package com.notepad.blog.domain.vo;
import com.notepad.blog.domain.BmsTag;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PostVO implements Serializable {
private static final long serialVersionUID = -261082150965211545L;
/**
* 文章ID
*/
private String id;
/**
* 用户ID
*/
private String userId;
/**
* 头像
*/
private String avatar;
/**
* 用户昵称
*/
private String alias;
/**
* 账号
*/
private String username;
/**
* 标题
*/
private String title;
/**
* 评论统计
*/
private Integer comments;
/**
* 置顶
*/
private Boolean top;
/**
* 加精
*/
private Boolean essence;
/**
* 收藏次數
*/
private Integer collects;
/**
* 话题关联标签
*/
private List<BmsTag> tags;
/**
* 浏览量
*/
private Integer view;
/**
* 创建时间
*/
private Date createTime;
/**
* 修改时间
*/
private Date modifyTime;
/**
* 文章描述
*/
private String summary;
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.notepad.blog.mapper.BmsPostMapper">
<resultMap id="postVo" type="com.notepad.blog.domain.vo.PostVO">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="user_id" property="userId"/>
<result column="comments" property="comments"/>
<result column="view" property="view"/>
<result column="collects" property="collects"/>
<result column="top" property="top"/>
<result column="essence" property="essence"/>
<result column="create_time" property="createTime"/>
<result column="modify_time" property="modifyTime"/>
<result column="username" property="username"/>
<result column="alias" property="alias"/>
<result column="avatar" property="avatar"/>
<result column="summary" property="summary"/>
<collection property="tags" ofType="com.notepad.blog.domain.BmsTag">
<result column="tag_id" property="id"/>
<result column="name" property="name"/>
<result column="post_count" property="postCount"/>
</collection>
</resultMap>
<select id="selectListAndPage" resultMap="postVo">
SELECT
p.id,
p.title,
<!-- p.user_id, -->
p.comments,
p.VIEW,
p.collects,
p.top,
p.essence,
p.create_time,
p.modify_time,
u.username,
u.alias,
u.avatar,
pt.tag_id,
t.`name`,
t.post_count
FROM
bms_post p
LEFT JOIN ums_user u ON p.user_id = u.id
LEFT JOIN bms_post_tag pt ON p.id = pt.post_id
LEFT JOIN bms_tag t ON t.id = pt.tag_id
<if test="tab == 'hot'">
<where>
date(p.create_time) <= date_add(curdate(), interval 1 day)
and date(p.create_time) >= date_sub(curdate(), interval 7 day)
</where>
order by p.view desc, p.create_time desc
</if>
<if test="tab == 'atest'">
order by p.create_time desc
</if>
<if test="tab == 'update'">
<where>
p.modify_time is NOT null
</where>
order by p.modify_time desc
</if>
</select>
</mapper>
mapper层
public interface BmsPostMapper extends BaseMapper<BmsPost> {
Page<PostVO> selectListAndPage(@Param("page") Page<PostVO> page, @Param("tab") String tab);
}java
controller
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.notepad.blog.common.api.ApiResult;
import com.notepad.blog.domain.vo.PostVO;
import com.notepad.blog.service.BmsPostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/post")
public class BmsPostController {
@Autowired
private BmsPostService postService;
@GetMapping("/list")
public ApiResult<Page<PostVO>> list(@RequestParam(value = "tab", defaultValue = "latest") String tab,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "size", defaultValue = "10") Integer pageSize) {
Page<PostVO> list = postService.getList(pageNo,pageSize, tab);
return ApiResult.success(list);
}
}
service
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.notepad.blog.domain.BmsPost;
import com.notepad.blog.domain.BmsPostTag;
import com.notepad.blog.domain.BmsTag;
import com.notepad.blog.domain.vo.PostVO;
import com.notepad.blog.mapper.BmsPostMapper;
import com.notepad.blog.mapper.BmsPostTagMapper;
import com.notepad.blog.mapper.BmsTagMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class BmsPostService extends ServiceImpl<BmsPostMapper, BmsPost> {
@Autowired
private BmsPostMapper postMapper;
public Page<PostVO> getList(Integer pageNo, Integer pageSize, String tab) {
Page<PostVO> page = new Page(pageNo, pageSize);
// 查询文章
Page<PostVO> iPage = postMapper.selectListAndPage(page, tab);
return iPage;
}
}
分页前端
1.src\components创建Pagination\index.vue
<template>
<div :class="{ hidden: hidden }" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import {scrollTo} from "@/utils/scroll-to";
export default {
name: "Pagination",
props: {
total: {
required: true,
type: Number,
},
page: {
type: Number,
default: 1,
},
limit: {
type: Number,
default: 10,
},
pageSizes: {
type: Array,
default() {
return [5, 10, 20, 30, 50];
},
},
layout: {
type: String,
default: "total, sizes, prev, pager, next, jumper",
// default: 'sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true,
},
autoScroll: {
type: Boolean,
default: true,
},
hidden: {
type: Boolean,
default: false,
},
},
computed: {
currentPage: {
get() {
return this.page;
},
set(val) {
this.$emit("update:page", val);
},
},
pageSize: {
get() {
return this.limit;
},
set(val) {
this.$emit("update:limit", val);
},
},
},
methods: {
handleSizeChange(val) {
this.$emit("pagination", { page: this.currentPage, limit: val });
if (this.autoScroll) {
scrollTo(0, 800);
}
},
handleCurrentChange(val) {
this.$emit("pagination", { page: val, limit: this.pageSize });
if (this.autoScroll) {
scrollTo(0, 800);
}
},
},
};
</script>
<style scoped>
.pagination-container {
/* background: #fff; */
padding: 5px 0px;
}
.pagination-container.hidden {
display: none;
}
</style>
2.src\utils创建scroll-to.js
Math.easeInOutQuad = function(t, b, c, d) {
t /= d / 2
if (t < 1) {
return c / 2 * t * t + b
}
t--
return -c / 2 * (t * (t - 2) - 1) + b
}
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
var requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
})()
/**
* Because it's so fucking difficult to detect the scrolling element, just move them all
* @param {number} amount
*/
function move(amount) {
document.documentElement.scrollTop = amount
document.body.parentNode.scrollTop = amount
document.body.scrollTop = amount
}
function position() {
return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
}
/**
* @param {number} to
* @param {number} duration
* @param {Function} callback
*/
export function scrollTo(to, duration, callback) {
const start = position()
const change = to - start
const increment = 20
let currentTime = 0
duration = (typeof (duration) === 'undefined') ? 500 : duration
var animateScroll = function() {
// increment the time
currentTime += increment
// find the value with the quadratic in-out easing function
var val = Math.easeInOutQuad(currentTime, start, change, duration)
// move the document.body
move(val)
// do the animation unless its over
if (currentTime < duration) {
requestAnimFrame(animateScroll)
} else {
if (callback && typeof (callback) === 'function') {
// the animation is done so lets callback
callback()
}
}
}
animateScroll()
}
3.修改src\views\post\index.vue
以下是index.vue的全部内容
<template>
<div>
<el-card shadow="never">
<div slot="header" class="clearfix">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="最新主题" name="latest">
<article v-for="(item, index) in articleList" :key="index" class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="`https://cn.gravatar.com/avatar/${item.userId}?s=164&d=monsterid`" style="border-radius: 5px;">
</figure>
</div>
<div class="media-content">
<div class="">
<p class="ellipsis is-ellipsis-1">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{name:'post-detail',params:{id:item.id}}">
<span class="is-size-6">{{ item.title }}</span>
</router-link>
</el-tooltip>
</p>
</div>
<nav class="level has-text-grey is-mobile is-size-7 mt-2">
<div class="level-left">
<div class="level-left">
<router-link class="level-item" :to="{ path: `/member/${item.username}/home` }">
{{ item.alias }}
</router-link>
<span class="mr-1">
发布于:{{ dayjs(item.createTime).format("YYYY/MM/DD") }}
</span>
<span
v-for="(tag, index) in item.tags"
:key="index"
class="tag is-hidden-mobile is-success is-light mr-1"
>
<router-link :to="{ name: 'tag', params: { name: tag.name } }">
{{ "#" + tag.name }}
</router-link>
</span>
<span class="is-hidden-mobile">浏览:{{ item.view }}</span>
</div>
</div>
</nav>
</div>
<div class="media-right" />
</article>
</el-tab-pane>
<el-tab-pane label="热门主题" name="hot">
<article v-for="(item, index) in articleList" :key="index" class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="`https://cn.gravatar.com/avatar/${item.userId}?s=164&d=monsterid`" style="border-radius: 5px;">
</figure>
</div>
<div class="media-content">
<div class="">
<p class="ellipsis is-ellipsis-1">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{name:'post-detail',params:{id:item.id}}">
<span class="is-size-6">{{ item.title }}</span>
</router-link>
</el-tooltip>
</p>
</div>
<nav class="level has-text-grey is-mobile is-size-7 mt-2">
<div class="level-left">
<div class="level-left">
<router-link class="level-item" :to="{ path: `/member/${item.username}/home` }">
{{ item.alias }}
</router-link>
<span class="mr-1">
发布于:{{ dayjs(item.createTime).format("YYYY/MM/DD") }}
</span>
<span
v-for="(tag, index) in item.tags"
:key="index"
class="tag is-hidden-mobile is-success is-light mr-1"
>
<router-link :to="{ name: 'tag', params: { name: tag.name } }">
{{ "#" + tag.name }}
</router-link>
</span>
<span class="is-hidden-mobile">浏览:{{ item.view }}</span>
</div>
</div>
</nav>
</div>
<div class="media-right" />
</article>
</el-tab-pane>
<el-tab-pane label="最近修改" name="update">
<article v-for="(item, index) in articleList" :key="index" class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="`https://cn.gravatar.com/avatar/${item.userId}?s=164&d=monsterid`" style="border-radius: 5px;">
</figure>
</div>
<div class="media-content">
<div class="">
<p class="ellipsis is-ellipsis-1">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{name:'post-detail',params:{id:item.id}}">
<span class="is-size-6">{{ item.title }}</span>
</router-link>
</el-tooltip>
</p>
</div>
<nav class="level has-text-grey is-mobile is-size-7 mt-2">
<div class="level-left">
<div class="level-left">
<router-link class="level-item" :to="{ path: `/member/${item.username}/home` }">
{{ item.alias }}
</router-link>
<span class="mr-1">
发布于:{{ dayjs(item.createTime).format("YYYY/MM/DD") }}
</span>
<span
v-for="(tag, index) in item.tags"
:key="index"
class="tag is-hidden-mobile is-success is-light mr-1"
>
<router-link :to="{ name: 'tag', params: { name: tag.name } }">
{{ "#" + tag.name }}
</router-link>
</span>
<span class="is-hidden-mobile">浏览:{{ item.view }}</span>
</div>
</div>
</nav>
</div>
<div class="media-right" />
</article>
</el-tab-pane>
</el-tabs>
</div>
<!--分页-->
<pagination
v-show="page.total > 0"
:total="page.total"
:page.sync="page.current"
:limit.sync="page.size"
@pagination="init"
/>
</el-card>
</div>
</template>
<script>
import { getList } from '@/api/post'
import Pagination from '@/components/Pagination'
export default {
name: 'TopicList',
components: { Pagination },
data() {
return {
activeName: 'latest',
articleList: [],
page: {
current: 1,
size: 10,
total: 0,
tab: 'latest'
}
}
},
created() {
this.init(this.tab)
},
methods: {
init(tab) {
getList(this.page.current, this.page.size, tab).then((response) => {
const { data } = response
this.page.current = data.current
this.page.total = data.total
this.page.size = data.size
this.articleList = data.records
})
},
handleClick(tab) {
this.init(tab.name)
}
}
}
</script>
<style scoped>
</style>
4.测试问题
测试页面还没分页,需要后端完成分页后显示
分页后端
MybatisPlusConfig
@Configuration
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}