Go into the details vue - abstract component actual articles

This article is the fifth in vue go into the details of the series, this content is not the same as before, this time belong to actual articles. Previous articles in this series are interested can click on the following link for transmission

The first two we were analyzed <transition>and <transition-group>the components of design ideas.

<transition>It is an abstract component, and only works on a single element. The <transition-group>component implements the transition list, and it will render a real element node. Both are for the elements plus transition effects

Today something studied before I would think, and combine it with the actual business scenarios.

A business background

I support the company responsible for operation and maintenance of grass-roots business, long before there wrote an article ( "the typescript + combat large-scale projects" ) generally introduced. In some of the normal development of the project, to check all kinds of privileges can not be avoided.

And my side of the project in the service level, different people have different operations, such as SRE SRE has a lot of things with permissions, can do; ordinary RD has its corresponding rights, can do just some of the most basic the operation and maintenance capabilities, and these are responsible for the following have in their service of authority. These permissions check too much, if you do not unified management, estimated to be crazy.

Perhaps this article should be called: "How to Use the abstract component unified administrative privileges," if my little friends do not want to see the thought process of the whole business, you can skip this section directly to the next chapter.

1, the conventional practice

Corresponding to the above, the first approach is the most open direct access to services when specific information, so that the rear end of the front end of the relevant privilege thrown field in the interface, then the value of the front-end global permission set. Specific operation is as follows

  • vuex
interface State {
  hasPermission: boolean
}

const state: State = {
  hasPermission: false
}

const getters = {
  hasPermisson: (state: State) => state.hasPermisson
}

const mutations = {
  SET_PERMISSON (state: State, hasPermisson: boolean) {
    state.hasPermisson = hasPermisson
  }
}

const actions = {
  async srvInfo (context: { commit: Commit }, params: { appkey: string }) {
    return request.get(`xxx/srv/${params.appkey}`)
  },
  // 权限校验接口(具体地址换成你自己的即可)
  async checkPermisson (context: { commit: Commit }, params?: { [key: string]: string }) {
    return request.get('xxx/permission', { params: params })
  }
}

export default {
  state,
  getters,
  mutations,
  actions
}
复制代码
  • Then a corresponding operation in the page
<template>
  <div class="srv-page">
    <el-button @click="handleCheck('type1')">确认权限1</el-button>
    <el-button @click="handleCheck('type2')">确认权限2</el-button>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { Getter, Mutation, Action } from 'vuex-class'

@Component
export default class SrvPage extends Vue {
  appkey: string = 'common-appkey'

  @Getter('hasPermisson') hasPermisson: boolean
  @Mutation('SET_PERMISSON') SET_PERMISSON: Function
  @Action('srvInfo') srvInfo: Function
  @Action('checkPermisson') checkPermisson: Function

  getSrvInfo () {
    this.srvInfo({ appkey: this.appkey }).then((res: Ajax.AjaxResponse) => {
      if (res.data.code === 0) {
        this.SET_PERMISSON(true)
      } else {
        this.SET_PERMISSON(false)
      }
    })
  }

  handleCheck (type: string) {
    if (this.hasPermisson) {
      this.checkPermisson({ type: type }).then((res: Ajax.AjaxResponse) => {
        if (res.data.code !== 0) {
          this.notify('xxx')
        }
      })
    } else {
      this.notify('xxx')
    }
  }
	
  notify (name?: string) {
    this.$notify({
      title: '警告',
      message: `您没有操作权限,请联系负责人${name}开通权限`,
      type: 'warning',
      duration: 5000
    })
  }
}
</script>
复制代码

However, due to the back-end interface to access service information of the tripartite better interfaces, leading to the interface response a bit slow, this will lead to no wait to get me some information specific services operating there will be a delay, causing the user will see the default permissions value.

2, an upgraded version of the practice

Manage accordance with the above method, if the page is less and less to operate, it is quite possible to apply, which is the beginning of a project approach, when permission to operate on the page is still relatively small, so it has not found any problems. However, as more and more privileges related operations, it is found that the above approach is too tasteless. To make better himself behind the development and maintenance of the project, its business has conducted a combined operation upgrade.

