Ant Design Pro Vue使用心得
19806 ワード
ディレクトリ構造
ルートとメニュー
きほんこうぞう
ルーティングとメニューはアプリケーションを組織する重要なスケルトンであり、proにおけるルーティングは管理を容易にするためにrouter.config.jsは構成と管理を統一する.ルーティング管理は、routerにおいて、所定の構文に従って管理する.config.jsでルーティングを構成します. メニュー生成は、ルーティング構成に従ってメニューを生成する.メニュー・アイテム名、ネストされたパスがルーティングに高度に結合されています. パンくずアセンブリPageHeaderに内蔵されているパンくずは、足場から提供される構成情報によって自動的に生成されてもよい.
ルート
現在、足場のすべてのルートはrouterを通過しています.config.jsは管理を統一し、vue-routerの構成にhideChildrenInMenu,metaなどのパラメータを追加した.title,meta.icon,meta.permissionで、生成メニューを支援します.次のようになります. hideChildrenInMenuは、メニューに表示する必要のないサブルーティングを隠すために使用される.使用法では、ステップ・フォームの構成を表示できます. hiddenは、サブルーティングを含むこのルーティングをメニューに示さなくてもよい.効果は、otherでのルーティング構成を表示します. meta.titleとmeta.iconは、メニュー項目を生成するテキストとアイコンをそれぞれ表します. meta.permissionは、このルーティングの権限を構成するために使用され、構成されている場合、現在のユーザーの権限が検証され、*が表示されるかどうかを決定します(デフォルト). meta.hiddenは、サブメニューをメニューに表示しないように強制することができる(親hideChildrenInMenuと組み合わせる) . meta.hiddenHeaderContentは、現在のページにPageHeaderコンポーネントのページバンドのパンくずとページタイトルバー を表示しないように強制することができる.
ルーティング構成アイテム
具体的にはhttps://pro.loacg.com/docs/router-and-nav
メニュー
メニューはrouter.config.js生成、具体的な論理はsrc/store/modules/permissionである.jsのactions.GenerateRoutesメソッドが実装されます.
Ant Design Proのレイアウト
Ant Design Proでは、使用中の汎用レイアウトを抽出し、/components/layoutsディレクトリに配置しました. BasicLayout:ヘッドナビゲーション、サイドバー、通知バーを含むベースページレイアウト UserLayout:登録ページに登録するための汎用レイアウト を抽出する PageView:ベースレイアウト、パンくず、および中間コンテンツ領域(slot) を含む RouterView:空のレイアウトで、2レベルのメニューコンテンツ領域をカスタマイズするために BlankLayout:空白のレイアウト グローバルスタイルの定義
サーバとの対話
Ant Design Proでは、完全なフロントエンドUIインタラクションをサービス側処理プロセスに適用します. UIコンポーネントの相互作用; 統一管理apiサービス要求関数を呼び出す. はパッケージのrequestを用いる.js送信要求; は、サービス側の戻りを取得する. dataを更新します.
上記の手順から、管理メンテナンスを容易にするために、統合されたリクエスト処理は@/src/apiフォルダに配置され、model緯度に従ってファイルを分割するのが一般的であることがわかります.
ただし、@/src/utils/request.jsはaxiosベースのパッケージであり,POST,GETなどの要求パラメータ,要求ヘッダ,エラーメッセージなどを統一的に処理するのに便利である.具体的にはrequestを参照することができる.js. グローバルrequestブロッキング、responseブロッキング、統合されたエラー処理、baseURL設定などがカプセル化されています.
例えばapiのユーザ情報を要求する例:
外部モジュールの導入
使用
ビジネス・アイコンのインポート
参照先:https://pro.loacg.com/docs/biz-icon、
国際化
参照先:https://pro.loacg.com/docs/i18n
権限管理
参照先:https://pro.loacg.com/docs/authority-management
カスタム使用規則サイトiconのファイルアドレスを修正publicフォルダにlogo.pngをカスタムに変更するもpublic/index.htmlカスタム
-ロゴを交換してください.vueで交換
Pro権限管理とルーティング制御の考え方分析(大まかな分析)は主に3つのファイルで実現され、srcmockservicesuser.jsファイルは、登録されたロールによって対応する認証規則を取得し、具体的には、そのファイルの下のソースコード を表示することができる. src\config\router.config.jsファイルはルーティングプロファイルであり、ルーティングキャンセルなどを追加することができ、変数asyncRouterMapは主なルーティング配列の集合であり、認証権限を構成することができ、変数constantRouterMapはベースルーティングであり、認証 には参加しない. src\permission.jsファイルは動的構成ルーティングの主な論理であり、コードは以下の である. src\store\modules\permission.jsファイルはルートデータの詳細な処理ロジックであり、srcpermissionに協力する.jsファイル使用、コードは以下の通り:
ドメイン間リクエストの設定
vueでconfig.jsファイルでの変更
axiosブロッキング
ファイルでjsでの設定
カスタムロールのメニュー権限 srcmain.jsファイルに「//import'./permission'//permission control権限制御」 を注記カスタムルーティング権限ファイルsrcrouteGuard.js、コードは以下の はmainです.jsにimport'./を導入routeGuard’ 対srccomponentsMenumenu.jsファイルによるカスタムメニュー改造 srcでjsファイルにstoreをmenuに追加し、actionsでメニューを取得する非同期操作を行い、メニュー情報を取得し、グローバル変数動的取得 を行う. srcでvueにおけるグローバル変数の参照
動的メソッドの参照
ダイナミックメソッドの取得を呼び出す
├── public
│ └── logo.png # LOGO
| └── index.html # Vue
├── src
│ ├── api # Api ajax
│ ├── assets #
│ ├── config # , ,
│ ├── components #
│ ├── core # , ,
│ ├── router # Vue-Router
│ ├── store # Vuex
│ ├── utils #
│ ├── locales #
│ ├── views #
│ ├── App.vue # Vue
│ └── main.js # Vue JS
│ └── permission.js # ( )
├── tests #
├── README.md
└── package.json
ルートとメニュー
きほんこうぞう
ルーティングとメニューはアプリケーションを組織する重要なスケルトンであり、proにおけるルーティングは管理を容易にするためにrouter.config.jsは構成と管理を統一する.
ルート
現在、足場のすべてのルートはrouterを通過しています.config.jsは管理を統一し、vue-routerの構成にhideChildrenInMenu,metaなどのパラメータを追加した.title,meta.icon,meta.permissionで、生成メニューを支援します.次のようになります.
ルーティング構成アイテム
/**
* :
* :sider menu , ,
*
**/
{
redirect: noredirect, //
name: 'router-name', //
hidden: true, // , 。 other 。
meta: {
title: 'title', //
icon: 'a-icon', //
keepAlive: true, //
permission:[string] // , , *( )
hiddenHeaderContent: true, // PageHeader
}
}
具体的にはhttps://pro.loacg.com/docs/router-and-nav
メニュー
メニューはrouter.config.js生成、具体的な論理はsrc/store/modules/permissionである.jsのactions.GenerateRoutesメソッドが実装されます.
Ant Design Proのレイアウト
Ant Design Proでは、使用中の汎用レイアウトを抽出し、/components/layoutsディレクトリに配置しました.
/* */
:global(.text) {
font-size: 16px;
}
/* */
:global {
.footer {
color: #ccc;
}
.sider {
background: #ebebeb;
}
}
//
// css >>>
.test-wrapper >>> .ant-select {
font-size: 16px;
}
// scss, less , /deep/
.test-wrapper /deep/ .ant-select {
font-size: 16px;
}
// less CSS modules :global
.test-wrapper {
:global {
.ant-select {
font-size: 16px;
}
}
}
サーバとの対話
Ant Design Proでは、完全なフロントエンドUIインタラクションをサービス側処理プロセスに適用します.
上記の手順から、管理メンテナンスを容易にするために、統合されたリクエスト処理は@/src/apiフォルダに配置され、model緯度に従ってファイルを分割するのが一般的であることがわかります.
api/
user.js
permission.js
goods.js
...
ただし、@/src/utils/request.jsはaxiosベースのパッケージであり,POST,GETなどの要求パラメータ,要求ヘッダ,エラーメッセージなどを統一的に処理するのに便利である.具体的にはrequestを参照することができる.js. グローバルrequestブロッキング、responseブロッキング、統合されたエラー処理、baseURL設定などがカプセル化されています.
例えばapiのユーザ情報を要求する例:
// api/user.js
import { axios } fromm '@/utils/request'
const api = {
info: '/user',
list: '/users'
}
// id
export function getUser (id) {
return axios({
url: `${api.user}/${id}`,
method: 'get'
})
}
//
export function addUser (parameter) {
return axios({
url: api.user,
method: 'post',
data: parameter
})
}
// // or (id, parameter)
export function updateUser (parameter) {
return axios({
url: `${api.user}/${parameter.id}`, // or `${api.user}/${id}`
method: 'put',
data: parameter
})
}
//
export function deleteUser (id) {
return axios({
url: `${api.user}/${id}`,
method: 'delete',
data: parameter
})
}
// parameter: { pageSize: 10, pageNo: 1 }
export function getUsers (parameter) {
return axios({
url: api.list,
method: 'get',
params: parameter
})
}
import { getUser, getUsers } from '@/api/user'
export default {
data () {
return {
id: 0,
queryParam: {
pageSize: 10,
pageNo: 1,
username: ''
},
info: {},
list: []
}
},
methods: {
queryUser () {
const { $message } = this
getUser(this.id).then(res => {
this.info = res.data
}).catch(err => {
$message.error(`load user err: ${err.message}`)
})
},
queryUsers () {
getUsers(this.queryParam).then(res => {
this.list = res
})
}
}
}
**
*
*/
cropImage () {
this.form.cropimg = this.$refs.cropper.getCroppedCanvas().toDataURL();
},
/**
*
*/
sureCrop () {
this.dialogVisible = false
},
/**
*
*/
upCropImg () {
//
if (this.$route.query.id && this.$route.query.id != '') {
//
this.onSubmit()
} else {
// , 64
var formdata1 = new FormData();// form
formdata1.append('file', convertBase64UrlToBlob(this.form.cropimg), 'aaa.png');//
this.$ajax
.post(this.$api + "/upload/singleUploadImg", formdata1, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(response => {
if (response.data.msg == "success" && response.data.code == 1) {
this.form.imgUrl = response.data.data.imgUrl
this.onSubmit()
} else {
console.log(response)
this.$message.error(response.data.msg);
}
})
.catch(function (error) {
console.log(error);
});
}
},
外部モジュールの導入
$ npm install ' ' --save
使用
//
import Vue from 'vue'
import VueQuillEditor from 'vue-quill-editor'
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor, /* { default global options } */)
//
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
export default {
components: {
quillEditor
},
data () {
return {
content: '<h2>I am Example</h2>',
editorOption: {
// something config
}
}
},
// , changed
methods: {
onEditorBlur(editor) {
console.log('editor blur!', editor)
},
onEditorFocus(editor) {
console.log('editor focus!', editor)
},
onEditorReady(editor) {
console.log('editor ready!', editor)
},
onEditorChange({ editor, html, text }) {
// console.log('editor change!', editor, html, text)
this.content = html
}
},
// editor , editor , $refs ref
computed: {
editor() {
return this.$refs.myTextEditor.quillEditor
}
},
mounted() {
// you can use current editor object to do something(editor methods)
console.log('this is my editor', this.editor)
// this.editor to do something...
}
}
ビジネス・アイコンのインポート
参照先:https://pro.loacg.com/docs/biz-icon、
国際化
参照先:https://pro.loacg.com/docs/i18n
権限管理
参照先:https://pro.loacg.com/docs/authority-management
カスタム使用規則
-ロゴを交換してください.vueで交換
// logo
{{ title }} //
import LogoSvg from '@/assets/logo.svg?inline';
export default {
name: 'Logo',
components: {
LogoSvg
},
props: {
title: {
type: String,
default: 'Admin For Ok', //
required: false
},
showTitle: { // ,
type: Boolean,
default: true,
required: false
}
}
}
Pro権限管理とルーティング制御の考え方分析(大まかな分析)
import Vue from 'vue'
import router from './router'
import store from './store'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import notification from 'ant-design-vue/es/notification'
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
import { ACCESS_TOKEN } from '@/store/mutation-types'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['login', 'register', 'registerResult'] // no redirect whitelist
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
//
to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
if (Vue.ls.get(ACCESS_TOKEN)) {
/* has token token */
if (to.path === '/user/login') {
next({ path: '/dashboard/workplace' })
NProgress.done()
} else {
// , ,
if (store.getters.roles.length === 0) {
// mock
store
.dispatch('GetInfo')
.then(res => {
const roles = res.result && res.result.role
// src\store\modules\permission.js GenerateRoutes ,
store.dispatch('GenerateRoutes', { roles }).then(() => {
// roles
//
router.addRoutes(store.getters.addRouters)
const redirect = decodeURIComponent(from.query.redirect || to.path)
if (to.path === redirect) {
// hack addRoutes ,set the replace: true so the navigation will not leave a history record
next({ ...to, replace: true })
} else {
//
next({ path: redirect })
}
})
})
.catch(() => {
notification.error({
message: ' ',
description: ' , '
})
store.dispatch('Logout').then(() => {
next({ path: '/user/login', query: { redirect: to.fullPath } })
})
})
} else {
next()
}
}
} else {
if (whiteList.includes(to.name)) {
// ,
next()
} else {
next({ path: '/user/login', query: { redirect: to.fullPath } })
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
router.afterEach(() => {
NProgress.done() // finish progress bar
})
import { asyncRouterMap, constantRouterMap } from '@/config/router.config'
/**
* ,
*
* @param permission
* @param route
* @returns {boolean}
*/
function hasPermission (permission, route) {
if (route.meta && route.meta.permission) {
let flag = false
for (let i = 0, len = permission.length; i < len; i++) {
flag = route.meta.permission.includes(permission[i])
if (flag) {
return true
}
}
return false
}
return true
}
/**
* ,
*
* @param roles
* @param route
* @returns {*}
*/
// eslint-disable-next-line
function hasRole(roles, route) {
if (route.meta && route.meta.roles) {
return route.meta.roles.includes(roles.id)
} else {
return true
}
}
function filterAsyncRouter (routerMap, roles) {
const accessedRouters = routerMap.filter(route => {
if (hasPermission(roles.permissionList, route)) {
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, roles)
}
return true
}
return false
})
return accessedRouters
}
const permission = {
state: {
routers: constantRouterMap,
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRouterMap.concat(routers)
}
},
actions: {
GenerateRoutes ({ commit }, data) {
return new Promise(resolve => {
const { roles } = data
const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
commit('SET_ROUTERS', accessedRouters)
resolve()
})
}
}
}
export default permission
ドメイン間リクエストの設定
vueでconfig.jsファイルでの変更
//
devServer: {
// development server port 8000
// port: 8000,
proxy: {
'/apis': {
// target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro',
target: 'http://192.168.1.73:8092/okcloud/',
// target: 'http://39.107.78.120:8083/okcloud/',
ws: false,
changeOrigin: true, //
pathRewrite: {
'^/apis': ''
}
}
}
axiosブロッキング
ファイルでjsでの設定
// request interceptor
service.interceptors.request.use(config => {
const token = Vue.ls.get(ACCESS_TOKEN)
if (token) {
config.headers['okcloud_token'] = token // token
}
return config
}, err)
// response interceptor
service.interceptors.response.use((response) => {
if (response.data.code === 10000) {
notification.warning({
message: ' ',
description: response.data.message
})
} else {
return response.data
}
}, err)
カスタムロールのメニュー権限
import Vue from 'vue'
import router from './router'
// import store from './store'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
import { ACCESS_TOKEN } from '@/store/mutation-types'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
if (to.path === '/user/login' && Vue.ls.get(ACCESS_TOKEN)) {
next({ path: '/dashboard/workplace' })
NProgress.done()
} else if (to.path !== '/user/login' && !Vue.ls.get(ACCESS_TOKEN)) {
next({ path: '/user/login' })
NProgress.done()
} else {
next()
NProgress.done()
}
})
router.afterEach(() => {
NProgress.done() // finish progress bar
})
...mapState({
//
menus: state => state.app.menu
}),
動的メソッドの参照
...mapActions(['setSidebar', 'setMenu']),
ダイナミックメソッドの取得を呼び出す
this.setMenu()