搭建一個簡易的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

如要轉載,請註明出處,若是以爲不錯,請點個贊,再走吧!鞠躬!!!

相關文章
相關標籤/搜索