8 very practical Vue custom instructions
- 2021-10-13 06:38:08
- OfStack
This article is included in github github.com/Michael-lzg …
demo Source Address github. com/Michael-lzg …
In Vue, Vue also allows registration of custom instructions in addition to the instructions built in by default for core functions (v-model and v-show). Its value lies in the fact that developers need to operate on ordinary DOM elements in some scenarios.
Vue custom instructions have two ways: global registration and local registration. First, let's look at the way to register global instructions. Register global instructions through Vue. directive (id, [definition]). Then make the Vue. use () call in the entry file.
Batch registration instruction, create new directives/index. js file
import copy from './copy'
import longpress from './longpress'
// Custom instruction
const directives = {
copy,
longpress,
}
export default {
install(Vue) {
Object.keys(directives).forEach((key) => {
Vue.directive(key, directives[key])
})
},
}
Imports and calls in main. js
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
The instruction definition function provides several (optional) hook functions:
bind: Called only once, when the instruction is bound to the element for the first time, it can define an initialization action that is executed once when binding. inserted: Called when the bound element is inserted into the parent node (it can be called if the parent node exists, but does not have to exist in document). update: Called when the template of the bound element is updated, regardless of whether the binding value changes. By comparing the binding values before and after the update. componentUpdated: Called when the template where the bound element is located completes one update cycle. unbind: Called only once, when the instruction is unbound from the element.Here are a few practical Vue custom directives
Copy and paste instruction v-copy Long press instruction v-longpress Input box anti-shake instruction v-debounce Prohibit emoticons and special characters v-emoji Picture lazy loading v-LazyLoad Permission verification instruction v-premission Implementation of page watermarking v-waterMarker Drag instruction v-draggable
v-copy
Requirements: Realize 1-key copy of text content for right mouse button paste.
Thoughts:
Create an textarea tag dynamically, set readOnly properties and move out of the visual area The value to be copied is assigned to the value attribute of the textarea tag and inserted into the body Select the value textarea and copy Remove textarea inserted in body Bind events on the first call and remove events on unbind
const copy = {
bind(el, { value }) {
el.$value = value
el.handler = () => {
if (!el.$value) {
// When the value is empty, give a prompt. Can be based on the project UI Carefully design
console.log(' No copied content ')
return
}
// Dynamic creation textarea Label
const textarea = document.createElement('textarea')
// Set the textarea Set to readonly Prevent iOS Automatically call up the keyboard, and at the same time, set the textarea Move out of the visible area
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
// Will copy Assign the value of the textarea Labeled value Attribute
textarea.value = el.$value
// Will textarea Insert into body Medium
document.body.appendChild(textarea)
// Select the value and copy
textarea.select()
const result = document.execCommand('Copy')
if (result) {
console.log(' Successful replication ') // Can be based on the project UI Carefully design
}
document.body.removeChild(textarea)
}
// Bind the click event, which is called 1 Key copy La
el.addEventListener('click', el.handler)
},
// Triggered when the incoming value is updated
componentUpdated(el, { value }) {
el.$value = value
},
// Remove the event binding when the instruction is unbound from the element
unbind(el) {
el.removeEventListener('click', el.handler)
},
}
export default copy
Use: Add v-copy and copied text to Dom
<template>
<button v-copy="copyText"> Duplicate </button>
</template>
<script> export default {
data() {
return {
copyText: 'a copy directives',
}
},
}
</script>
v-longpress
Requirement: To realize long press, the user needs to press and hold the button for several seconds to trigger the corresponding event
Thoughts:
Create a timer and execute the function in 2 seconds When the user presses the button, the mousedown event is triggered to start the timer; The mouseout event is called when the user releases the button. If the mouseup event is triggered within 2 seconds, the timer is cleared as a normal click event If the timer is not cleared within 2 seconds, it is determined to be a long press, and the associated function can be executed. touchstart and touchend events should be considered on the mobile side
const longpress = {
bind: function (el, binding, vNode) {
if (typeof binding.value !== 'function') {
throw 'callback must be a function'
}
// Defining variables
let pressTimer = null
// Create a timer ( 2 Execute the function in seconds )
let start = (e) => {
if (e.type === 'click' && e.button !== 0) {
return
}
if (pressTimer === null) {
pressTimer = setTimeout(() => {
handler()
}, 2000)
}
}
// Cancel the timer
let cancel = (e) => {
if (pressTimer !== null) {
clearTimeout(pressTimer)
pressTimer = null
}
}
// Running function
const handler = (e) => {
binding.value(e)
}
// Add an event listener
el.addEventListener('mousedown', start)
el.addEventListener('touchstart', start)
// Cancel the timer
el.addEventListener('click', cancel)
el.addEventListener('mouseout', cancel)
el.addEventListener('touchend', cancel)
el.addEventListener('touchcancel', cancel)
},
// Triggered when the incoming value is updated
componentUpdated(el, { value }) {
el.$value = value
},
// Remove the event binding when the instruction is unbound from the element
unbind(el) {
el.removeEventListener('click', el.handler)
},
}
export default longpress
Use: Add v-longpress and callback function to Dom
<template>
<button v-longpress="longpress"> Long press </button>
</template>
<script>
export default {
methods: {
longpress () {
alert(' Long-term instruction takes effect ')
}
}
}
</script>
v-debounce
Background: In the development, some submit and save buttons are sometimes clicked many times in a short time, which will repeatedly request the back-end interface, resulting in data confusion. For example, if you add a submit button for a new form, you will add multiple duplicate data if you click it many times.
Requirements: Prevent the button from being clicked many times in a short time, and use the anti-shake function to limit the specified time to only click once.
Thoughts:
Defines a method with delayed execution, and recalculates the execution time if the method is called again within the delayed time.
Bind the time to the click method.
const debounce = {
inserted: function (el, binding) {
let timer
el.addEventListener('keyup', () => {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
binding.value()
}, 1000)
})
},
}
export default debounce
Use: Add v-debounce and callback function to Dom
<template>
<button v-debounce="debounceClick"> Anti-shake </button>
</template>
<script>
export default {
methods: {
debounceClick () {
console.log(' Trigger only 1 Times ')
}
}
}
</script>
v-emoji
Background: Form input encountered in development often has restrictions on input content, such as not inputting expressions and special characters, only inputting numbers or letters, etc.
Our usual approach is to handle the on-change event on every 1 form.
<template>
<input type="text" v-model="note" @change="vaidateEmoji" />
</template>
<script> export default {
methods: {
vaidateEmoji() {
var reg = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?! ,. ? ! … &$=()-+/*{}[]]|s/g
this.note = this.note.replace(reg, '')
},
},
} </script>
This code is large and difficult to maintain, so we need to customize a command to solve this problem.
Requirements: According to regular expressions, design custom instructions to deal with form input rules. The following is an example of prohibiting the input of expressions and special characters.
let findEle = (parent, type) => {
return parent.tagName.toLowerCase() === type ? parent : parent.querySelector(type)
}
const trigger = (el, type) => {
const e = document.createEvent('HTMLEvents')
e.initEvent(type, true, true)
el.dispatchEvent(e)
}
const emoji = {
bind: function (el, binding, vnode) {
// Regular rules can be customized according to requirements
var regRule = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?! ,. ? ! … &$=()-+/*{}[]]|s/g
let $inp = findEle(el, 'input')
el.$inp = $inp
$inp.handle = function () {
let val = $inp.value
$inp.value = val.replace(regRule, '')
trigger($inp, 'input')
}
$inp.addEventListener('keyup', $inp.handle)
},
unbind: function (el) {
el.$inp.removeEventListener('keyup', el.$inp.handle)
},
}
export default emoji
Use: Add v-emoji to the input box to be verified
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
0
v-LazyLoad
Background: In e-commerce projects, there are often a large number of pictures, such as banner advertisement map, menu navigation map, Meituan and other business list headers. Many pictures and too large pictures often affect the page loading speed and cause bad user experience, so it is imperative to optimize the lazy loading of pictures.
Requirements: Realize a picture lazy loading instruction, and only load the pictures in the visible area of the browser.
Thoughts:
The principle of lazy loading of pictures is mainly realized by the core logic of judging whether the current picture has reached the visual area Get all the pictures Dom, traverse each picture to judge whether the current picture is in the visual area If you arrive, set the src property of the picture, otherwise, the default picture will be displayedLazy loading of pictures can be achieved in two ways, 1 is to bind srcoll events to monitor, and 2 is to use IntersectionObserver to judge whether pictures are in the visible area, but there are browser compatibility problems.
The following encapsulation of a lazy loading instruction is compatible with two methods to judge whether the browser supports IntersectionObserver API. If it supports it, use IntersectionObserver to realize lazy loading, otherwise use srcoll event monitoring + throttling.
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
1
Use, replace the src of the label in the component with v-LazyLoad
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
2
v-permission
Background: In some background management systems, we may need to judge some operation permissions according to the user role. Most of the time, we rudely add v-if/v-show to an element for display and hiding. However, if the judgment conditions are cumbersome and multiple places need to be judged, the code in this way is not only inelegant but also redundant. In view of this situation, we can deal with it through global custom instructions.
Requirements: Customize a permission instruction to show and hide Dom that needs permission judgment.
Thoughts:
Customize 1 permission array Determine whether the user's permission is in this array, and if so, display it; Otherwise, remove Dom
function checkArray(key) {
let arr = ['1', '2', '3', '4']
let index = arr.indexOf(key)
if (index > -1) {
return true // Have authority
} else {
return false // No authority
}
}
const permission = {
inserted: function (el, binding) {
let permission = binding.value // Get to v-permission Value of
if (permission) {
let hasPermission = checkArray(permission)
if (!hasPermission) {
// No permissions Remove Dom Element
el.parentNode && el.parentNode.removeChild(el)
}
}
},
}
export default permission
Use: Assign value to v-permission
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
4
vue-waterMarker
Requirement: Add background watermark to the whole page
Thoughts:
Use canvas features to generate base64 format picture file, set its font size, color, etc. Set it as a background image to achieve the watermarking effect of the page or component
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
5
Use, set the watermark copy, color and font size
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
6
v-draggable
Requirements: Realize a drag instruction, which can drag and drop elements arbitrarily in the visual area of the page.
Thoughts:
Set the element to be dragged to relative positioning, and its parent element to absolute positioning. Record the current left and top values of the target element when the mouse is pressed (onmousedown). When the mouse moves (onmousemove), the change values of the transverse distance and the longitudinal distance of each move are calculated, and the left and top values of the element are changed Drag and drop completed once when mouse is released (onmouseup)
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
7
Use: Add v-draggable to Dom
<template>
<div class="el-dialog" v-draggable></div>
</template>
All instruction source addresses github. com/Michael-lzg …
These are the details of 8 very practical Vue custom instructions. For more information about vue custom instructions, please pay attention to other related articles on this site!