vue-element-ui前后端交互实现分页查询
Posted YDaryl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue-element-ui前后端交互实现分页查询相关的知识,希望对你有一定的参考价值。
大体思路:
①添加element-ui分页组件
②在data里定义几个参数用来存放当前页,每页条数,条目总数以及存放后端分页查询的结果
③后端使用分页查询,controller层接收当前页以及每页条数的参数
④前端编写方法发送请求到controller层调用分页查询的方法,并传参当前页及每页条数
⑤接收查询结果并存放进之前定义好的参数中
⑥给前端点击上下页等功能绑定事件,事件调用分页查询的方法并传参
前端:
①添加element-ui分页组件
<!--
@size-change,pageSize 改变时会触发
@current-change , currentPage 改变时会触发
:current-page 当前页码
:page-sizes 选择每页显示个数
:page-size 默认每页显示条目个数,支持 .sync 修饰符
layout 组件布局,
:total 总条目数
-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 15, 20]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
②在data里定义几个参数用来存放当前页,每页条数,条目总数以及存放后端分页查询的结果
newsData:[], //存放接收后端的数据
pageNum: 1, // 当前页 默认设值1
pageSize: 5, // 每页显示条目 默认设置5
total: '' ,// 条目总数
③后端使用分页查询,controller层接收当前页以及每页条数的参数
controller层
service层
④前端编写方法发送请求到controller层调用分页查询的方法,并传参当前页及每页条数
⑤接收查询结果并存放进之前定义好的参数中
loadPage(pageNum,pageSize)
let url = '/news/page';
axios.get(url,
params:
// pageNum:this.pageNum,
// pageSize:this.pageSize
pageNum,
pageSize
).then(resp =>
resp.data.list.get
this.newsData = resp.data.list;
this.total = resp.data.total;
// this.total = resp.data.list.total;
console.log(resp.data);
);
⑥给前端点击上下页等功能绑定事件,事件调用分页查询的方法并传参
handleSizeChange(val)
this.pageSize = val;
this.loadPage(this.pageNum,this.pageSize);
console.log(`每页 $val 条`);
,
handleCurrentChange(val)
this.pageNum = val;
this.loadPage(this.pageNum,this.pageSize);
console.log(`当前页: $val`);
,
功能展示:
我的前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>listdemo</title>
<script src="/js/vue-2.6.10.js"></script>
<script src="/js/axios.min.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
<div id="root">
<el-button
size="mini"
type="primary"
@click="clean">发布新闻</el-button>
<el-table
ref="news"
:data="newsData"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column
prop="nid"
label="新闻编号"
width="120">
</el-table-column>
<el-table-column
prop="ntid"
label="主题编号"
width="120">
</el-table-column>
<el-table-column
prop="ntitle"
label="新闻标题"
width="120">
</el-table-column>
<el-table-column
prop="nauthor"
label="新闻作者"
width="120">
</el-table-column>
<el-table-column
prop="ncreateDate"
label="创建日期"
width="120">
</el-table-column>
<el-table-column
prop="npicPath"
label="图片路径"
width="120">
</el-table-column>
<el-table-column
prop="ncontent"
label="新闻内容"
width="120"
show-overflow-tooltip="true">
</el-table-column>
<el-table-column
prop="nmodifyDate"
label="修改时间"
width="120">
</el-table-column>
<el-table-column
prop="nsummary"
label="备注信息"
width="120"
show-overflow-tooltip="true">
</el-table-column>
<el-table-column
prop="comment"
label="评论信息"
width="120">
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button
size="mini"
@click="dialogFormVisible = true;getDate(scope.$index)">编辑
</el-button>
<el-dialog title="修改信息"
:visible.sync="dialogFormVisible"
:close-on-click-modal="false"
@close="onClose">
<el-form ref="form"
:model="form"
:rules="rules"
label-width="100px"
class="demo-form">
<el-form-item label="新闻编号" prop="nid">
<el-input v-model="form.nid"></el-input>
</el-form-item>
<el-form-item label="主题编号" prop="ntid">
<el-input v-model="form.ntid"></el-input>
</el-form-item>
<el-form-item label="新闻标题" prop="ntitle">
<el-input type="textarea" v-model="form.ntitle"></el-input>
</el-form-item>
<el-form-item label="新闻作者" prop="nauthor">
<el-input v-model="form.nauthor"></el-input>
</el-form-item>
<el-form-item label="创建日期" prop="ncreateDate">
<el-date-picker type="date"
placeholder="选择日期"
v-model="form.ncreateDate"
style="width: 100%;"></el-date-picker>
</el-form-item>
<el-form-item label="图片路径" prop="npicPath">
<el-input v-model="form.npicPath"></el-input>
</el-form-item>
<el-form-item label="新闻内容" prop="ncontent">
<el-input type="textarea" v-model="form.ncontent"></el-input>
</el-form-item>
<el-form-item label="修改时间" prop="nmodifyDate">
<el-date-picker type="date"
placeholder="修改时间"
v-model="form.nmodifyDate"
style="width: 100%;"></el-date-picker>
</el-form-item>
<el-form-item label="备注信息" prop="nsummary">
<el-input type="textarea" v-model="form.nsummary"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('form')">立即创建</el-button>
<el-button @click="resetForm('form')">重置</el-button>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary"
@click="dialogFormVisible = false;loadUpdate">确 定
</el-button>
</div>
</el-dialog>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--
@size-change,pageSize 改变时会触发
@current-change , currentPage 改变时会触发
:current-page 当前页码
:page-sizes 选择每页显示个数
:page-size 默认每页显示条目个数,支持 .sync 修饰符
layout 组件布局,
:total 总条目数
-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 15, 20]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<script>
new Vue(
el:"#root",
data()
return
newsData:[],
pageNum: 1, // 当前页
pageSize: 5, // 每页显示条目
total: '' ,// 条目总数
dialogFormVisible: false,
form:
delivery: false,
type: [],
nid:'',
ntid:'',
ntitle:'',
nauthor:'',
ncreateDate:'',
npicPath:'',
ncontent:'',
nmodifyDate:'',
nsummary:''
,
rules:
nid: [
required: true, message: '请输入新闻编号', trigger: 'blur' ,
min: 1, max: 5, message: '长度在 1 到 5 个字符', trigger: 'blur'
],
ntid: [
required: true, message: '请输入主题编号', trigger: 'blur'
],
ntitle: [
required: true, message: '请输入新闻标题', trigger: 'blur'
],
nauthor: [
required: true, message: '请输入新闻作者', trigger: 'blur'
],
ncreateDate: [
type: 'date', required: true, message: '请选择创建日期', trigger: 'change'
],
npicPath: [
required: true, message: '请输入图片路径', trigger: 'blur'
],
ncontent: [
required: true, message: '请输入新闻内容', trigger: 'blur'
],
nmodifyDate: [
type: 'date', required: true, message: '请选择修改时间', trigger: 'change'
],
nsummary: [
required: true, message: '请输入备注信息', trigger: 'blur'
],
,
formLabelWidth: '120px'
,
methods:
onClose()
this.form = '';
,
clean()
// this.form = '';
this.dialogFormVisible = true;
// this.show();
,
show()
this.dialogFormVisible = true;
,
toggleSelection(rows)
if (rows)
rows.forEach(row =>
this.$refs.multipleTable.toggleRowSelection(row);
);
else
this.$refs.multipleTable.clearSelection();
,
handleSelectionChange(val)
this.multipleSelection = val;
,
handleEdit(index, row)
console.log(index, row);
,
getDate(index)
this.form = this.newsData[index];
,
handleDelete(index, row)
this.$confirm('是否确定删除此条数据','提示',
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
// center: true
).then(() =>
let url = `/news/delete/$row.nid`;
axios.delete(url).then(resp =>
this.loadAll();
console.log(resp.data);
);
this.$message(
type: 'success',
message: '删除成功!'
);
).catch(() =>
this.$message(
type: 'info',
message: '已取消删除'
);
);
// console.log(index, row);
,
loadAll()
//then()回调函数,获取后台响应的数据
let url = '/news/findAll';
axios.get(url).then(resp =>
this.newsData = resp.data;
console.log(resp.data);
);
,
loadUpdate()
let url = 'news/update';
// let news = JSON.parse(this.form);
axios.put(url, this.form).then(resp =>
this.loadAll();
console.log(resp.data);
);
,
submitForm(formName)
this.$refs[formName].validate((valid) =>
if (valid)
alert('submit!');
else
console.log('error submit!!');
return false;
);
,
resetForm(formName)
this.$refs[formName].resetFields();
,
loadAdd()
let url = 'news/insert';
axios.post(url,params).then(resp =>
console.log(resp.data);
);
,
handleSizeChange(val)
this.pageSize = val;
this.loadPage(this.pageNum,this.pageSize);
console.log(`每页 $val 条`);
,
handleCurrentChange(val)
this.pageNum = val;
this.loadPage(this.pageNum,this.pageSize);
console.log(`当前页: $val`);
,
loadPage(pageNum,pageSize)
let url = '/news/page';
axios.get(url,
params:
// pageNum:this.pageNum,
// pageSize:this.pageSize
pageNum,
pageSize
).then(resp =>
resp.data.list.get
this.newsData = resp.data.list;
this.total = resp.data.total;
// this.total = resp.data.list.total;
console.log(resp.data);
);
,
created()
this.loadPage(this.pageNum,this.pageSize);
// this.loadAll();
)
</script>
</body>
</html>
前后端分离实践分页请求历史聊天消息
分页加载原因
在一个系统数据很大,在接口数据交互,海量数据查询,服务器接口返回的数据不可能一次性返回。
数据量大,从数据库一次性查询,再到网络传输是要花费更多的时间客户端才能响应拿到数据进行 UI 界面渲染。
从接口拿到大量数据渲染,Web 端会造成界面卡顿,移动端处理大量数据,会出现 OOM。
所以获取数据可以通过分页加载的方式处理数据和UI交互。这样解决性能问题,让 UED 效果更好一点。
通常前端可以通过上拉刷新、下拉加载更多等方式。
解决当前聊天问题
-
在单聊,会获取聊天历史记录,分页拉取
-
获取聊天历史记录,其实就是一个下拉加载更多数据的操作 -
更新聊天记录列表
-
方法一、从新调用获取
-
方法二、在接收到消息到时候更新
-
方法三、查找现有列表,获取在列表位置,根据更新对应字段
解决方案监听
-
监听滚动鼠标滚轮或滚动事件 -
使用第三方模块 pullrefreshjs
-
...
添加正在加载
修改 pages/Im/chat/index.jsx
,在请求的时候才显示 Spin 组件,良好提示。
...
<div className={styles['chat-container']}>
<div id="chatItems" className={styles['chat-items']}>
{loading && (
<div className={styles['chat-loading']}>
<Spin />
</div>
)}
...
loading
属性可以从 chat model 中获取,dva effects
封装了在发起请求都会维护一个 models 属性
export default connect(({ user, chat, loading }) => ({
user,
chat,
loading: loading.models.chat, // if user ==> loading.models.user
}))(Chat);
监听滚动鼠标滚轮
监听聊天容器鼠标滚动
const onChatItemScroll = (e) => {
// hasMore 标示加载最后一次,已经没有更多数据了
// loading 表示正在加载中,不再加载,等上一次请求完成才能发起请求,避免请求过快
if (!hasMore || loading) return;
// 鼠标滚轮是否滚动
// (e.wheelDelta > 0) 向上滚动
// 否则向下滚动
if (e.wheelDelta > 0) {
let chatItems = document.getElementById('chatItems');
// 聊天容器滚动至顶部的时候才发起请求
if (chatItems && chatItems.scrollTop === 0) {
// 获取当前聊天对象聊天记录
let chatId = getDiffChatId(chatUserInfo, userId);
// 发起请求 -->. dispatch model
dispatch({ type: 'chat/getMessageChatList', payload: { chatId, pageNum: pageNum + 1 } });
} else {
console.log('follow @全栈技术部 thank');
}
}
};
const addChatItemScrollListener = () => {
let chatItems = document.getElementById('chatItems');
chatItems && chatItems.addEventListener('mousewheel', onChatItemScroll, false);
};
const removeChatItemScrollListener = () => {
let chatItems = document.getElementById('chatItems');
chatItems && chatItems.removeEventListener('mousewheel', onChatItemScroll, false);
};
useEffect(() => {
if (!receiveId) {
history.replace({ pathname: '/im' });
return;
}
// 添加事件
addChatItemScrollListener();
return () => {
// 移除事件
removeChatItemScrollListener();
};
// 当以下属性发生变化,事件监听都需要获取当前最新的属性数据
}, [pageNum, hasMore, loading]);
mousewheel 事件存在 浏览器兼容性问题
Chat Model 逻辑处理
添加状态
state {
...
// 请求页码
pageNum: 1,
// 标示 是否还有更多数据
hasMore: true
...
},
effects{
...
/**
* 获取聊天请求
*/
*getMessageChatList({ payload }, { call, put, select }) {
const { chatId, pageNum } = payload;
const chatState = yield select((state) => state['chat']);
const { messageChatList = [] } = chatState;
const response = yield call(getMessageChatList, { chatId, pageNum });
if (response.code === 200) {
// 响应数据
const lists = (response.data && response.data.lists) || [];
// 这个数据根据接口返回
// 数据反转,无需遍历添加
lists.reverse();
// 加载下一页数据,继续往聊天记录中添加 concat
let messageList = pageNum !== 1 ? lists.concat(messageChatList) : lists;
yield put({
type: 'updateMessageChatList',
// dispatch 传递参数
// 请求最后一次返回 lists 字段为空,表示没有很多数据了
payload: { messageChatList: messageList, pageNum: pageNum, hasMore: lists.length > 0 },
});
}
...
}
发送消息更新聊天记录
*sendMessage({ payload }, { call, put, select }) {
const { messageTemplate } = payload;
const chatState = yield select((state) => state['chat']);
const { messageChatList = [], socket, messageRecordList = [] } = chatState;
const temp = messageChatList.concat();
temp.push(messageTemplate);
yield put({ type: 'refreshChatList', payload: { messageChatList: temp } });
yield put({ type: 'chatInputMessageChange', payload: { content: null } });
if (!socket) console.warn('socket 不存在,需要重新登录,请检查 Socket 连接。');
if (socket) socket.emit('SINGLE_CHAT', messageTemplate);
// 更新聊天记录列表
// 方法一、从新调用获取
yield put({ type: 'getMessageRecordList' });
// 方法二、在接收到消息到时候更新
// 方法三、查找现有列表 更新对应字段
// const { sendId, receiveId } = messageTemplate;
// let recordIndex = -1;
// messageRecordList.map((item, index) => {
// if (
// (item.sendId === sendId && item.receiveId === receiveId) ||
// (item.receiveId === sendId && item.sendId === receiveId)
// ) {
// recordIndex = index;
// }
// });
// if (recordIndex !== -1) {
// messageRecordList[recordIndex]
// }
// console.log(recordIndex);
console.log(chatState);
},
API 修改查看
效果图
end
以上是关于vue-element-ui前后端交互实现分页查询的主要内容,如果未能解决你的问题,请参考以下文章