搭建一个简易的antd-pro-vue

本文是在学习antd-pro-vue开箱即用的中台前端/设计解决方案的源码后,写的笔记。javascript

这是他们的官方文档ANTD PRO VUEcss

1、搭建环境

  1. vue create ant-design-vue-pro

这里须要用到vue-cli脚手架 必须先在全局安装vue-cli Vue-cli的官网:Vue Clihtml

屏幕快照 2019-10-14 下午8.21.57

选择第二个,自定义配置 前端

image-20191014202310150

image-20191014202503677

  1. 以后咱们须要借助Ant Design of Vue的UI组件

npm i ant-design-vue -D -Svue

  1. 按需加载所须要的组件

npm install babel-plugin-import --dev 修改babel.config.js 文件,配置babel-plugin-importjava

module.exports = {
  presets: ["@vue/app"],
+  plugins: [
+    [
+      "import",
+      { libraryName: "ant-design-vue", libraryDirectory: "es", style: true }
+    ]
+  ]
};
复制代码

详细内容能够看antd of vuenode

  1. 若是发现使用了less 控制台报错

修改vue.config.js 文件,若是没有该文件,则新建一个ios

module.exports = {
    css: {
    	loaderOptions:{
    		less:{
    			javascriptEnabled:true,
            }
        }
    }
}
复制代码

2、按需加载UI组件

在删除大部分不须要的内容后,如今目录以下:vue-router

屏幕快照 2019-10-14 下午8.47.23

  1. 在根目录,新建一个文件夹core
  2. core文件夹下新建lazy_lib文件夹
  3. lazy_lib文件夹下新建components_use.js
//component_use.js
import Vue from 'vue'
import {
  //引入你须要加载的组件
	Button,
  Icon,
	Switch,
	notification,
} from 'ant-design-vue'

Vue.use(Button)
Vue.use(Icon)
Vue.use(Switch)
Vue.use(notification)

Vue.prototype.$notification = notification // 在vue 单文件中能够直接 this.$notification去调用
复制代码
  1. main.js中导入该文件

import "@/core/lazy_lib/components_use.js"vuex

3、页面基本布局配置

  1. src文件夹下新建layouts 文件夹
  2. layouts 文件夹下各类布局文件,如BasicLayout.vue

关于页面布局,详细信息能够看layout

4、路由配置

  1. src文件夹下新建config 文件夹,用来设置各类配置
  2. config文件夹下新建router.config.js
// router.config.js
//导入各类基本页面布局
import {UserLayout,BasicLayout,RouteView,BlankLayout,PageView} from "@/layouts"
复制代码
// 基本路由配置
export const constantRouterMap = [
	{
		path:'/user',
		component:UserLayout,
		redirect:'/user/login',重定向到登录页
		children:[
			{
			  path:'login',
			  name:'Login',
			  component:() => import('@views/user/login')
  	                 }
        ]
   },
   ...
  {
    path:'/404',
    component:()=>import('@views/exceptions/404')
  }
]
// 详情页面的路由
export const asyncRouterMap = [
...
]
复制代码
  1. src文件夹下新建一个router文件夹,在改文件夹下新建index.js
//index.js
import Vue from 'vue'
import Router from 'vue-router'
const{ constantRouterMap,asyncRouterMap} from '@/config/router.config'

Vue.use(Router)

export default new Router({
	mode:'history',
	routes:constantRouterMap.concat(asyncRouterMap)
})
复制代码
  1. main.js中导入
...
import router from './router'
...
new Vue({
	router,
	render:h => h(App),
}).$mount('#app')
复制代码

