项目地址:https://gitee.com/liangPromise/vue-app-toutiaoAdmin/tree/article/
创建组件并配置路由
我们首先在views文件夹下面创article文件夹 里面存放的是文章列表组件
并在组件中配置了路由信息
{
path: '/home',
component: () => import('@/views/home/Home.vue'),
children: [
{
path: '',
component: () => import('@/views/home/indexHoem.vue')
},
{
// 文章列表
name: 'article',
path: 'article',
component: () => import('@/views/article')
},
{
// 发布文章
name: 'publish',
path: 'publish',
component: () => import('@/views/publish')
}
]
}
页面布局
在文章列表组件中我们使用了大量的element-ui组件 包括 :卡片、面包屑导航、from表单、表格、分页、等等···
使用了大量的组件来实现页面的基本结构 并给相关的组件绑定数据和事件
内容管理页面总共分为两大部分 使用两个卡片组件所包裹 上面展示表单功能 下面使用表格来渲染数据,在表单中
<template>
<div>
<el-card class="box-card">
<div slot="header" class="clearfix">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: 'home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>内容管理</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<!-- el-radio 默认把 label 作为文本和选中之后的 value 值 -->
<el-radio :label="null">全部</el-radio>
<el-radio :label="0">草稿</el-radio>
<el-radio :label="1">待审核</el-radio>
<el-radio :label="2">审核通过</el-radio>
<el-radio :label="3">审核失败</el-radio>
<el-radio :label="4">已删除</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="频道">
<el-select v-model="form.channel_id" placeholder="请选择频道">
<el-option label="全部" :value="null"></el-option>
<el-option
v-for="item in channels"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="日期">
<el-date-picker
v-model="date"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy 年 MM 月 dd 日"
value-format="yyyy-MM-dd"
onPick="abc"
>
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button
type="primary"
size="medium"
@click="onSubmit"
:disabled="loading"
>查询</el-button
>
</el-form-item>
</el-form>
</el-card>
<el-card class="box-card">
<div slot="header" class="clearfix">
<span
>根据筛选条件共查询到<b>{{ totalAll }}</b
>条结果</span
>
</div>
<el-table :data="articles" stripe v-loading="loading" style="width: 100%">
<el-table-column prop="cover.images" label="封面">
<template slot-scope="scope">
<el-image
style="width: 100px; height: 50px"
:src="scope.row.cover.images[0]"
></el-image>
<!-- <el-image style="width: 100px; height: 50px" src="./no-cover.gif"></el-image> -->
</template>
</el-table-column>
<el-table-column prop="title" label="标题"></el-table-column>
<el-table-column label="状态">
<template slot-scope="scope">
<!-- <el-tag v-if="scope.row.status == 0" type="info">草稿</el-tag> -->
<el-tag :type="articleStatus[scope.row.status].type">{{
articleStatus[scope.row.status].text
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="pubdate" label="发布时间"></el-table-column>
<el-table-column prop="address" label="操作">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" @click="editArticleFn(scope.row.id)" circle></el-button>
<el-button
type="danger"
icon="el-icon-delete"
@click="removeArticleFn(scope.row.id)"
circle
></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:disabled="loading"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage4"
:page-sizes="[10, 20, 30, 40]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="totalAll"
>
</el-pagination>
</el-card>
</div>
</template>
文章接口
在api文件夹下新建了一个article.js文件,里面用来编写跟文章有关的api接口,随后向外暴露出去。
在文章相关的组件中,引入api方法调用,将获取的到的数据渲染到页面中
// 文章相关的接口调用
import request from '@/utils/request.js'
// 获取文章频道
const getChannels = () => {
return request.get('/mp/v1_0/channels')
}
// 获取文章列表
const getArticles = params => {
return request.get('/mp/v1_0/articles', { params })
}
// 删除文章
const removeArticle = params => {
return request.delete(`/mp/v1_0/articles/${params}`)
}
// 发布文章
const addArticle = (data, params) => {
console.log(data, params)
return request({
method: 'POST',
url: '/mp/v1_0/articles',
params: {
draft: params // 是否存为草稿(true 为草稿)
},
data
})
}
// 查询文章
const inquireArticle = params => {
return request.get(`/mp/v1_0/articles/${params}`)
}
// 修改文章
const editArticle = (data, params) => {
return request.put(`/mp/v1_0/articles/${params}`, data)
}
// 导出
export {
getChannels,
getArticles,
removeArticle,
addArticle,
inquireArticle,
editArticle
}
数据分页
分页的目的是为了缓解查询数据的压力,提高页面的响应速度,让用户更快的看到页面的内容。
假如是固定的数据,例如10条,20条,以后不会增加了。那就没有必要分页,没有意义。
如果是动态产生的数据,例如文章列表,商品列表,评论列表。
数据量增加的越来越多,就需要使用分页来缓解数据查询和渲染的压力的。
数据库中有 100 条数据:
- 第几页
- 每页大小
后端会从数据库中获取数据,
假设每页10条数据
请求第1页数据,
1-10 - 请求第2页数据,
1-20 - 请求第3页数据,
21-30 - ... 然后后端通过接口提供给前端使用。
- page 页码,
默认第1页 - per_page 每页大小,默认每页 10 条数据
数据筛选:
- 接口的参数
- 通过表单的交互得到接口参数
使用步骤
1、传递分页参数
2、注册分页组件的 current-change
事件
3、当页码改变,请求对应页码数据
<el-pagination
:disabled="loading"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage4"
:page-sizes="[10, 20, 30, 40]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="totalAll"
>
</el-pagination>
---------------------------------------------------------------
// 分页功能
handleSizeChange (value) {
this.form.per_page = value
this.getArticlesFn(this.form)
},
handleCurrentChange (value) {
this.form.page = value
this.getArticlesFn(this.form)
},
总页码处理
1、将数据列表接口中返回的总数据条数存储到 data 数据中
2、将总记录数和每页大小绑定到分页组件
数据筛选
把视图处理成接口需要的数据提交给后端。
1、在 data 中初始化 form并传递给请求方法
2、处理表单绑定获取 form数据
3、点击查询的时候,调用 onSubmit方法加载数据
// 查询按钮
onSubmit () {
console.log(this.form)
this.getArticlesFn(this.form)
},
------------------------------------------------------------------
// 获取文章列表
async getArticlesFn (params) {
this.loading = true
const articles = await getArticles(params).catch(err => err)
if (articles.status !== 200) {
this.loading = false
return this.$message.error('文章列表取失败')
}
this.articles = articles.data.data.results
this.totalAll = articles.data.data.total_count
console.log(articles.data.data)
this.loading = false
},
加载中 loading
在表格中我们设置了加载中loading...状态,在请求期间表格处于loading状态,使项目有更好的交互状态。
1、初始化 loading 数据
// 是否加载中
loading: true
2、设置表格的 loading 状态
<el-table :data="articles" stripe v-loading="loading" style="width: 100%">
</el-table>
----------------------------------------------------------------------------
// 请求期间会开启表格的loading 状态
// 获取文章列表
async getArticlesFn (params) {
this.loading = true
const articles = await getArticles(params).catch(err => err)
if (articles.status !== 200) {
this.loading = false
return this.$message.error('文章列表取失败')
}
this.articles = articles.data.data.results
this.totalAll = articles.data.data.total_count
console.log(articles.data.data)
this.loading = false
},
删除文章
在这里我们遇到了一个问题,在后端返回的数中包含大数字,在js中无法正确读取 ,我们这里使用了第三方插件json-bigint解决了这个问题 。
具体怎么解决的请看我的另一篇文章,里面有详细的解决过程解决js中后端返回数据中的大数字问题
删除操作
1、封装了删除文章请求方法
2、注册删除按钮点击事件
3、删除成功,更新当前页数据
<el-button type="primary" icon="el-icon-edit" @click="editArticleFn(scope.row.id)" circle></el-button>
----------------------------------------------------------
// 删除文章
removeArticleFn (id) {
this.$confirm('此操作将永久删除该文章, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
const data = await removeArticle(id).catch(err => err)
console.log(data)
if (data.status !== 204) return this.$message.error('文章删除失败')
this.$message.success('文章删除成功')
this.getArticlesFn(this.form) // 删除成功更新当前页面
})
.catch(() => {
this.$message.error('已取消删除')
})
},