directive的官方文档
Vue.directive( id, [definition] )
参数:
{string} id
{Function | Object} [definition]
用法:
注册或获取全局指令。
// 注册 Vue.directive('my-directive', { bind: function () {}, inserted: function () {}, update: function () {}, componentUpdated: function () {}, unbind: function () {} }) // 注册 (指令函数) Vue.directive('my-directive', function () { // 这里将会被 `bind` 和 `update` 调用 }) // getter,返回已注册的指令 var myDirective = Vue.directive('my-directive')
- 案例:
<html>
<head>
<title>directive 用法</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="root">
<div v-loading="isLoading">{{data}}</div>
<button @click="update">更新</button>
</div>
<script>
Vue.directive('loading', {
//当我们的isLoading发生变化的时候会触发update
//1. 传入的是object
update(el, binding, vnode) {
// 会触发两次
console.log(el, binding, vnode)
/*
第一次调用:
<div></div>
{name: "loading", rawName: "v-loading", value: true, expression: "isLoading", modifiers: {…},name: "loading",oldArg: undefined,oldValue: false,rawName: "v-loading",value: true, …}
VNode {tag: "div", data: {…}, children: Array(1), text: undefined, elm: div, …}
第二次调用:
<div>用户数据 </div>
{name: "loading", rawName: "v-loading", value: false, expression: "isLoading", modifiers: {…},name: "loading",oldArg: undefined,oldValue: true,rawName: "v-loading",value: false, …}
VNode {tag: "div", data: {…}, children: Array(1), text: undefined, elm: div, …}
*/
if (binding.value) {
// 非侵入的创建一个遮罩,可以封装成固定的静态组件
const div = document.createElement('div')
div.innerText = '加载中...'
div.setAttribute('id', 'loading')
div.style.position = 'absolute'
div.style.left = 0
div.style.top = 0
div.style.width = '100%'
div.style.height = '100%'
div.style.display = 'flex'
div.style.justifyContent = 'center'
div.style.alignItems = 'center'
div.style.color = 'white'
div.style.background = 'rgba(0, 0, 0, .7)'
document.body.append(div)
} else {
document.body.removeChild(document.getElementById('loading'))
}
},
})
/*
2.传入的是function
Vue.directive('loading', {
update(el, binding, vnode) {
console.log(el, binding, vnode)
if (binding.value) {
const div = document.createElement('div')
div.innerText = '加载中...'
div.setAttribute('id', 'loading')
div.style.position = 'absolute'
div.style.left = 0
div.style.top = 0
div.style.width = '100%'
div.style.height = '100%'
div.style.display = 'flex'
div.style.justifyContent = 'center'
div.style.alignItems = 'center'
div.style.color = 'white'
div.style.background = 'rgba(0, 0, 0, .7)'
document.body.append(div)
} else {
// 因为是function时会直接绑定到bind和update两个生命周期上,当时bind时,我们的loading还没有加入当页面当中,所以会找不到这个dom节点
const div = document.getElementById('loading')
div && document.body.removeChild(div)
}
},
})
*/
new Vue({
el: '#root',
data() {
return {
isLoading: false,
data: '',
}
},
methods: {
update() {
this.isLoading = true
setTimeout(() => {
this.data = '用户数据'
// 获取请求时我们可以使用try catch方法防止未知错误
this.isLoading = false
}, 3000)
},
},
})
</script>
</body>
</html>
- directive的源码
//vue.js:5210
function initAssetRegisters(Vue) {
/**
* Create asset registration methods.
*/
ASSET_TYPES.forEach(function (type) {
//type => directive
Vue[type] = function (id, definition) {
//id => "loading",definition = >{update:f}
if (!definition) {
return this.options[type + 's'][id]
} else {
/* istanbul ignore if */
if (type === 'component') {
validateComponentName(id)
}
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
//我们的definition是object
definition = { bind: definition, update: definition } //如果是function,直接添加到bind和update这两个生命周期上
}
this.options[type + 's'][id] = definition //this.options.directives.loading = f
/*
=>
options:{
components: {KeepAlive: {…}, Transition: {…}, TransitionGroup: {…}}
directives:{
loading: {update: ƒ}
model: {inserted: ƒ, componentUpdated: ƒ}
show: {bind: ƒ, update: ƒ, unbind: ƒ}
}
filters: {}
_base: ƒ Vue(options)
}
*/
return definition
}
}
})
}
网友评论