catalogue
2, How to customize instructions
1, What is a custom directive
The in-line attributes at the beginning of v-are all instructions. Different instructions can complete or implement different functions. When performing bottom-level operations on ordinary DOM elements, custom instructions will be used. In addition to the core functions, the default built-in instructions (V- model And v-show), Vue also allows you to register custom instructions
Several ways of using instructions:
//An instruction will be instantiated, but the instruction has no parameters `v-xxx` // --Pass value to instruction `v-xxx="value"` // --Pass the string into the instruction, such as ` v-html = "'< p > content < / P >'"` `v-xxx="'string'"` // --Pass parameters (` arg '), such as ` v-bind:class="className"` `v-xxx:arg="value"` // --Use modifier (` modifier ') `v-xxx:arg.modifier="value"`
2, How to customize instructions
Register a user-defined instruction, including global registration and local registration
Global registration is mainly used Vue Register with the direct method
Vue. The first parameter of directive is the name of the instruction (no v-prefix is required), and the second parameter can be object data or an instruction function
// Register a global custom instruction ` v-focus` Vue.directive('focus', { // When the bound element is inserted into the DOM inserted: function (el) { // Focus element el.focus() // A small function that automatically enables the input box to get the focus after the page is loaded } })
Local registration is achieved by setting the directive property in the component options option
directives: { focus: { // Definition of instruction inserted: function (el) { el.focus() // A small function that automatically enables the input box to get the focus after the page is loaded } } }
Then you can use the new "v-focus" property on any element in the template, as follows:
<input v-focus />
Hook function
Custom instructions also have hook functions like components:
bind: called only once, when the instruction is bound to the element for the first time. One time initialization settings can be performed here
Inserted: called when the bound element is inserted into the parent node (only the parent node is guaranteed to exist, but it may not have been inserted into the document)
Update: called when the VNode of the component is updated, but it may occur before its child VNode is updated. The value of the instruction may or may not have changed. However, you can ignore unnecessary template updates by comparing the values before and after the update
componentUpdated: the VNode and its sub VNode of the instruction component are updated after all updates.
unbind: called only once when the instruction is unbound from the element
All hook functions have the following parameters:
el: the element bound by the instruction, which can be used to directly operate DOM
binding: an object containing the following properties:
`name`: Instruction name, excluding v- Prefix. `value`: Binding value of the instruction, for example: v-my-directive="1 + 1" In, the binding value is 2. `oldValue`: The previous value of the instruction binding, only in update and componentUpdated Available in hooks. Available whether the value changes or not. `expression`: An instruction expression in the form of a string. for example v-my-directive="1 + 1" In, the expression is "1 + 1". `arg`: Parameters passed to the instruction, optional. for example v-my-directive:foo In, the parameter is "foo". `modifiers`: An object that contains modifiers. For example: v-my-directive.foo.bar In, the modifier object is { foo: true, bar: true } `vnode`: Vue Compiled virtual node `oldVnode`: Previous virtual node, only in update and componentUpdated Available in hook
Except el, other parameters should be read-only and should not be modified. If you need to share data between hooks, it is recommended to do so through the dataset of the element
for instance:
<div v-demo="{ color: 'white', text: 'hello!' }"></div> <script> Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // "white" console.log(binding.value.text) // "hello!" }) </script>
3, Application scenario
Using custom components can meet some of our daily scenarios. Here are some examples of custom components:
-
Anti shake
-
Lazy loading of pictures
-
One click Copy function
Input box anti shake
In this case, a v-throttle custom instruction is set to implement anti shake
for instance:
// 1. Set v-throttle custom instruction Vue.directive('throttle', { bind: (el, binding) => { let throttleTime = binding.value; // Anti shake time if (!throttleTime) { // If the user does not set the anti shake time, it defaults to 2s throttleTime = 2000; } let cbFun; el.addEventListener('click', event => { if (!cbFun) { // First execution cbFun = setTimeout(() => { cbFun = null; }, throttleTime); } else { event && event.stopImmediatePropagation(); } }, true); }, }); // 2. Set the v-throttle custom instruction for the button label <button @click="sayHello" v-throttle>Submit</button>
Lazy loading of pictures
Set up a v-lazy custom component to complete the lazy loading of pictures
const LazyLoad = { // install method install(Vue,options){ // loading diagram instead of picture let defaultSrc = options.default; Vue.directive('lazy',{ bind(el,binding){ LazyLoad.init(el,binding.value,defaultSrc); }, inserted(el){ // Compatible processing if('InterpObserver' in window){ LazyLoad.observe(el); }else{ LazyLoad.listenerScroll(el); } }, }) }, // initialization init(el,val,def){ // src stores the real src el.setAttribute('src',val); // Set src as loading graph el.setAttribute('src',def); }, // Using InterpObserver to monitor el observe(el){ let io = new InterpObserver(entries => { let realSrc = el.dataset.src; if(entries[0].isIntersecting){ if(realSrc){ el.src = realSrc; el.removeAttribute('src'); } } }); io.observe(el); }, // Listen for scroll events listenerScroll(el){ let handler = LazyLoad.throttle(LazyLoad.load,300); LazyLoad.load(el); window.addEventListener('scroll',() => { handler(el); }); }, // Load real pictures load(el){ let windowHeight = document.documentElement.clientHeight let elTop = el.getBoundingClientRect().top; let elBtm = el.getBoundingClientRect().bottom; let realSrc = el.dataset.src; if(elTop - windowHeight<0&&elBtm > 0){ if(realSrc){ el.src = realSrc; el.removeAttribute('src'); } } }, // throttle throttle(fn,delay){ let timer; let prevTime; return function(...args){ let currTime = Date.now(); let context = this; if(!prevTime) prevTime = currTime; clearTimeout(timer); if(currTime - prevTime > delay){ prevTime = currTime; fn.apply(context,args); clearTimeout(timer); return; } timer = setTimeout(function(){ prevTime = Date.now(); timer = null; fn.apply(context,args); },delay); } } } export default LazyLoad;
One click Copy function
import { Message } from 'ant-design-vue'; const vCopy = { // /* bind Hook function, called when Binding for the first time, can be initialized here el: Acting dom object value: The value passed to the instruction, that is, the value we want to copy */ bind(el, { value }) { el.$value = value; // Use a global attribute to store the value passed in, because this value will be used in other hook functions el.handler = () => { if (!el.$value) { // When the value is empty, the prompt will be given. The prompt here is ant design Vue, and you are free to use it Message.warning('No copy content'); return; } // Dynamically create textarea Tags const textarea = document.createElement('textarea'); // Set the textarea to readonly to prevent the keyboard from being automatically recalled under iOS, and move the textarea out of the visual area at the same time textarea.readOnly = 'readonly'; textarea.style.position = 'absolute'; textarea.style.left = '-9999px'; // Assign the value to copy to the value attribute of the textarea tag textarea.value = el.$value; // Insert textarea into the body document.body.appendChild(textarea); // Select the value and copy it textarea.select(); // textarea.setSelectionRange(0, textarea.value.length); const result = document.execCommand('Copy'); if (result) { Message.success('Copy successful'); } document.body.removeChild(textarea); }; // Binding click events is the so-called one click copy el.addEventListener('click', el.handler); }, // Triggered when the value passed in is updated componentUpdated(el, { value }) { el.$value = value; }, // When an instruction is unbound from an element, the event binding is removed unbind(el) { el.removeEventListener('click', el.handler); }, }; export default vCopy;
Drag
<div ref="a" id="bg" v-drag></div> directives: { drag: { bind() {}, inserted(el) { el.onmousedown = (e) => { let x = e.clientX - el.offsetLeft; let y = e.clientY - el.offsetTop; document.onmousemove = (e) => { let xx = e.clientX - x + "px"; let yy = e.clientY - y + "px"; el.style.left = xx; el.style.top = yy; }; el.onmouseup = (e) => { document.onmousemove = null; }; }; }, }, },