注意事项:写法从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;