AntDesign 简介

1,016 阅读1分钟

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… ant­design­vue­pro 学习项目:github.com/vueComponen…

1 创建vue2项目并添加 antd

(1)创建 antd 项目(增加 Router 和 Vuex 组件)

vue create funnyshop-antd

2)添加 ant­design­vue 等组件

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…

安装 babel­plugin­import 插件

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表单中的<a­form­item>提供如下属性可用于验证错误显示: (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)需要自定义显示的列,可以通过嵌入插槽模板“