5、网络请求

  1. npm i axios

    安装axios

    关于axios的详细信息,请看其官方文档axios中文网

  2. axios的响应格式以下:

    {
      // `data` 由服务器提供的响应
      data: {},
    
      // `status` 来自服务器响应的 HTTP 状态码
      status: 200,
    
      // `statusText` 来自服务器响应的 HTTP 状态信息
      statusText: 'OK',
    
      // `headers` 服务器响应的头
      headers: {},
    
       // `config` 是为请求提供的配置信息
      config: {},
     // 'request'
      // `request` is the request that generated this response
      // It is the last ClientRequest instance in node.js (in redirects)
      // and an XMLHttpRequest instance the browser
      request: {}
    }
    复制代码

    由于axios将服务端响应的信息包裹了一层,因此咱们通常会去写一个响应拦截器,提取服务端真正返回的信息

    // 添加响应拦截器
    axios.interceptors.response.use(function (response) {
        // 对响应数据作点什么
        return response.data;//response.data是服务端真正返回的信息
      }, function (error) {
        // 对响应错误作点什么
        return Promise.reject(error);
      });
    复制代码
  3. 给每次网络请求的请求头加上token

    // 是否要添加请求头
    service.interceptors.request.use(config => {
    	const token = Vue.ls.get(ACCESS_TOKEN)
    	if(token){
    		config.headers['Access-Token'] = token //让每一个请求自带token
             }
    	return config
    },(err)=>{
    	  //对请求错误作些什么
    })
    复制代码
  4. src目录下新建utils文件夹,在utils文件夹下新建request.js

    import Vue from 'vue'
    import axios from 'axios'
    import store from '@/store'
    import notification from 'ant-design-vue/es/notification'
    import {ACCESS_TOKEN} from '@/store/mutation-types'
    
    //建立axios实例
    const service = axios.create({
    	baseURL:process.env.VUE_APP_API_BASE_URL,//能够不写
    	timeout:6000,//请求超时时间
    })
    
    // 建立一个函数用来处理网络请求的错误
    const err = (error) => {
    	if(error.response){
    		const data = error.response.data
    		const token = Vue.ls.get(ACCESS_TOKEN)
    		if(error.response.status === 403){
    			notification.error({
    				message:"权限限制",
    				description:data.message
                   })
              }
              if(error.response.status ==... ){
    			... 写上大家所须要的业务逻辑
              }
         }
    	// 业务逻辑处理完后,依然返回所有的错误信息
    	return Promise.reject(error)
    }
    
    // 是否要添加请求头
    service.interceptors.request.use(config => {
    	const token = Vue.ls.get(ACCESS_TOKEN)
    	if(token){
    		config.headers['Access-Token'] = token //让每一个请求自带token
         }
    	return config
    },err)
    
    // 由于axios会将服务段返回的信息嵌套一层,因此咱们能够
    // 将服务端真正返回的信息返回
    service.interceptiors.response.use((response)=>{
    	return response.data,
    },err)
    
    export {
    	service as axios
    }
    复制代码
  5. 关于axios拦截器对知识,详细内容能够看官方文档拦截器

6、Restful API

  1. src文件夹下新建一个api文件夹,在该文件夹下新建三个js文件,以下:

    --index.js
    --login.js
    --manage.js
    复制代码
  2. index.js主要用于存放各类api

    const prefix = "http://baidu.com"//根地址
    
    const userPrefix = prefix + "/user"
    const devicePrefix = prefix + "/deivce"
    
    const apiUserLogin  = userPrefix + '/login'
    
    const apiDeviceAdd = devicePrefix + "/add"
    
    //将全部api存放于一个对象内,导出该对象
    const api = {
     userPrefix,
     devicePrefix,
     apiUserLogin,
     apiDeviceAdd
    }
    
    export default api
    复制代码
  3. login.js存放用户注册、登录、修改密码、退出等网络请求

    import api from './index'
    import {axios} from '@/utils/request'
    
    // 用户登录
    export function login (parameter) {
    	return axios({
    		url:api.apiUserLogin,
    		method:'post',
    		data:{
    			phone:parameter.phone,
    			password:parameter.password
             }
      })
    }
    ...
    复制代码
  4. manage.js 存放关于公司的主体业务的网络请求

    ...

7、状态管理

  1. src 文件夹下新建store文件夹,在store 文件夹中 具体建立的文件以下:

    .
    ├── getters.js
    ├── index.js
    ├── modules
    │   └── user.js
    └── mutation-types.js
    复制代码
  2. mutation-types.js里写满了,要存储信息的文件都名字

    //mutation-types.js
    export const AVATAR = 'avatar'
    export const NAME = 'name'
    export const USERINFO = 'userInfo'
    export const ACCESS_TOKEN = 'token'
    复制代码
  3. index.js文件内导入了各个store模块

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    import user from "./modules/user"
    import getters from "./getters"
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      // 导入的模块所有放在modules中
        modules:{
            user
        },
        state:{},
        mutations:{},
        actions:{},
        getters,
    })
    复制代码
  4. modules 文件夹中存放了各个信息模块的store

    //user.js
    import Vue from 'vue'
    import {AVATAR,NAME,USERINFO,ACCESS_TOKEN} from '@/store/mutation-types'
    import {login} from "@/api/login"
    const user = {
      // 存放用户信息
    	state:{
    		token:'',
    		name:'',
    		avatar:'',
    		userInfo:''
      },
      // 操做state
    	mutations:{
      	SET_NAME:(state,name)=>{
    				state.name = name
        },
    		SET_AVATAR:(state,avatar) =>{
    				state.avatar = avatar
        },
    		SET_USERINFO:(state,userInfo) =>{
    			state.userInfo = userInfo
        }
    	},
    	// 能够异步操做,等网络请求结果返回后,再经过操做mutations来改写state 内容
    	actions:{
    		// 登录:
        Login({commit},userInfo){
    			return new Promise((resolve,reject)=>{
            // 网络请求
    				login(userInfo)
    					.then(res=>{
    						let statusCode = res.code;
    						if(statusCode==200){
    							const data = res.data;
                  Vue.ls.set(NAME,data.nickName,3*24*60*60*1000);
                  Vue.ls.set(AVATAR,data.headImg,3*24*60*60*1000);
                  Vue.ls.set(USERINFO,data,3*24*60*60*1000);
                  Vue.ls.set(ACCESS_TOKEN,data.token,3*24*60*60*1000);
                  commit('SET_NAME',data.nickName);
                  commit('SET_AVATAR',data.headimg);
                  commit('SET_USERINFO',data);
                  resolve();
                }else{
    							reject({
                    description:res.message
    							})
                }
            	})
          }).catch(err=>{
    				reject({
    					description:"登录失败请重试"
            })
          })
        }
      }
    }
    复制代码

