Handwritten vUE custom directive (Directive) V-loading, project combat
Goal:
- Used in vUE project tags
v-loading="true"
As shown by using v-loading=”true” in Element-UI.- After learning it, you can directly copy it to your project for actual combat. V-loading will definitely be used in the VUE project at work, which is super convenient to introduce global use at a time
Here I do two laoding effects:
- Full screen loading effect, used when entering the page to use loaidng
- Partial load effect, load effect when the user paginates or loads part of the content
Display effect:
Full screen loading:<div v-loading="true"></div>
Local loading:<div v-load="true"></div>
The directory structure
Loading 5 files was created, copied into the loading file, and then used in main.js. Can't work can leave a message | - SRC | -- App. Vue | -- main. Js / / need to use | - components | | -- the HelloWorld. Vue | - directive / / need to use | | - loading . | | - index js | | - load. The local load js / / | | - load. The vue / / local load | | -- loading. Js / / global loading | | - loading. The vue / / Global loadingCopy the code
1. Create a file
Js; load.js; load.vue; load.js; load.vue; load.vue; load.vue With vue. directive, you can v-load pages with custom directives
loading/index.js
import load from './load';
import loading from './loading';
export default {
install(Vue) {
Vue.directive("load", load), / / partial load
Vue.directive("loading", loading) / / global loading}}Copy the code
loading/loading.vue
Is a component used to insert into the target element of a custom directive, where you can write some loading styles
// directive/loading/loading.vue
<template>
<div v-show="visible" class="loading-wrap">
<div class="loading-box">
<div class="loading-add"></div>
<div class="loading-txt">Global loading...</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
visible: false}; }};</script>
<style scoped>
.loading-wrap {
position: absolute;
left: 0 ! important;
right: 0 ! important;
top: 0 ! important;
bottom: 0 ! important;
width: 100vw ! important;
height: 100vh ! important;
background: rgba(0.0.0.0.7);
white-space: nowrap;
}
.loading-box {
user-select: none;
font-size: 16px;
white-space: nowrap;
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
justify-content: center;
}
.loading-add {
width: 16px;
height: 4px;
background-color: #eee;
display: inline-block;
margin-right: 4px;
position: relative;
animation: add 1s 0s linear infinite forwards;
border-radius: 4px;
}
.loading-add::after {
content: "";
display: inline-block;
width: 16px;
height: 4px;
background-color: #eee;
position: absolute;
left: 50%;
top: 50%;
border-radius: 4px;
transform: translate(-50%, -50%) rotateZ(90deg);
}
@keyframes add {
0% {
transform: rotateZ(0);
}
100% {
transform: rotateZ(360deg); }}.loading-txt {
color: #eee;
animation: fontColor 3s 0s linear infinite reverse;
display: inline-block;
}
@keyframes fontColor {
0% {
color: rgba(238.238.238.0.85);
}
25% {
color: rgba(135.207.235.0.85);
}
50% {
color: rgba(255.0.0.0.85);
}
75% {
color: rgba(51.51.51.0.85);
}
100% {
color: rgba(255.255.0.0.85); }}</style>
Copy the code
loading/loading.js
// directive/loading/loading.js
import Vue from 'vue'
import Loading from './loading.vue'
const Mask = Vue.extend(Loading)
const toggleLoading = (el, binding) = > {
if (binding.value) {
Vue.nextTick(() = > {
// Controls the loading component display
el.instance.visible = true
// Insert to the target element
insertDom(el, el, binding)
})
} else {
el.instance.visible = false}}const insertDom = (parent, el) = > {
parent.appendChild(el.mask)
}
export default {
bind: function (el, binding, vnode) {
const mask = new Mask({
el: document.createElement('div'),
data() { }
})
el.instance = mask
el.mask = mask.$el
el.maskStyle = {}
binding.value && toggleLoading(el, binding)
},
update: function (el, binding) {
if(binding.oldValue ! == binding.value) { toggleLoading(el, binding) } },unbind: function (el, binding) {
el.instance && el.instance.$destroy()
}
}
Copy the code
loading/load.js
// directive/loading/load.js
import Vue from 'vue';
import Load from './load.vue';
const Mask = Vue.extend(Load);
const toggleLoading = (el, binding) = > {
if (binding.value) {
Vue.nextTick(() = > {
el.instance.visible = true// Controls the loading component display
insertDom(el, el, binding)// Insert to the target element})}else {
el.instance.visible = false}}const insertDom = (parent, el) = > {
parent.appendChild(el.mask)
}
export default {
// bind(){} when the instruction is bound
bind: function (el, binding, vnode) {
const mask = new Mask({
el: document.createElement('div'),
data() { }
})
el.instance = mask
el.mask = mask.$el
el.maskStyle = {}
binding.value && toggleLoading(el, binding)
},
// update(){} This function is triggered when data is updated
update: function (el, binding) {
if(binding.oldValue ! == binding.value) { toggleLoading(el, binding) } },// unbind(){} triggers this function when it is unbound
unbind: function (el, binding) {
el.instance && el.instance.$destroy()
}
}
Copy the code
loading/load.vue
// directive/loading/load.vue
<template>
<div v-show="visible" class="load-wrap">
<div class="loading-box">
<div class="loading-add"></div>
<div class="loading-txt">Loading in...</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
visible: false}; }};</script>
<style scoped>
.load-wrap {
white-space: nowrap;
}
.loading-box {
user-select: none;
display: flex;
align-items: center;
justify-content: center;
}
.loading-add {
width: 16px;
height: 4px;
background-color: #eee;
display: inline-block;
margin-right: 4px;
position: relative;
animation: add 1s 0s linear infinite reverse;
border-radius: 4px;
}
.loading-add::after {
content: "";
display: inline-block;
width: 16px;
height: 4px;
background-color: #eee;
position: absolute;
left: 50%;
top: 50%;
border-radius: 4px;
transform: translate(-50%, -50%) rotateZ(90deg);
}
@keyframes add {
0% {
transform: rotateZ(0);
}
100% {
transform: rotateZ(-360deg); }}.loading-txt {
color: #eee;
display: inline-block;
font-size: 16px;
animation: fontColor 3s 0s linear infinite reverse forwards;
}
@keyframes fontColor {
0% {
color: rgba(238.238.238.0.85);
}
25% {
color: rgba(135.207.235.0.85);
}
50% {
color: rgba(255.0.0.0.85);
}
75% {
color: rgba(51.51.51.0.85);
}
100% {
color: rgba(255.255.0.0.85); }}</style>
Copy the code
- Vue.extend takes arguments and returns a constructor. New This constructor can return a component instance.
- When we new Mask(), we mount the component instance to a div that has not yet been mounted to the page. Print it out.
- Then catch the mask instance with a variable el.instance = mask
- The toggleLoading method controls whether the visible variable in loading. Vue is displayed. And if value is true, it is inserted into the target element
Function attributes
- Bind: Called only once, the first time a directive is bound to an element. This is where you can perform one-time initialization Settings
- Inserted: Called when the bound element is inserted into the parent node
- Update: called when the VNode of the component is updated.
- ComponentUpdated: Invoked when the VNode of the component where the directive resides and its child VNodes are all updated
- Unbind: Called only once, when an instruction is unbound from an element.
Function parameters
- El: The element bound by the directive that can be used to manipulate the DOM directly.
- Binding: Contains event information
- Vnode: virtual node generated by Vue compilation.
- OldNode: Last virtual node, available only in update and componentUpdated hooks.
Binding contains:
- Name: indicates the command name
- Value: binding value Example:
v-my-directive="1 + 1"
, the binding value is 2. - OldValue: indicates the value before binding. Only in the
update
和componentUpdated
Hooks are available. Available regardless of whether the value changes. - Expression: command expression in the form of a string. For example,
v-my-directive="1 + 1"
In, the expression is “1 + 1”. - Arg Is an optional parameter passed to the instruction. For example,
v-my-directive:foo
, the parameter is “foo”. - Modifiers: An object that contains modifiers. Such as:
v-my-directive.foo.bar
, the modifier object is{ foo: true, bar: true }
.
Case use teaching:
According to the directory structure above, the corresponding file code copy into, can be used
src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// Import loading (including global loading and local loading)
import loading from './directive/loading'
Vue.use(loading);
Vue.config.productionTip = false
new Vue({
router,
store,
render: h= > h(App)
}).$mount('#app')
Copy the code
src/components/HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<! -- Global loading true -- display false -- hide -->
<div v-loading="true"> </div>
<! -- local load true -- display false -- hide -->
<div v-load="false"> </div>
</div>
</template>
<script>
export default {
name: "HelloWorld".props: {
msg: String,}};</script>
<style scoped></style>
Copy the code
Global loading: