VUE自定义指令深度刨析

developing 自定义指令

<template>
    <transition name="u-loading-fade">
        <div class="developing">
            {{ text }}
        </div>
    </transition>
</template>

<script>
export default {
    data() {
        return {
            text: ''
        }
    }
}
</script>

<style lang="scss" scoped>
.developing {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-size: 60px;
    color: #cccccc8c;
    cursor: default;
    background: rgba(0, 0, 0, 0.5);
}
</style>

import Vue from 'vue'
import DevelopingComponent from './developing.vue'
const DevelopingConstructor = Vue.extend(DevelopingComponent)
export default () => {
    Vue.directive('developing', function(el, binding) {
        if (el.getElementsByClassName('developing').length === 0) {
            const instance = new DevelopingConstructor({
                el: document.createElement('div'),
                data: {}
            })
            Vue.nextTick(() => {
                console.log(instance) // VueComponent实例化参数
                el.appendChild(instance.$el)
                el.instance = instance
                el.style.setProperty('position', 'relative', 'important')
                el.instance.$el.style.setProperty('position', 'absolute', 'important')
                el.instance.text = binding.value
            })
        }
    })
}

src/directive/index.js

import Vue from 'vue'
import developing from './developing'
Vue.directive('developing', developing) // 暂未接入

src/main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

import './directive' // 全局指令注册

Vue.prototype.$mapView = {
    map: {},
    map1: {},
    map2: {}
}

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')

指令钩子函数说明

具体可以查看https://cn.vuejs.org/v2/guide/custom-directive.html,这里不累赘。

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

我们会在稍后讨论渲染函数时介绍更多 VNodes 的细节。

componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

unbind:只调用一次,指令与元素解绑时调用。

接下来我们来看一下钩子函数的参数 (即 el、binding、vnode 和 oldVnode)。

Vue.extend 构造器

构造器简单例子

// 创建构造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')

为什么使用 extend

在 vue 项目中,我们有了初始化的根实例后,所有页面基本上都是通过 router 来管理,组件也是通过 import 来进行局部注册,所以组件的创建我们不需要去关注,相比 extend 要更省心一点点。但是这样做会有几个缺点:

  1. 组件模板都是事先定义好的,如果我要从接口动态渲染组件怎么办?
  2. 所有内容都是在 #app 下渲染,注册组件都是在当前位置渲染。如果我要实现一个类似于 window.alert() 提示组件要求像调用
    JS 函数一样调用它,该怎么办?

这时候,Vue.extend + vm.$mount 组合就派上用场了。

import Vue from 'vue'

const testComponent = Vue.extend({
  template: '<div>{{ text }}</div>',
  data: function () {
    return {
      text: 'extend test'
    }
  }
})

也可以通过以下这种方式

import DevelopingComponent from './developing.vue' // 具体的vue组件
const DevelopingConstructor = Vue.extend(DevelopingComponent)

然后我们将它手动渲染:

const extendComponent = new testComponent().$mount()

我们可以通过 $el 属性来访问 extendComponent 组件实例:

document.body.appendChild(extendComponent.$el)

VueComponent实例化

import Vue from 'vue'
import DevelopingComponent from './developing.vue'
const DevelopingConstructor = Vue.extend(DevelopingComponent)
export default () => {
    Vue.directive('developing', function(el, binding) {
        if (el.getElementsByClassName('developing').length === 0) {
            const instance = new DevelopingConstructor({
                el: document.createElement('div'),
                data: {}
            })
            Vue.nextTick(() => {
                console.log(instance) // VueComponent实例化参数
                el.appendChild(instance.$el)
                el.instance = instance
                el.style.setProperty('position', 'relative', 'important')
                el.instance.$el.style.setProperty('position', 'absolute', 'important')
                el.instance.text = binding.value
            })
        }
    })
}

通过下图可以看到instance 其实就是一个vue组件,具体使用方法可以把instance 等同于组件中的this一样操作
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GY程序源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值