由于用户每次登录,咱们都须要存储服务端返回的该用户的惟一标识token与用户的各类我的信息,因此咱们能够将 vuex与网络请求结合起来,利用actions能够异步操做这个特性,发送网络请求,在确认请求成功后,便经过commit去调用mutations操做改写state的各类信息

  1. getters.js用于取出state中的数据
const getters = {
   name:state.user.name,
   avatar:state.user.avatar,
   userInfo:state.user.userInfo,
   token:state.user.token
}
export default getters
复制代码

8、数据持久化

vuex能够存放状态,但只要浏览器一刷新,这些数据就会没有了。因此咱们须要数据持久化,在这里推荐使用vue-ls ,这是它在npm 官网上的地址https://www.npmjs.com/package/vue-ls

  1. npm i vue-ls安装vue-ls
  2. src/config目录下,新建defaultSettings.js,用于配置vue-ls
export default {
	storageOptions:{
		namespace:'pro_',//本地存储,key的前缀
		name:'ls',//Vue.[name] => 经过Vue.ls来调用
		storage:'local'//本地存储
  }
}
复制代码
  1. main.js中导入
import Vue from 'vue'
import VueStorage from 'vue-ls'
import config from '@/config/defaultSettings'

Vue.use(VueStorage,config.storageOptions)
复制代码
  1. 使用
Vue.ls.set(name,value,time)
// name : 本地存储的名字
// value : 本地存储的值
// time : 本地存储的时间
// Vue.ls.set('boo',123,3*24*60*60*1000)

Vue.ls.remove('foo')// 删除本地缓存
复制代码

9、数据持久化和状态管理的结合

虽然Vue.ls能够本地缓存信息,可是vuex依然是每次浏览器一刷新,数据就全没有了,因此咱们须要在浏览器刷新的时候,从本地缓存中将数据取出来,再将数据存放vuex中

  1. core文件夹下新建bootstrap.js
import Vue from 'vue'
import store from '@/store'

import {
	ACCESS_TOKEN,
	NAME,
  AVATAR,
	USERINFO
} from '@/store/mutation-types'

export default function Initializer() {
	store.commit('SET_NAME',Vue.ls.get(NAME))
  store.commit('SET_AVATAR',Vue.ls.get(AVATAR))
	store.commit('SET_USERINFO',Vue.ls.get(USERINFO))
}
复制代码
  1. 每次在Vue建立实例后,调用Initializer 函数
import Vue from 'vue'
import bootstrap from './core/bootstrap'

new Vue({
// 每次刷新浏览器,vue 就会从新建立一次实例
// 于是能够每次刷新,都从缓存中取数据存放到state中
	created:bootstrap,
	
	render:h => h(App)
}).$mount('#app')
复制代码

10、路由权限管理

此处只讲用户登录先后的路由权限

  1. src 目录下,新建permission.js
//导入的文件
import Vue from 'vue'
import router from './router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {ACCESS_TOKEN} from '@/store/mutation-types'
复制代码

NProgress 是浏览器工具栏处的进度条,详细信息能够访问它在npm网上的地址https://www.npmjs.com/package/nprogress

  1. 路由白名单
const whiteList = ['login','register','forget'];// 即便用户没有登录,也能够访问的路由
复制代码
  1. 全局导航路由beforeEach
router.beforeEach((to,from,next) => {
	NProgress.start();// 进度条开始
	if(Vue.ls.get(ACCESS_TOKEN)){
		//判断用户是否登录
            if(to.path==='user/login'){
    	// 若是已经登录,而且访问的地址是登录地址,
        // 则跳转到登录后到页面
        			next({path:'/xx/xx'});
            }else{
        // 若是已经登录,而且访问的地址不是登录地址,则让其跳转
              next();
            }
  }else{
	if(whiteList.includes(to.name)){
		// 若是用户没有登录,但访问的路由在白名单内,则直接进入|
			next()
        }else{
    	// 既没有登录,访问的路由地址又不在白名单内
    	// 则让其跳转到登录地址
          next({path:'/user/login'})
        }
  }
})

router.afterEach(()=>{
	NProgress.done();// 路由跳转结束后,让进度条结束
})
复制代码

结语

小生实力水平有限,若是错漏处,还请各位看官指正, 再声明一次,该文是看ANTD PRO VUE源码后的笔记, 有兴趣了解更多,请前往其官方文档https://pro.loacg.com/

做者:胡志武

时间:2019/10/15

如要转载,请注明出处,若是以为不错,请点个赞,再走吧!鞠躬!!!

相关文章
相关标签/搜索