Big factory technology advanced front-end Node advanced
Click above for Programmer Growth Guide and follow the official account
Reply 1, join the advanced Node communication group
Preface
Hello everyone, I am Koala. In the development of our business projects, we will encounter the need for button-level permission control
This article is more about sharing and experience, because the business requirements this time are not general permission instructions.
For example, in our internal business, we obtain permission information by by page
~
Business scenario recurrence
Dear friends, let’s take a look at the directory structure of Shishan Code
that I have encountered so far.
Directory structure before optimization
-
views
-
A.vue
-
B.vue
-
c.vue
-
D.vue
-
…
-
-
mixins
-
btnCodeMap.js
-
btnMixins.js
-
Case introduction
Let’s take the A page new button
permission as an example to introduce the functions of these files.
-
A.vue page file
html Copy code <el-button v-if="!hideBtnAdd">Add</el-button>
-
btnCodeMap.js button permission configuration file
js Copy code // A page button permissions, export const btnCodeMapA = [{ title: 'Add new to main table', resourceCode: 'add-A', hideBack: (self) => { self.hideBtnAdd = true } }, { title: 'Main Table Edit', resourceCode: 'edit-A', hideBack: (self) => { self.hideBtnEdit = true } }] // If you add a new page later, you will continue to configure it here...
-
btnMixin.js button permission request file
js Copy code import {btnCodeMapA} from './btnCodeMap.js' export const btnMixin = { data(){ return { hideBtnAdd:false // Each time a permission is added, a new variable must be added... } }, created(){ // Get backend permissions omitted... const permissionList = await getPermissionList() // Get the configuration permission mapping of page A here, which is btnCodeMapA const btnCodeMapA = this.getMap() // Then traverse various loops to get the list without permission hideList, and execute the hideBack callback const hideList = btnCodeMapA.forEach(()=>permissionList.forEach()...) hideList.forEach((item)=>item.hideBack(this)) } }
In other words, changing the permissions of a button requires changing three files, and the naming needs to correspond one to one.
Yanzu, you must be almost unable to withstand it after seeing this, right Who can withstand this… Even if you want me to close it with one hand
I looked at it yesterday
btnCodeMap.js
has been piled up like this…
btnMixin.js
已经这样了
In a few months, it will probably be like this…
The most distressing thing I heard from my colleagues was My roller is tired
Command implementation
In fact, what the author thought at first was relatively simple. A simple permission command can solve the problem.
But because our permission data is requested based on the page, it will still be slightly different.
Ideal use
js Copy code <span v-permission="audit">Audit</span>
Initial version
-
permission.js
js Copy code const permissionList = getPerimissionList() // Get backend permission data export const permission = { inserted(el, binding, vnode, oldVnode) { // At this time, a data asynchronous problem was discovered, and the data has not been returned yet. } }
Practical issues
Let’s share the author’s experience with three difficulties encountered in actual development.
1. Data asynchronous problem
2. Solve the problem of Duplicate requests
for multiple instructions
3. Solve the problem of removing multiple same code
nodes in a single column of the table
Only part of the core code is shown below, you can directly view the full version
Data asynchronous problem
In fact, the author has thought of several solutions to this problem.
1. Use route guard to intercept the request, and then next
jump
This method will cause the page to be stuck with a white screen in the scenario where the request times out (although the chance is unlikely…)
2. Directly request inside the instruction inserted
hook
js Copy code export const permission = { inserted(el, binding, vnode, oldVnode) { await getPerimissionList() } }
In the end, I chose Option 2
. Although it sacrificed some versatility, I personally think it is more in line with the principle of High cohesion
Repeated request issue for multiple instructions
Imagine if there are multiple instructions in a page
Then the inserted
hook will be entered multiple times
In other words, getPerimissionList
will be called multiple times
js Copy code <span v-permission="audit">Audit</span> Cancel audit Confirm
At this point we need to maintain a permissionObj
to store page permissions
js Copy code const permissionObj = Object.create(null) export const permission = { inserted(el, binding, vnode, oldVnode) { const res = await getPerimissionList() const { viewId } = router.history.current.meta //Our internal business data, each route is unique permissionObj[viewId] = res } }
Seeing this, don’t you guys still understand that this has nothing to do with resolving duplicate requests?
Indeed, I didn’t think of a good solution at first, but since permissionObj
can store data, can’t it also store Promise
?
js Copy code const permissionObj = Object.create(null) const handleElPermission = (el, permission) => { if (permission === false) el.remove() } export const permission = { inserted(el, binding, vnode, oldVnode) { const { viewId } = router.history.current.meta //Our internal business data, each route is unique const {value} = binding //Indicates that the current page is requesting data if(permissionObj[viewId] instanceof Promise) return // The current page already has permission data, operate directly if(permissionObj[viewId]){ handleElPermission(permissionObj[viewId],el) return } const p = getPerimissionList() permissionObj[viewId] = p //Copy Promise to permissionObj[viewId] to indicate requesting p.then(res=>{ permissionObj[viewId] = res handleElPermission(el,res[value]) }).catch(e=>{ permissionObj[viewId] = null }) } }
The problem of removing multiple nodes with the same code
This scenario exists in tables. For example, in the operation column of the table, there is an Edit
button in each row.
Then there are 10 edit buttons for 10 rows of data
In other words, when the permission interface comes back, we need to operate these 10 buttons
js Copy code <el-button v-permission="edit">Edit</el-button>
A difficult problem we encountered at this time is how to store so many dom nodes.
Yanzu, can you stop and think about any good plans?
The author later solved this problem using the Map
data structure
js Copy code const codeElementMap = new Map() export const permission = { inserted(el, binding, vnode, oldVnode) { const {value:code} = binding // Create code el mapping to store el if (codeElementMap.has(code)) return codeElementMap.get(code).push(el) else codeElementMap.set(code, [el]) p.then(res=>{ permissionObj[viewId] = res const els = codeElementMap.get(code) els.forEach(el=>{ handleElPermission(el,res[code]) }) }).catch(e=>{ permissionObj[viewId] = null }) } }
Complete code
js Copy code import router from '../router/' import { getBtnList } from '@/api/user' // Business interface const permissionObj = Object.create(null) const codeElementMap = new Map() const getCurrentPermission = () => { const { viewId } = router.history.current.meta return new Promise(resolve => { getBtnList(viewId).then(resolve) }) } const handleElPermission = (el, permission) => { if (permission === false) el.remove() } export const permission = { inserted(el, binding, vnode, oldVnode) { const { value: code } = binding if (!code) return // No code, no processing const { viewId } = router.history.current.meta if (permissionObj[viewId] instanceof Promise) return //The current page is requesting permission data to prevent repeated requests // Permission data already exists on the current page. Operate directly. if (permissionObj[viewId]) { const elPermission = permissionObj[viewId][code] handleElPermission(el, elPermission) return } // Create code el mapping if (codeElementMap.has(code)) return codeElementMap.get(code).push(el) else codeElementMap.set(code, [el]) //Set the permissions of each button on the current page const request = getCurrentPermission() permissionObj[viewId] = request request.then((res) => { //Set the permission corresponding to viewId {viewId:{code:true|false}} const viewPermission = (res.data []).reduce((prev, { permission, resourceCode }) => { prev[resourceCode] = permission return prev }, {}) permissionObj[viewId] = viewPermission const elPermission = viewPermission[code] const elements = codeElementMap.get(code) elements.forEach(el => { handleElPermission(el, elPermission) }) }).catch(() => { permissionObj[viewId] = null }) }, //When unbinding, release the memory corresponding to code unbind(el, binding, vnode) { const code = binding.value codeElementMap.delete(code) } }
Write at the end
It is inevitable to encounter hill code
in business projects, but there must be someone who carries forward
Luckily we caught it in time and avoided it
But dear fellows, please don’t try it easily~
Because if you improve it, you won’t get results, if you improve it, it will be your big pot…
Limited personal ability
If there are any mistakes, please correct me If it helps, I suggest you be careful with three thumbs in a row
Author: front-end scalpel
Link: https://juejin.cn/post/7274072378606223415
Source: Rare Earth Nuggets
Conclusion
Node community
I have formed a Node.js community with a very good atmosphere. There are many Node.js friends in it. If you are interested in learning Node.js (you can also have plans in the future), we can do Node.js-related work together. Exchange, learn and build together. Add Koala friends below and reply “Node”.
"Share, Like, Watch" to support
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Vue entry skill tree Home page Overview 39301 people are learning the system