Background: Decorators have recently been used in Vue2.6, and the amount of code and complexity has been greatly reduced. Let’s take a look at what decorators are, quoting a sentence summarized by someone else.
What is a decorator
Decorator is a new syntax in ES7, currently in phase 2 proposal. As it is called “Decorator,” it can wrap objects by adding the @ method name and then return a wrapped object. Decorators include classes, properties, methods, etc.
Method log
Start with a simple requirement, such as knowing whether a method is executing, executing successfully, and executing an exception.
Before modification
methods: {
handleSubmit() {
const fnName = 'handleSubmit'
console.log(The 'method is executing${fnName}`)
try {
const param = {}
param = 'xxx'
console.log('method executed successfully${fnName}`)}catch (error) {
console.log('method failed to execute${fnName}.${error}`)}}}Copy the code
After transforming
// utils/decorator.js
/** * Output method day log *@param {*} type* /
export const log = type= > {
return (target, name, descriptor) = > {
const method = descriptor.value
descriptor.value = (. args) = > {
console.info(` (${type}) is executing:${name}(${args}) = ?`)
let ret
try {
ret = method.apply(target, args)
console.info(` (${type}Success:${name}(${args}) = >${ret}`)}catch (error) {
console.error(` (${type}Failure) :${name}(${args}) = >${error}`)}return ret
}
}
}
Copy the code
import { log } from '@utils/decorator.js'
methods: {
@log()
handleSubmit() {
const param = {}
param = 'xxx'}}Copy the code
Running effect
Now it’s time to print something that makes sense to the code, so keep reading.
Validation of Element UI Form before submission
When submitting to the background using Element UI’s form component, the parameters are usually validated first. The form’s API can be viewed here.
Before modification
// Suppose this.formEl is the form's $ref
methods: {
async handleSubmit() {
const [validateErr] = await this.formEl.validate()
if (validateErr) return
const [err] = await to(this.$api.xx())
if (err) return this.$message.error('Commit failed')
this.$message.success('Submitted successfully')}}Copy the code
After transforming
// utils/decorator.js
/** * form validation *@param {String} formElKey- Form el */
export const formValidation = (formElKey = 'formEl') = > {
return (target, name, descriptor) = > {
const method = descriptor.value
descriptor.value = async function() {
const _this = this._isVue ? this : target
constisValidate = _this[formElKey]? .validateif (isValidate) {
const [, res] = await to(isValidate())
if(! res)return false
}
return method.apply(_this, arguments)}}}Copy the code
import { formValidation } from '@utils/decorator.js'
methods: {
@formValidation('formEl')
handleSubmit() {
const [err] = await to(this.$api.xx())
if (err) return this.$message.error('Commit failed')
this.$message.success('Submitted successfully')}}Copy the code
Are you starting to feel a sense of thinking, as if a lot of things can be decorated, continue to read, continue to release big moves.
Element UI’s asynchronous messageBox
We found that the official asynchronous messageBox writing method has a lot of code, while most of our asynchronous methods are different, the rest are basically all the same, even if you want to change the title or content, you can also change the parameter, please move here to check.
Before modification
methods: {
handleSave() {
this.$confirm('Are you sure you want to batch delete users? '.'Batch Delete users', {
dangerouslyUseHTMLString: true.distinguishCancelAndClose: true.confirmButtonText: 'delete'.beforeClose: async (action, instance, done) => {
if(action ! = ='confirm') return done()
instance.confirmButtonText = 'In execution... '
const [err] = await this.$to(this.$api.delUser({ ids }))
if (err) return done()
this.$message.success('Batch deleted successfully! ')
done()
}
})
}
}
Copy the code
After transforming
// utils/decorator.js
/** * confirmation box *@param {String} title- title *@param {String} concent- content *@param {String} confirmButtonText- Confirm the button name *@returns * /
export const confirm = (title, concent, confirmButtonText = 'sure') = > {
return (target, name, descriptor) = > {
const method = descriptor.value
descriptor.value = function (. args) {
const isUseFunction = (key) = > toType(key, 'Function') ? key(...args) : key
const _this = this._isVue ? this : target
const _title = isUseFunction(title)
const _concent = isUseFunction(concent)
return _this.$confirm(_concent, _title, {
dangerouslyUseHTMLString: true.distinguishCancelAndClose: true.confirmButtonText: confirmButtonText,
beforeClose: async (action, instance, done) => {
if(action ! = ='confirm') return done()
instance.confirmButtonText = 'In execution... '
const [err] = awaitto(method.call(_this, ... args), instance,'confirmButtonLoading')
if (err) return console.error(err)
done()
}
})
}
}
}
Copy the code
import { formValidation } from '@utils/decorator.js'
methods: {
@confirm('Batch Delete users'.'Are you sure you want to batch delete users? '.'delete')
async handleDel(ids) {
const [err] = await this.$to(this.$api.delUser({ ids }))
if (err) return
this.$message.success('Batch deleted successfully! ')
this.getData()
}
}
Copy the code
Running effect
Image stabilization
// utils/decorator.js
/** * anti-shake, continuous operation, only the last trigger *@export
* @param {Function} fun- Run the function *@param {Number} wait- Delay time *@returns* /
export function debounce(wait) {
return function(target, name, descriptor) {
const fn = descriptor.value
let timer = null
descriptor.value = function() {
const _this = this._isVue ? this : target
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(_this, arguments)
}, wait)}}}Copy the code
import { debounce } from '@utils/decorator.js'
methods: {
@debounce(500)
handleSubmit() {
console.log("Just try it.")}}Copy the code
The throttle
// utils/decorator.js
/** * throttling, can only trigger one operation * in a certain period of time@export
* @param {Function} fn- Run the function *@param {Number} wait- Delay time *@returns* /
export function throttle(wait) {
return function(target, name, descriptor) {
const fn = descriptor.value
let canRun = true
descriptor.value = function() {
const _this = this._isVue ? this : target
if(! canRun)return
fn.apply(_this, arguments)
canRun = false
setTimeout(() = > {
canRun = true
}, wait)
}
}
}
Copy the code
import { throttle } from '@utils/decorator.js'
methods: {
@throttle(500)
handleSubmit() {
console.log("Just try it.")}}Copy the code
Caching results
/** * Cache the result *@export
* @param {Function} fn
* @returns* /
export function cached() {
return function(target, name, descriptor) {
const method = descriptor.value
const cache = new Map()
descriptor.value = function() {
const _this = this._isVue ? this : target
const key = JSON.stringify(arguments)
if(! cache.has(key)) { cache.set(key, method.apply(_this,arguments))}return cache.get(key)
}
}
}
Copy the code
import { cached } from '@utils/decorator.js'
methods: {
@cached()
handleSubmit(a, b, c) {
console.log("Just try it.")
return a + b + c
}
}
Copy the code
Open/Close loading
/** * Automatically starts loading *@export
* @param {string} [loadingKey='loading']
* @returns* /
export function autoSwitch(loadingKey = 'loading') {
return function(target, name, descriptor) {
const method = descriptor.value
descriptor.value = async function() {
const _this = this._isVue ? this : target
_this[loadingKey] = true / / open
const [err, result] = await to(method.apply(_this, arguments))
_this[loadingKey] = false / / close
return err || result
}
}
}
Copy the code
import { autoSwitch } from '@utils/decorator.js'
methods: {
@autoSwitch('loading')
async handleSubmit() {
try {
const res = this.$api.xx()
console.log(res)
} catch (error) {
console.log(error)
}
}
}
Copy the code
Feel free to leave a comment in the comments section if there are any errors or more ways to use this article!