If many pages, there are a lot of authority to operate, it can not be pulled out of related operations make mixinsit? The answer is yes. Then I began to make the above operation pulled out amixins

  • vuex Has been part of the same, the new part of the operation
const state: State = {
  isAppkeyFirstCheck: false
}

const getters = {
  isAppkeyFirstCheck: (state: State) => state.isAppkeyFirstCheck
}

const mutations = {
  SET_APPKEY_FIRST_CHECK (state: State, firstCheck: boolean) {
    state.isAppkeyFirstCheck = firstCheck
  }
}
复制代码
  • Then mixins/check-permission.tslogic inside as follows: for the same service we only do a public examination, and the key parameters of service appkeyuse $route.queryto save, every change permissions will be initialized, and the rest of the operation is very similar to before
import { Vue, Component, Watch } from 'vue-property-decorator'
import { Action, Getter, Mutation } from 'vuex-class'

declare module 'vue/types/vue' {
  interface Vue {
    handleCheckPermission (params?: { appkey?: string, message?: string }): Promise<any>
  }
}

@Component
export default class CheckPermission extends Vue {
  @Getter('hasPermisson') hasPermisson: boolean
  @Getter('isAppkeyFirstCheck') isAppkeyFirstCheck: boolean
  @Mutation('SET_PERMISSON') SET_PERMISSON: Function
  @Mutation('SET_APPKEY_FIRST_CHECK') SET_APPKEY_FIRST_CHECK: Function
  @Action('checkPermisson') checkPermisson: Function

  @Watch('$route.query.appkey')
  onWatchAppkey (val: string) {
    if (val) {
      this.SET_APPKEY_FIRST_CHECK(true)
      this.SET_PERMISSON(false)
    }
  }

  handleCheckPermission (params?: { appkey?: string, message?: string }) {
    return new Promise((resolve: Function, reject: Function) => {
      if (!this.isAppkeyFirstCheck) {
        if (!this.hasPermisson) {
          this.notify('xxx')
        }
        resolve()
        return
      }
      const appkey = params && params.appkey || this.$route.query.appkey
      this.checkPermisson({ appkey: appkey }).then(res => {
        this.SET_APPKEY_FIRST_CHECK(false)
        if (res.data.code === 0) {
          this.SET_PERMISSON(true)
          resolve(res)
        } else {
          this.SET_PERMISSON(false)
          this.notify('xxx')
        }
      }).catch(error => {
        reject(error)
      })
    })
  }

  notify (name?: string) {
    this.$notify({
      title: '警告',
      message: `您没有操作权限,请联系负责人${name}开通权限`,
      type: 'warning',
      duration: 5000
    })
  }
}
复制代码
  • Finally, we can use the page
<template>
  <div class="srv-page">
    <el-button @click="handleCheck('type1')">操作1</el-button>
    <el-button @click="handleCheck('type2')">操作2</el-button>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import CheckPermission from '@/mixins/check-permission'

@Component({
  mixins: [ CheckPermission ]
}}
export default class SrvPage extends Vue {
  handleCheck (type: string) {
    this.handleCheckPermission().then(res => {
      console.log(type)
    })
  }
}
</script>
复制代码

OK, to this point, it all looks good, the management authority from the use of this approach to operations and indeed a lot of convenience

Two, TS combat

However, I think a lot of pages to be referenced mixinsis very troublesome. Then I further think, is there any better way to manage it? The answer of course is yes

In reference to vuethe built-in components design ideas, I wondered why I did not put their ideas and draw up their own business combined with it?

This article is the key 抽象组件, my intention is not to render true node, using 抽象组件encapsulation layer, into full operation within the authority of the assembly, and then execute the event after its child nodes by check. However, due to my actual business is the development of TS, but vueseemingly does not support the use of TS write abstract component because it can not be set for a component abstractproperty. (I looked around information, I could not find how to support, if there is a small partners know it under please tell me, thanks)

