系列文章目录
Vue基础篇一:编写第一个Vue程序 Vue基础篇二:Vue组件的核心概念 Vue基础篇三:Vue的计算属性与侦听器 Vue基础篇四:Vue的生命周期(秒杀案例实战) Vue基础篇五:Vue的指令 Vue基础篇六:Vue使用JSX进行动态渲染 Vue提高篇一:使用Vuex进行状态管理 Vue提高篇二:使用vue-router实现静态路由 Vue提高篇三:使用vue-router实现动态路由 Vue提高篇四:使用Element UI组件库 Vue提高篇五:使用Jest进行单元测试 Vue提高篇六: 使用Vetur+ESLint+Prettier插件提升开发效率 Vue实战篇一: 使用Vue搭建注册登录界面 Vue实战篇二: 实现邮件验证码发送 Vue实战篇三:实现用户注册 Vue实战篇四:创建多步骤表单 Vue实战篇五:实现文件上传 Vue实战篇六:表格渲染动态数据 Vue实战篇七:表单校验 Vue实战篇八:实现弹出对话框进行交互 Vue实战篇九:使用省市区级联选择插件 Vue实战篇十:响应式布局 Vue实战篇十一:父组件获取子组件数据的常规方法 Vue实战篇十二:多项选择器的实际运用 Vue实战篇十三:实战分页组件 Vue实战篇十四:前端excel组件实现数据导入 Vue实战篇十五:表格数据多选在实际项目中的技巧 Vue实战篇十六:导航菜单 Vue实战篇十七:用树型组件实现一个知识目录 Vue实战篇十八:搭建一个知识库框架 Vue实战篇十九:使用printjs打印表单 Vue实战篇二十:自定义表格合计 Vue实战篇二十一:实战Prop的双向绑定 Vue实战篇二十二:生成二维码 Vue实战篇二十三:卡片风格与列表风格的切换 Vue实战篇二十四:分页显示 Vue实战篇二十五:使用ECharts绘制疫情折线图 Vue实战篇二十六:创建动态仪表盘 Vue实战篇二十七:实现走马灯效果的商品轮播图 Vue实战篇二十八:实现一个手机版的购物车
一、背景
- 前两周有位同学,在后台发私信,希望能实现一个简易的留言板,这周就带领大家来进行实战。
二、留言板功能
- 本次实战我们先模拟一个简易的留言板,主要模拟访客的留言发布与浏览。
- 后续会提供后端管理员功能的实现。
三、留言板搭建
3.1 留言区
<el-card class="el-card-m">
<span class="el-card-m-content">{{ item.content }}</span>
<div />
<span class="el-card-m-nick-name">{{ item.nickName }} 提交于 {{ item.createTime }}</span>
</el-card>
– 用el-timeline时间线组件呈现留言区的时间信息
<el-timeline infinite-scroll-disabled="disabled">
<div v-if="pagemessages.length > 0">
<el-timeline-item
v-for="(item, index) in pagemessages"
:key="index"
:timestamp="item.createDate"
placement="top"
>
<el-card class="el-card-m">
<span class="el-card-m-content">{{ item.content }}</span>
<div />
<span class="el-card-m-nick-name">{{ item.nickName }} 提交于 {{ item.createTime }}</span>
</el-card>
</el-timeline-item>
</div>
<div v-else>
<el-timeline-item placement="top">
<el-card class="el-card-m">
<p class="el-card-m-nick-name"> 没有任何留言</p>
</el-card>
</el-timeline-item>
</div>
</el-timeline>
– 用分页组件分解数据,翻页浏览
<el-pagination
background
:current-page="currentPage"
:page-size="pagesize"
layout="prev, pager, next"
:total="allmessages.length"
:hide-on-single-page="true"
@current-change="handleCurrentChange"
/>
3.2 发布区
– 输入昵称 – 输入留言内容 – 点击留言按钮进行发布
<div class="el-card-messages">
<el-input v-model="nickName" size="mini" class="message-nick-name">
<template slot="prepend">昵称:</template>
</el-input>
<el-input
slot="prepend"
v-model="message"
type="textarea"
:rows="2"
class="message-text"
placeholder="输入留言"
maxlength="200"
/>
<el-button
type="info"
round
class="submit-message"
size="mini"
@click="submitMessage"
>留言</el-button>
</div>
四、前端完整源码
- 注意,本实战并未与后端进行交互,数据只在前端模拟展示
<template>
<div>
<el-card class="el-card-d" shadow="always">
<el-timeline infinite-scroll-disabled="disabled">
<div v-if="pagemessages.length > 0">
<el-timeline-item
v-for="(item, index) in pagemessages"
:key="index"
:timestamp="item.createDate"
placement="top"
>
<el-card class="el-card-m">
<span class="el-card-m-content">{{ item.content }}</span>
<div />
<span class="el-card-m-nick-name">{{ item.nickName }} 提交于 {{ item.createTime }}</span>
</el-card>
</el-timeline-item>
</div>
<div v-else>
<el-timeline-item placement="top">
<el-card class="el-card-m">
<p class="el-card-m-nick-name"> 没有任何留言</p>
</el-card>
</el-timeline-item>
</div>
</el-timeline>
<el-pagination
background
:current-page="currentPage"
:page-size="pagesize"
layout="prev, pager, next"
:total="allmessages.length"
:hide-on-single-page="true"
@current-change="handleCurrentChange"
/>
</el-card>
<div class="el-card-messages">
<el-input v-model="nickName" size="mini" class="message-nick-name">
<template slot="prepend">昵称:</template>
</el-input>
<el-input
slot="prepend"
v-model="message"
type="textarea"
:rows="2"
class="message-text"
placeholder="输入留言"
maxlength="200"
/>
<el-button
type="info"
round
class="submit-message"
size="mini"
@click="submitMessage"
>留言</el-button>
</div>
</div>
</template>
<script>
import { parseTime } from '@/utils/index'
export default {
data() {
return {
nickName: '',
message: '',
pagesize: 3,
currentPage: 1,
pagemessages: [],
allmessages: []
}
},
created() {
this.doQuery()
},
methods: {
doQuery() {
const start = (this.currentPage - 1) * this.pagesize
const end = start + this.pagesize
for (var i = start; i < end; i++) {
if (i < this.allmessages.length) {
this.pagemessages.push(this.allmessages[i])
}
}
},
handleCurrentChange(val) {
this.currentPage = val
this.pagemessages = []
this.doQuery()
},
submitMessage() {
if (this.nickName === '' || this.nickName.replace(/(^\s*)|(\s*$)/g, '') === '') {
this.$message('请输入昵称')
return
}
if (this.message === '' || this.message.replace(/(^\s*)|(\s*$)/g, '') === '') {
this.$message('留言不能为空')
return
}
var timestamp = Date.parse(new Date())
this.allmessages.push({ createTime: parseTime(timestamp), createDate: parseTime(timestamp, '{y}-{m}-{d}'), nickName: this.nickName, content: this.message })
this.nickName = ''
this.message = ''
this.currentPage = Math.ceil(this.allmessages.length / this.pagesize, 0)
this.handleCurrentChange(this.currentPage)
}
}
}
</script>
<style scoped>
.el-card-d {
float: left;
margin-top: 20px;
margin-left: 10%;
width: 80%;
height: 500px;
background: rgb(252, 250, 250);
}
.el-card-m{
height: 100px;
}
.el-card-m-content{
display: block;
font-weight: bold;
}
.el-card-m-nick-name{
display: block;
font-size: x-small;
margin-top: 15px;
color: gray;
}
.el-card-messages {
float: left;
margin-top: 20px;
margin-left: 10%;
width: 70%;
}
.message-nick-name {
width: 50%;
}
.message-text {
margin-top: 10px;
display: block;
width: 50%;
}
.submit-message {
margin-top: 10px;
width: 80px;
background: rgb(235, 245, 247);
color: cadetblue;
text-align: center;
letter-spacing: 20px;
}
</style>
五、效果演示
|