实现功能
前段请求
后端接口:http://localhost:8000/api/v1/articles?page=2&limit=10
{
"code": 200,
"data": {
"lists": [
{
"id": 21,
"created_on": "2019-08-19T21:00:39+08:00",
"modified_on": "2019-08-19T21:00:39+08:00",
"state": 0,
"tag_id": 1,
"title": "test1",
"desc": "test-desc",
"Content": "test-content",
"cover_image_url": "",
"created_by": "test-created",
"tag": {
"id": 0,
"created_on": "0001-01-01T00:00:00Z",
"modified_on": "0001-01-01T00:00:00Z",
"name": "",
"created_by": "",
"modified_by": "",
"state": 0
}
},
...//省略
{
"id": 41555,
"created_on": "2019-08-19T21:00:39+08:00",
"modified_on": "2019-08-19T21:00:39+08:00",
"state": 0,
"tag_id": 1,
"title": "test1",
"desc": "test-desc",
"Content": "test-content",
"cover_image_url": "",
"created_by": "test-created",
"tag": {
"id": 0,
"created_on": "0001-01-01T00:00:00Z",
"modified_on": "0001-01-01T00:00:00Z",
"name": "",
"created_by": "",
"modified_by": "",
"state": 0
}
}
],
"total": 22
},
"msg": "ok"
}
数据库
DDL
CREATE TABLE `blog_article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tag_id` int(10) unsigned DEFAULT '0' COMMENT '标签ID',
`title` varchar(100) DEFAULT '' COMMENT '文章标题',
`desc` varchar(255) DEFAULT '' COMMENT '简述',
`content` text COMMENT '内容',
`cover_image_url` varchar(255) DEFAULT '' COMMENT '封面图片地址',
`created_on` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`created_by` varchar(100) DEFAULT '' COMMENT '创建人',
`modified_on` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`modified_by` varchar(255) DEFAULT '' COMMENT '修改人',
`deleted_on` int(10) unsigned DEFAULT '0' COMMENT '删除时间',
`state` tinyint(3) unsigned DEFAULT '1' COMMENT '状态 0为草稿、1为已发布、2为删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4155556 DEFAULT CHARSET=utf8 COMMENT='文章管理';
1.src\router\index.js
添加路由
{
path: '/article',
component: Layout,
children: [
{
path: 'index',
name: 'Article',
component: () => import('@/views/article/index'),
meta: { title: '文章管理', icon: 'form' }
}
]
},
2.新建src\views\article\index.vue
<template>
<div class="app-container">
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
<el-table-column align="center" label="ID" width="80">
<template slot-scope="scope">
<span>{{ scope.row.id }}</span>
</template>
</el-table-column>
<el-table-column width="180px" align="center" label="Date">
<template slot-scope="scope">
<span>{{ scope.row.created_on | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column width="120px" align="center" label="作者">
<template slot-scope="scope">
<span>{{ scope.row.created_by }}</span>
</template>
</el-table-column>
<el-table-column width="100px" label="Importance">
<template slot-scope="scope">
<!-- <svg-icon v-for="n in +scope.row.tag_id" :key="n" icon-class="star" class="meta-item__icon" /> -->
<i v-for="n in +scope.row.tag_id" :key="n" class="el-icon-star-on" />
</template>
</el-table-column>
<el-table-column class-name="state-col" label="Status" width="110">
<template slot-scope="{row}">
<el-tag :type="row.state | statusFilter">
{{ row.state == 1?'发布':'草稿' }}
</el-tag>
</template>
</el-table-column>
<el-table-column min-width="300px" label="Title">
<template slot-scope="{row}">
<router-link :to="'/form/edit/'+row.id" class="link-type">
<span>{{ row.title }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column align="center" label="Actions" width="120">
<template slot-scope="scope">
<router-link :to="'/form/edit/'+scope.row.id">
<el-button type="primary" size="small" icon="el-icon-edit">
编辑
</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
</div>
</template>
<script>
import { parseTime } from '@/utils'
import { fetchList } from '@/api/article'
import Pagination from '@/components/Pagination'
export default {
name: 'ArticleList',
components: { Pagination },
filters: {
statusFilter(state) {
const statusMap = {
1: 'success',
0: 'info',
2: 'danger'
}
return statusMap[state]
},
parseTime: parseTime
},
data() {
return {
list: null,
total: 0,
listLoading: true,
listQuery: {
page: 1,
limit: 10
}
}
},
created() {
this.getList()
},
methods: {
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
console.log(response.data)
this.list = response.data.lists
this.total = response.data.total
this.listLoading = false
})
}
}
}
</script>
<style>
</style>
3.新建公共依赖文件src\utils\index.js
实际是https://github.com/PanJiaChen/vue-element-admin下的src\utils\index.js
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (('' + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
)
}
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = url.split('?')[1]
if (!search) {
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"')
.replace(/\+/g, ' ') +
'"}'
)
}
4.新建src\components\Pagination\index.vue
分页组件
实际是https://github.com/PanJiaChen/vue-element-admin下的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 [10, 20, 30, 50]
}
},
layout: {
type: String,
default: 'total, 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: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>
5.分页组件依赖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()
}
6.新建src\api\article.js
文件调用axios
import request from '@/utils/request'
export function fetchList(params) {
return request({
url: '/api/v1/articles',
method: 'get',
params
})
}