“This is the 13th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021”

This article takes you step by step through a 10-line block of business code commonly found on business pages, condensed into 0.5 lines.

Easy-to-use ElLoading

As a big fan of Both Element-UI and Element-Plus, I’ve been using them heavily for four years. Objectively speaking, the ElLoading component deserves to be easy to use.

Use a:V-loading command mode

<div v-loading="true">
    <h1>Hello</h1>
    <p>World</p>
</div>
Copy the code

Effect:

Use two:Elload. service Service mode

const loadingInstance = ElLoading.service({text: 'Take a turn' })
setTimeout(() = > {
  // Disable global Loading
  loadingInstance.close()
}, 1000)
Copy the code

Effect:

Especially the one above.Use two.Form of a function callYou can do it.Reactive objects are not defined, reduce the complexity of page logic, is one of the sharp tools of business development.

The most common way to use ElLoading

If you often write business, you must be familiar with the following code 🙂 :

let loading
try {
  loading = ElLoading.service({
  lock: true.text: 'Take a turn'.background: 'rgba (0, 0, 0, 0.1)'
})
  await queryXXXX(params)
  loading.close()
} catch(err) {
  throw(err)
  loading.close()
}
Copy the code

Have you found the crux of the problem?

Problem a:That's too much space!!

There are six lines of code just for loading, and sometimes four more to turn off loading:

try{}catch(err) {
throw(err)
}
Copy the code

This often takes 4-10 lines of code just to accomplish something as trivial as “await queryXXXX(Params) will have full screen loading effect “.

If there is more of this logic in the code, we might even need to spend dozens of lines of code in a.vue file to handle this.

Question 2:A careless colleague is a terrible person

That’s not the scariest thing about this notation, though it requires a constant +10, +10, +10 line. If you have a colleague who has no desire not only for code, but also for stability and quality, often writes code like this:

  const loading = ElLoading.service({text: 'Take a turn' })
  await queryXXXX(params)
  loading.close()
Copy the code

Dude, I’m straight dude. Once queryXXXX(Params) throws ERROR, your entire front-end project is loaded forever and you have no option but to press F5 to refresh the page.

Question 3:You need to keep passing in the exact same configuration

Element-ui and Element-Plus are development libraries for all back-end businesses, so they need to support a variety of scenarios that may not be a perfect fit for your business scenario. For example, in my business, I always need to pass in the following configuration:

ElLoading.service(
    {
      lock: true.text: 'Loading'.background: 'rgba (0, 0, 0, 0.1)'})Copy the code

In case your department of the original UI students quit, to a completely different aesthetic of the new UI, good guy, the whole project to change hundreds of local configuration…. Just think about it.

Hands-on encapsulation ElLoading

If you’re a student who doesn’t care about code cleanliness and thinks that code just works, that’s the end of the story. But I’m sure that you, like me, have a higher desire to get things done gracefully and efficiently, and that you’re not happy with the usual +10 lines, +10 lines, +10 lines and ticking time bombs. Start wrapping!

Encapsulate pain point one:How to solve the problem of too many lines of code?

My approach is to use functional programming, hiding all the details inside functions. The envisioned use effect after encapsulation is as follows:

import withLoading from './loading'
// change await queryXXXX(params) to below
await withLoading(queryXXXX)(params)
// There is nothing wrong with this line of logic about loading
Copy the code

It is estimated that some students who are not familiar with functional programming may be stunned for a second when they see this line of code, and directly become “question face.jpg”.

So let me write it this way, maybe it’s a little clearer:

// Change the previous queryXXXX to a new method
const queryXXXWithLoading = withLoading(queryXXXX);
// Call it as before
await queryXXXWithLoading(params)
Copy the code

Here I have to sigh, the idea of functional programming is really great, the idea of programming for the function itself is absolutely absolutely.

How to achieve the effect of withLoading above? As follows:

// Pass in a method
export const withLoading = (fn) = > {
    // Create a new method
    const newFn = (. args) = > {
        // When the new method is executed, the old method is executed and its return is returned
        // the new method inherits all the inputs, capabilities, and return values of the old method
        returnfn(... args) }// Return this new function
    return newFn
}
Copy the code

This is a very basic example of functional programming. OK, at this point we have identified a solution to the excessively long code. Take a look at the following implementation code for this step:

// Regardless of 'error handling' and 'Options' passed in, the following code implements the above design
export const withLoading = (fn) = > {
  let loading;
  const showLoading = () = > {
    loading = ElLoading.service()
  }
  const hideLoading = () = > {
    if (loading) {
      loading.close()
    }
  }
  const newFn = (. args) = > {
      showLoading()
      constresult = fn(... args) hideLoading() }return newFn
}
Copy the code

Encapsulate pain point two:Resolve the default parameter transmission and custom parameter transmission

This point is easy:

// Define a default configuration
const defaultOptions = {
  lock: true.text: 'Loading'.background: 'rgba (0, 0, 0, 0.1)'
}
// Add a second parameter to pass in the custom configuration
export const withLoading = (fn, options = {}) = >{...const showLoading = (options) = > {
    loading = ElLoading.service(options)
  }
  / / assign
  const _options = Object.assign(defaultOptions, options)
  const newFn = (. args) = > {
      showLoading(_options)
  }
  return newFn
}
Copy the code

Encapsulate pain point three:Exception handling encapsulates a try catch

Consider the simplest scenario, where fn is passed as a synchronous method and the code can be very simple, all we need to do is the following:

  • Ensure that loading is disabled after a catch Error occurs
  • I’m going to keep throwing the catch Error
export const withLoading = (fn, options = {}) = > {
    const newFn = (. args) = > {
        try {
           letresult showLoading(_options) result = fn(... args) hideLoading()return result
        } catch (err) {
          hideLoading()
          throw err
        }
    }
}
Copy the code

But this is clearly not enough. Because the method passed in May be an asynchronous method, in which case we return a Promise object and turn off loading immediately. Therefore, we need to determine whether the method passed in is asynchronous. The method to determine is as follows:

constresult = fn(... args)// Determine if a Promise is returned
const isPromise = result instanceof Promise
Copy the code

If it is not a Promise, return with the synchronization logic above. If it’s a Promise, then we need to do catch and error handling.

  return result
    .then((res) = > {
      hideLoading()
      return res
    })
    .catch((err) = > {
      hideLoading()
      throw err
    })
Copy the code

Call it a day and see what happens

Write a simple Demo to test the normal and abnormal performance respectively:

<template>
  <div>
    <el-button @click="queryBirds">Access to personnel</el-button>
    <el-button @click="queryCars">Access to the vehicle</el-button>
  </div>
</template>
<script setup>
import { getBirds, getCars } from './mock';
import { withLoading } from './hooks/loading';
import { ElMessage } from 'element-plus';
const queryBirds = async() = > {// Not a single line of code is added
  const birds = await withLoading(getBirds)()
  ElMessage.success(birds.map(t= > t.name).join())
}
const queryCars = async() = > {try {
    // Not a single line of code is added
    await withLoading(getCars)()
  } catch(err) {
    ElMessage.error(err.message)
  }
}
</script>
Copy the code

Perfect!

The source code in

# making source

Github.com/zhangshichu…