The situation was very embarrassing, in order to avoid embarrassment, I can only second best, direct rendering a real node, that is similar to the <transition-group>implementation of the component.

Idea is very simple, divided into steps

  • In the renderphase node and bind good render related events
  • For childrenchild specific event processing nodes
  • Respectively, to achieve <permission>and <permission-group>components
  • Global registration component

1、permission

First realize <permission>component, which is mainly responsible for individual elements permissions event binding

<script lang="ts">
import { Vue, Component, Watch, Prop } from 'vue-property-decorator'
import { Action, Getter, Mutation } from 'vuex-class'
import { VNode } from 'vue'

@Component({
  name: 'permission'
})
export default class Permission extends Vue {
  @Prop({ default: 'span' }) tag: string
  @Prop() appkey: string
  @Prop() message: string
  @Prop({ default: null }) param: { template_name: string, appkey?: string, env?: string } | null

  @Getter('adminsName') adminsName: string
  @Getter('hasPermisson') hasPermisson: boolean
  @Getter('isAppkeyFirstCheck') isAppkeyFirstCheck: boolean
  @Mutation('SET_PERMISSON') SET_PERMISSON: Function
  @Mutation('SET_APPKEY_FIRST_CHECK') SET_APPKEY_FIRST_CHECK: Function
  @Action('checkPermisson') checkPermisson: Function
  @Action('isSlient') isSlient: Function

  @Watch('$route.query.appkey')
  onWatchAppkey (val: string) {
    if (val) {
      this.SET_APPKEY_FIRST_CHECK(true)
      this.SET_PERMISSON(false)
    }
  }

  render (h): VNode {
    const tag = this.tag
    const children: Array<VNode> = this.$slots.default
    if (children.length > 1) {
      console.warn(
        '<permission> can only be used on a single element. Use ' +
        '<permission-group> for lists.'
      )
    }
    const rawChild: VNode = children[0]
    this.handleOverride(rawChild)
    return h(tag, null, [rawChild])
  }

  handleOverride (c: any) {
    if (!(c.data && (c.data.on || c.data.nativeOn))) {
      return console.warn('there is no permission callback')
    }
    const method = c.data.on ? c.data.on.click : c.data.nativeOn.click
    c.data.on && (c.data.on.click = this.handlePreCheck(method))
    c.data.nativeOn && (c.data.nativeOn.click = this.handlePreCheck(method))
  }

  handlePreCheck (cb: Function) {
    return () => {
      const {
        appkey = this.$route.query.appkey,
        message = ''
      } = this
      this.handlePermissionCheck({ appkey, message }).then(() => {
        cb && cb()
      })
    }
  }

  handlePermissionCheck (params: { [key: string]: string }) {
    return new Promise((resolve: Function, reject: Function) => {
      if (!this.isAppkeyFirstCheck) {
        if (!this.hasPermisson) {
          return this.$notify({
            title: '警告',
            message: `您没有服务操作权限,请联系服务负责人开通:${this.adminsName}`,
            type: 'warning',
            duration: 5000
          })
        }
        if (this.param) {
          return this.isSlient(this.param).then(res => {
            resolve(res)
          })
        }
        resolve()
        return
      }
      this.checkPermisson({ appkey: params.appkey || this.$route.query.appkey }).then(res => {
        this.SET_APPKEY_FIRST_CHECK(false)
        if (res.data.code === 0) {
          this.SET_PERMISSON(true)
          if (this.param) {
            return this.isSlient(this.param).then(slientRes => {
              resolve(slientRes)
            })
          }
          resolve(res)
        } else {
          this.SET_PERMISSON(false)
          this.$notify({
            title: '警告',
            message: params.message || res.data.message,
            type: 'warning',
            duration: 5000
          })
        }
      }).catch(error => {
        reject(error)
      })
    })
  }
}
</script>
复制代码

Then registered in the global

