AntDesign 简介
Ant Design Vue 是蚂蚁金服旗下的一套开源的 Vue UI 组件库。 蚂蚁金服最早开源组件库 Ant Design (简称antd)在 React 技术领域拥有大量的使用者,于是最近又推出了 Vue 和 Angular 的版本。今天讲述的 Ant Design Vue 是Vue 版本的组件库,适用于搭建复杂的前端应用后台。 官网:vue.ant.design/ 官网文档:www.antdv.com/docs/vue/in… 源码:github.com/vueComponen… antdesignvuepro 学习项目:github.com/vueComponen…
1 创建vue2项目并添加 antd
(1)创建 antd 项目(增加 Router 和 Vuex 组件)
vue create funnyshop-antd
2)添加 antdesignvue 等组件
cd funnyshop‐antd
npm install ant‐design‐vue ‐‐save #antd组件,必须
npm install moment ‐‐save #时间日期工具包,必须
vue add axios #异步请求包
3)使用antd组件
在 main.js 中全局注册组件:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import { Button } from 'ant‐design‐vue' // 导入Button
import 'ant‐design‐vue/dist/antd.css' // 导入样式
Vue.config.productionTip = false
Vue.use(Button) // 全局注册Button
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
在App.vue中使用Button组件
这时就可以显示出antd的Button组件了。但是,现在的antd组件是全部加载的,编译生成的应用程序包会比较大庞大,实际开发中最好使用按需加载。
(4)实现按需加载
官方按需加载介绍请参看“快速上手”中的“按需加载"www.antdv.com/docs/vue/in…
安装 babelpluginimport 插件
npm install babel‐plugin‐import ‐‐save
修改配置 babel.config.js,添加 “plugins” 配置节
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
['import', { libraryName: 'ant-design-vue', libraryDirectory: 'es', style: 'css' }]
// `style: true` 会加载 less 文件
]
}
修改完配置后,需要重新启动vue2项目。 这时我们只需导入所某一插件(不用导css)就可以按需加载了。
import { Button } from 'ant-design-vue' // 导入Button
Vue.use(Button) // 全局注册Button
2 配置基本路由和页面布局
(1)定义基本路由(router.js)
项目结构如下图:
路由文件router-index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{ // 登录页
path: '/login',
name: 'login',
component: () => import('@/views/Login.vue')
},
{ // 其它路径显示404页
path: '*',
name: '404',
component: () => import('@/views/PageNotFound.vue')
},
{ // 基本布局
path: '/product',
name: 'product',
component: () => import('@/layouts/BasicLayout.vue'),
children: [ // 子路由--二级路由
{
path: '/product',
redirect: '/product/categories' // 路由重定向
},
{
path: '/product/categories',
name: 'categories',
component: () => import('@/views/product/Categories.vue')
},
{ // 商品管理页
path: '/product/products',
name: 'products',
component: () => import('@/views/product/Products.vue')
}
]
}
]
})
2)全局导入所需的antd组件(main.js)
import { Button, Col, Row, Card, Form, Input, Layout, Breadcrumb, Menu, Icon, Table, Modal, Select } from 'ant-design-vue'
Vue.use(Button)
Vue.use(Col)
Vue.use(Row)
Vue.use(Form)
Vue.use(Input)
Vue.use(Card)
Vue.use(Layout)
Vue.use(Breadcrumb)
Vue.use(Menu)
Vue.use(Icon)
Vue.use(Table)
Vue.use(Modal)
Vue.use(Select)
3)根组件(App.vue)
<template>
<div id="app">
<router‐view></router‐view>
</div>
</template>
4)定义404错误页(views/PageNotFound.vue)
<template>
<div class="box">
<img src="/images/404.jpg">
</div>
</template>
<style scoped>
.box {
display: flex;
justify‐content: center;
}
</style>
5)定义登录页(views/Login.vue)
<template>
<div>
<br />
<br />
<a-row>
<a-col :span="8" :push="8">
<a-card title="用户登录">
<a-form>
<a-form-item
label="用户名"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 12 }"
>
<a-input type="text" />
</a-form-item>
<a-form-item
label="密码"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 12 }" >
<a-input type="password" />
</a-form-item>
<a-form-item :wrapper-col="{ span: 12, offset: 6 }">
<a-button type="primary" html-type="submit">登录</a-button>
</a-form-item>
</a-form>
</a-card>
</a-col>
</a-row>
</div>
</template>
<script>
export default {
name: 'Login'
}
</script>
6)定义基本的布局(layouts/BasicLayout.vue)
在antd官方文档(vue.ant.design/components/… 。界面效果:
代码如下:
<template>
<a-layout id="components-layout-demo-side" style="min-height: 100vh">
<a-layout-sider v-model="collapsed" collapsible>
<div class="logo" >FunnyShop</div>
<a-menu theme="dark" :default-selected-keys="['1']" mode="inline">
<a-menu-item key="1">
<a-icon type="user" />
<span>用户管理</span>
</a-menu-item>
<a-menu-item key="2">
<a-icon type="file" />
<span>订单管理</span>
</a-menu-item>
<a-sub-menu key="sub1">
<span slot="title">
<a-icon type="gift" />
<span>后台商品管理</span></span>
<a-menu-item key="3">
<router-link to="/product/categories">分类管理</router-link>
</a-menu-item>
<a-menu-item key="4">
<router-link to="/product/products">商品管理</router-link>
</a-menu-item>
</a-sub-menu>
</a-menu>
</a-layout-sider>
<a-layout>
<a-layout-header style="background: #fff; padding: 0" />
<a-layout-content style="margin: 0 16px">
<a-breadcrumb style="margin: 16px 0">
<a-breadcrumb-item>funny-shop</a-breadcrumb-item>
<a-breadcrumb-item>后台管理</a-breadcrumb-item>
</a-breadcrumb>
<div :style="{ padding: '24px', background: '#fff', minHeight: '360px' }">
<!-- 二级路由占位符 -->
<router-view></router-view>
</div>
</a-layout-content>
<a-layout-footer style="text-align: center">
Ant Design ©2018 Created by Ant UED
</a-layout-footer>
</a-layout>
</a-layout>
</template>
<script>
export default {
data () {
return {
collapsed: false
}
}
}
</script>
<style>
#components-layout-demo-side .logo {
height: 32px;
background: rgba(255, 255, 255, 0.2);
margin: 16px;
font-size:20px;
color:aliceblue;
}
</style>
7)定义基本的类别页 (views/product/Categories.vue )
<template>
<div>
<h3>分类信息管理</h3>
</div>
</template>
8)定义基本的产品页 (views/product/Products.vue)
<template>
<div>
<h3>商品信息管理</h3>
</div>
</template>
3. 手工表单验证、登录与访问权限
一) 手工表单验证
antd表单验证可以通过两种方式实现:一是手工实现,二是通过验证组件实现。这里用登录表单演示手工验证。 手工验证表单虽然麻烦,但往往能解决更灵活复杂的问题。antd表单中的<aformitem>提供如下属性可用于验证错误显示: (1)validateState <a-form-item>组件中的 validate-state 属性可以指定表单的校验状态:
可选 ‘success’,‘warning’, ‘error’, validating’ (2)help
<a-form-item>组件中的 help 属性可以设置校验文字信息。
<template>
<div>
<br />
<br />
<a-row>
<a-col :span="8" :push="8">
<a-card title="用户登录">
<a-form>
<a-form-item
label="用户名"
:validate-status="usernameStatus"
:help="usernameHelp"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 12 }"
>
<a-input type="text" v-model="username" />
</a-form-item>
<a-form-item
label="密码"
:validate-status="passwordStatus"
:help="passwordHelp"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 12 }"
>
<a-input type="password" v-model="password" />
</a-form-item>
<a-form-item :wrapper-col="{ span: 12, offset: 6 }">
<a-button type="primary" @click="login" html-type="submit">登录</a-button>
</a-form-item>
</a-form>
</a-card>
</a-col>
</a-row>
</div>
</template>
<script>
export default {
name: 'Login',
data () {
return {
username: '',
password: '',
usernameStatus: '',
passwordStatus: '',
usernameHelp: '',
passwordHelp: ''
}
},
methods: {
login () {
let valid = true
if (this.username.length === 0) {
valid = false
this.usernameStatus = 'error'
this.usernameHelp = '请输入用户名'
} else {
this.usernameStatus = ''
this.usernameHelp = ''
}
if (this.password.length === 0) {
valid = false
this.passwordStatus = 'error'
this.passwordHelp = '请输入密码'
} else {
this.passwordStatus = ''
this.passwordHelp = ''
}
if (valid) {
// 客户端验证成功,使用axios远程验证用户名和密码
}
}
}
}
</script>
二)权限拦截
1)为路由对象定义访问权限 路由项中允许使用meta属性自定义一些附加信息,因此我们可以在meta中定义用户的访问权限。对于后台系统,除了登录页之外,其他页面都需要先登录再访问,我们在登录页路由meta中添加一个自定义的允许匿名属性。
2)修改main.js,在router对象中添加路由访问的前置拦截器
// 设置路由过滤
router.beforeEach((to, from, next) => {
if (to.meta.anonymous) { // 判断该路由是否允许匿名访问
next()
} else {
if (UserService.getLoginUser()) { // 检查是否已登录,已登录继续
next()
} else {
next({
path: '/login',
query: { redirect: to.fullPath } // 将跳转的路由path作为参数,登录成功后跳转到该路
})
}
}
})
3)其中UserService使用SessionStorage维护用户的登录状态 (src/service/UserService.js)
export default class UserService {
static getLoginUser () { // 检查登录与否
var json = sessionStorage.getItem('loginUser')
if (json) {
return JSON.parse(json)
}
return null
}
static saveUser (user) {
sessionStorage.setItem('loginUser', JSON.stringify(user))
}
static logout () { // 注销登录
sessionStorage.clear()
}
}
4.动态加载类别信息
(一) 配置后端请求和vuex
(1)配置后端代理:在根目录添加vue.config.js
module.exports = {
devServer: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:9090' // target host
}
}
}
}
(2)配置vuex的categories模块
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import categories from './modules/categories.js'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
categories
}
})
mutation-types.js,定义模块常量
export const CATEGORIES = {
FIND_CATEGORIES: 'findCategories'
}
定义categories功能模块
import { CATEGORIES } from '../mutation-types'
import axios from 'axios'
const state = {
items: []
}
const getters = {
}
const actions = {
// 查找所有类别
findCategories (context) {
axios.get('/api/admin/categories')
.then(resp => {
context.commit(CATEGORIES.FIND_CATEGORIES, resp.data.data)
})
},
save (context, category) {
axios.post('/api/admin/categories', category)
.then(resp => {
context.dispatch('findCategories')
})
},
delete (context, id) {
axios.delete('/api/admin/categories', id)
.then(resp => {
context.dispatch('findCategories')
})
}
}
const mutations = {
[CATEGORIES.FIND_CATEGORIES] (state, data) {
state.items = data
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
(二)实现分类列表显示(~/components/product/CategoryList.vue)
分类列表使用antd提供的Table组件来实现,具体可以参考:vue.ant.design/components/… 中的“可编辑单元格示例”。
(1)Table中的dataSource属性用于绑定数据行 (2)Table中的columns属性用于定制数据列 (3)需要自定义显示的列,可以通过嵌入插槽模板“