preface
In recent projects, there are often problems caused by users’ multiple clicks, and the use of anti-shake/throttling is quite frequent. Therefore, WE want to achieve this through the way of vUE custom instruction. If you need to use anti-shake in the back, just use the command.
The original code
<button @click="sayHello">submit</button>
Copy the code
sayHello() {
console.log('Hello! ')}Copy the code
What I want to achieve:
<button v-throttle="200" @click="sayHello">submit</button>
Copy the code
With this setting, the submit button can be executed only once for multiple clicks in 200ms and as soon as it is clicked. If you do not set time (200), the system runs only once within 2000ms by default.
Anti – shake/throttling differences and options
<1> Throttling means that the JS method only runs once in a certain period of time. For example, the human eye blinks once in a certain period of time. This is the function. <2> Anti – shake refers to the case of frequent triggering, only enough idle time, to execute the code once. Take a bus in life, for example, is a certain period of time, if someone has to swipe the card to get on the bus, the driver will not drive. A driver only drives when someone else’s card is gone.
(1) Differences In my opinion, their differences lie in the application scenarios, for example, as follows:
[Effect after shaking] : 0.8s after the real send searchAPI;
[Throttling effect] : at 0.2s, the searchAPI interface is triggered immediately when someone clicks, and within x seconds, the user clicks are invalid.
Stole a GIF from the InternetVUE anti – shake and throttling the best solution – functional components), the feeling looks clearer:(2) Choice
On my side, I need to respond immediately when the user clicks on it. The clicks in the next few seconds are invalid because of throttling effect, so I choose throttling.
How do I create custom directives
From the Vue official website, the custom instruction tutorial (poke here can see the details), find the following two points for me to use:
(1) Custom directive hook functions: BIND, Inserted, Update, componentUpdated, unbind
I use bind, which only needs to be initialized once.
(2) Hook function parameters
El: DOM manipulation can be done directly (for example, el.addeventListener, el.onclick).
Binding: The directive binding value can be obtained by value.
Consider: How can I add a listening click event without interfering with the original click event
If there are more than one handler for the onclick event, the latter overrides the former. AddEventListener Registers multiple listeners for an event without overwriting it.
Use addEventListener of course (IE will use attachEvent, however I only need to support Chrome in my project)
The first option
Implementation approach
How do I control whether the sayHello() method executes? The first thing THAT comes to mind is to use a variable called isDisableClick to control the sayHello() method by registering the click event to store the variable isDisableClick in the DOM.
Define anti-shake instructions:
Vue.directive('throttle', {
bind: function (el, binding) {
let throttleTime = binding.value // Throttle time
if(! throttleTime) {// If the user does not set the throttling time, the default is 2s
throttleTime = 2000
}
let cbFun
el.addEventListener('click'.() = > {
el.isDisableClick = true
if(! cbFun) { cbFun =setTimeout(() = > {
el.isDisableClick = false
cbFun = null
}, throttleTime)
}
}, true)}})Copy the code
Use instructions:
<button @click="sayHello" ref="target" v-throttle>submit</button>
Copy the code
sayHello() {
if (!this.$refs.target.isDisableClick) {
console.log('Hello! ')}}Copy the code
Question:
Use to write redundant code, feel the use of unpleasant, discard!
The second option (seen online)
Implementation approach
Prevent the onclick event from firing with the disabled attribute
Define anti-shake instructions:
Vue.directive('throttle', {
bind: function (el, binding) {
let throttleTime = binding.value // Throttle time
if(! throttleTime) {// If the user does not set the throttling time, the default is 2s
throttleTime = 2000
}
let cbFun
el.addEventListener('click'.() = > {
if(! el.disabled) { el.disabled =true
cbFun = setTimeout(() = > {
el.disabled = false
cbFun = null
}, throttleTime)
}
}, true)}})Copy the code
Use instructions:
<button @click="sayHello" v-throttle>submit</button>
Copy the code
sayHello() {
console.log('Hello! ')}Copy the code
Question 1:
For buttons, you can use the Disabled attribute to keep them from firing, but some buttons are implemented with div/span, etc. The disabled attribute does not prevent div onclick events.
Solution to problem 1:
Set style pointer-events: None to block div/span onclick events.
Question 2:
Pointer-events: None makes the element entities “dashed”. For example, a button element with pointer-events: None applied, then the button we see on the page is just an illusory shadow, which you can interpret as a mirage, the body of a ghost. When we touch it with our hands we can easily pass through it without feeling anything.
Excerpt from Zhang XinxuCSS3 pointer-events: None Example and extension
Since pointer-events: None means that the element no longer exists, will a click in this case pass through to its outer layer?
If you set pointer-events: None, clicking on the child node is invalid, but clicking on its parent node is equivalent to clicking on its parent node.
Third option
Define anti-shake instructions:
Vue.directive('throttle', {
bind: (el, binding) = > {
let throttleTime = binding.value; // Anti-shake time
if(! throttleTime) {// If you do not set the anti - shake time, the default value is 2s
throttleTime = 2000;
}
let cbFun;
el.addEventListener('click'.event= > {
if(! cbFun) {// This is the first execution
cbFun = setTimeout(() = > {
cbFun = null;
}, throttleTime);
} else{ event && event.stopImmediatePropagation(); }},true); }});Copy the code
Use instructions:
<button @click="sayHello" v-throttle>submit</button>
Copy the code
sayHello() {
console.log('Hello! ')}Copy the code
PS: a small white front, welcome to leave a message error, thank you ~