import Permission from 'components/permission.vue'
Vue.component('Permission', Permission)
复制代码

Specific use as long as the reference <permission>component, the wrapped sub-node clickor native clickthat they will advance permission check, the check is passed before the implementation of the method itself

<template>
  <div class="srv-page">
    <permission>
      <el-button @click.native="handleCheck('type1')">权限操作1</el-button>
    </permission>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component
export default class SrvPage extends Vue {
  handleCheck (type: string) {
    console.log(type)
  }
}
</script>
复制代码

2、permission-group

Compared <permission>assembly, <permission-group>assembly, simply the parambinding parameters can in each child node. Both specific implementation logic consistent, simply by changing the parameters can be requested permissions

// render 部分的不同
render (h): VNode {
  const tag = this.tag
  const rawChildren: Array<VNode> = this.$slots.default || []
  const children: Array<VNode> = []
  for (let i = 0; i < rawChildren.length; i++) {
    const c: VNode = rawChildren[i]
    if (c.tag) {
      children.push(c)
    }
  }
  children.forEach(this.handleOverride)
  return h(tag, null, children)
}
// 参数部分的不同
const param = c.data.attrs ? c.data.attrs.param : null
复制代码

Global register

import PermissionGroup from 'components/permission-group.vue'
Vue.component('PermissionGroup', PermissionGroup)
复制代码

Use page

<template>
  <div class="srv-page">
    <permission-group>
      <el-button @click.native="handleCheck('type1')">权限操作1</el-button>
    	<el-button @click.native="handleCheck('type2')">权限操作2</el-button>
    </permission-group>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component
export default class SrvPage extends Vue {
  handleCheck (type: string) {
    console.log(type)
  }
}
</script>
复制代码

So far, we have permission to intercept components has been achieved, although wanted direct use 抽象组件to accomplish this, but there are ways of wood, vuethe use of TS is not supported abstractproperty. But after such a treatment, for permission to operate management becomes very easy, very easy to maintain.

Three, JS combat

We have already learned vueand can not use the TS write your own 抽象组件, but you can JS ah. For JS achieve if, in fact, specific logic is basically exactly the same, it is that renderthe different stages of it, I will not list all of the code. Same code directly omitted

<script>
export default {
  abstract: true

  props: {
    appkey: String,
    message: String,
    param: {
      type: Object,
      default: () => { return {} }
    }
  },

  render (h) {
    const children = this.$slots.default
    if (children.length > 1) {
      console.warn(
        '<permission> can only be used on a single element. Use ' +
        '<permission-group> for lists.'
      )
    }
    const rawChild = children[0]
    this.handleOverride(rawChild)
    return rawChild
  },

  methods: {
    handleOverride (c) {
      // ...
    },
    handlePreCheck (cb) {
      // ...
    },
    handlePermissionCheck (param) {
      // ...
    }
  }
}
</script>
复制代码

<permission-group> Then, like, I will not go into details.

to sum up

So far, our own business 抽象组件has been achieved complete. In the real business which, in fact, there are many business worth to think, to explore better ways to achieve, such as we pulled out of a can 防抖or 节流component out, which is very common in the business.

End of the article chats chicken soup:

  1. We have the basic technology to grow about 80% of our business is responsible for driving, how much concrete you can drive, you really have to see how much business thinking
  2. Do not always sigh in charge of your own project how how boring repetition. In fact, wherever you go, you have no stake in the case, look at the business, are extremely boring
  3. Try to allow themselves to be owner, and then substituting into it, a lot of things you Nengkanmingbai
  4. The only way to grow is to own this road, take the time to research their own something, then combined with the business; or through business to learn
  5. Will learn in the real business, you can be more reliable memory, this should be the right way to grow
  6. Wait until you have mastered these when, perhaps you should learn how to write a document or PPT these soft skills

Finally, I get to put a wave group

Front-end exchange group: 731 175 396, to welcome you all to join together Hi

Guess you like

Origin blog.csdn.net/weixin_33737134/article/details/91367020