小白视角:vue3自定义指令开发,一步步那种, 看不懂打我好吧

2,007 阅读3分钟

注意事项:写法从extend替换成了createApp

阅前须知: vue2 和 vue3 的自定义指令方式有点不一样 vue2 是 extend 去挂载dom元素 vue3 不再支持 extend 了,要用createApp生成实例去挂载 (我也是看文章才知道,大家可以去搜下,然后这个demo我是用TS去写的,后面会是anyScript,因为刚接触TS不太懂语法,然后就直接在这个项目上写来玩了)

不对的地方大家多多体谅哈~小编是小萌新

第一步: 创建loading.vue组件

创建一个.vue 文件,写出你loading的样式,这里我就不写了,大家可以网上找下(毕竟需求不一样)。

第二步: 创建ts文件

创建一个.ts文件,作为一个导出文件。

第三步: 挂载与导出

我们需要在.ts文件引入我们写好的 loading.vue 文件、 createApp方法: 下面展示一些 示例

import Loading from "./loading.vue"
import { createApp } from "vue";

随后我们定义一个导出对象,用来暴露在main中的进行注册,然后方法就可以在里面书写了。

const loadingObj = {
}
export default loadingObj;

注意: 暴露出来的钩子函数不太一样了

vue2: bind,inserted,update,componentUpdated,unbind。 vue3: created,mounted,updated,unmounted

createApp的作用: 创建app实例,这个时候是处于游荡阶段,等待挂载。 这个时候的app实例属于Vue的一个准备阶段,为后面的mount等操作准备好了所需要使用到的函数。

在这里插入图片描述

mount是比较核心,和vue2差不多,反正一句话就是进行渲染该组件

在这里插入图片描述

接下来写下代码~(AnyScript了解一下)

  // 这段代码可以放在mounted里面挂载在el身上,方便操作。但是我试过放在顶部也是可以用的
  const app = createApp(Loading);
  const instance:any = app.mount(document.createElement("div")); // 你也可以挂载在全局的app下,反正就给个dom它

然后和vue2的写法差不多,就是钩子有点变化而已:

  mounted(el:any, bind:any) {
    // 这段代码我放在mounted里挂载在el身上,传参的时候可以方便调用
    const app = createApp(Loading);
    const instance:any = app.mount(document.createElement("div"));
    console.log("instance",instance);
    el.instance = instance;
    // 这里是我组件里面的方法,调用这个去更新值,也可以直接改data的值,见仁见智哈~安全而已
    el.instance.setLoading("我是努力加载中");
    if(bind.value) {  // v-loading="true"时候调用添加在组件
      appndChild(el)
    }
  },

接下来是更新的时候触发的事件:

  updated(el:any, bind:any){
    if(bind.value !== bind.oldValue){
      bind.value? appndChild(el): remove(el);
    }
  }

公共方法:

function appndChild(el:any){
  el.appendChild(el.instance.$el);
}
function remove(el:any){
  el.removeChild(el.instance.$el);
}

然后在main.ts中去注册就行。

import { createApp } from 'vue'
import App from './App.vue'
import direactive from "../src/hooks/direactive"

const app = createApp(App);

app.directive("loading",direactive).mount('#app')

接下来谈谈题外话,自定义指令的注册方式:

第一种:和以前vue2一样,通过暴露出一个对象,里面有install方法,然后通过vue.use去全局注册,代码如下:

import { App } from 'vue'
export default {
    install(vue){
      app.directive("loading",{
        created(){
        },
        mounted(){
        }
      })
    }
}
**然后在main.ts注册就行**
import loading  from './loading'
let app = createApp(App)
app.use(loading)

第二种就是我上面写的方式,在app实例下,通过调用app.directive("loading",direactive)去使用,这种写法我感觉就相当于局部创建的一样,不过这个局部是全局的实例而已。(个人理解,不对别打我哈~)

import { createApp } from 'vue'
import App from './App.vue'
import direactive from "../src/hooks/direactive"

const app = createApp(App);

app.directive("loading",direactive).mount('#app')

下面打印下挂载后的instance实例,方便和我一样懒的小伙伴

const instance:any = app.mount(document.createElement("div")); 在这里插入图片描述

挂载后的dom对象结构,你可以直接去改data的值控制显示的样式~ 在这里插入图片描述

我贴下全部的代码:

import Loading from "./loading.vue";
import { createApp } from "vue";

const LoadingObj = {
  mounted(el:any, bind:any) {
    const app = createApp(Loading);
    const instance:any = app.mount(document.createElement("div"));
    el.instance = instance;
    el.instance.setLoading("我是努力加载中");
    if(bind.value) {
      appndChild(el)
    }
  },
  updated(el:any, bind:any){
    if(bind.value !== bind.oldValue){
      bind.value? appndChild(el): remove(el);
    }
  }
 
}
function appndChild(el:any){
  el.appendChild(el.instance.$el);
}
function remove(el:any){
  el.removeChild(el.instance.$el);
}
export default LoadingObj;

最后如果有不对的地方,各位大佬请见谅并指出,这是弟弟的个人理解而已~小萌新一个,一起加油。