Vue:对函数式调用组件还犯迷糊?

写在最前

看官们好,我叫JetTsang,之前都是在掘金潜水来着,现在偶尔做一些内容输出吧。

引出

在vue2当中,全局组件比如弹窗组件如何封装呢?

有些小伙伴可能就简单的封装一个,这种功能也是很完备的 缺点:需要引入额外响应式变量,方法去控制 优点:像el-dialog一样,适合需要定制性更大的场景

那么对于定制性要求更小的场景,因此适合展示较为简单的内容,ElementUI是推荐: messageBox组件,

看下它的用法:

这种类似于原生alert弹窗的,就是函数式调用,那么如何封装一个这样的组件呢? 下面会一一道来

如何封装?

为什么能this.$alert?

这个官方给出了答案

就是利用原型链

javascript 复制代码
Vue.prototype.$alert = function(message, title, options){
    // 这里写逻辑
}

$alert当中怎么将弹窗组件创建出来?

看一下脚手架的工程文件,main.js

javascript 复制代码
import Vue from "vue"
import App from "./App.vue"

const vm = new Vue({
    render: (h) => h(App),
});

vm.$mount("#app")

这里的过程其实就是,

  • 创建Vue实例(new Vue)
  • 创建实例的时候,会调用render方法生成vNode(虚拟节点),其中的参数h函数 是一个用来创建 vNode 的辅助函数。能将引入的APP组件,变成vNode
  • 最后实例挂载($mount)到#app这个真实dom当中

其实$alert里面做的事情无非就是这样嘛,将我们的.vue组件,挂载到真实dom下

可以看到el的MessageBox 是挂在body下的

那么来实现一个自己的Modal

回到之前开头实现Modal,分别3个属性,2个自定义事件

内部方法构成:

前面提到了,只需要构造一个用于创建和挂载的函数,然后挂载到Vue.prototype即可全局调用

现在的目标就是构造这样一个函数

新建一个index.js,

javascript 复制代码
import Vue form 'vue'
import Modal from "./Modal.vue"
export default function $modal (){
        const vm = new Vue({
            render:(h) => h(Modal)
        })
        // 创建游离节点
        const div = document.createElement('div')
        // 放到body上
        document.body.appendChild(div)
        // 将vm挂载到这个节点上
        vm.$mount(div)
}

打印一下这个vm

可以看到$el这一项是一个注释节点,因为我们设计的是v-if,此时没命中,因此会创建一个注释节点。

此时我们需要将showModal等参数传进去,该怎么办呢?

h函数就派上用场了,它的第2个参数可以传配置项(就是.vue里面的配置项)进去

javascript 复制代码
h(Modal,{props:{showModal:true}})

这样子就有渲染了Modal了,但这个h函数的第2个参数只能传入包含模板相关属性(例如 propsclassstyle 等),如果要传入方法的话,只能另寻他法了

救星:VueExtend

所幸Vue提供了Vue.extend

从官网可以看到,extend需要传入一个配置项,但我们Modal.vue组件已经写好了呀,总不能重新写一份到template,或者写一个render函数吧?

知道你很急,但你先别急,此时你就要知道.vue文件,被引入之后是什么?

.vue组件究竟是啥???

打印一下Modal

这不就是一个对象嘛,options配置项

回忆一下.vue当中,是怎么写代码的

同时vue的编译器帮我们把<template>标签里的内容编译成了render函数

改造

所以就可以利用vue.extend进行改造啦

javascript 复制代码
import Vue form 'vue'
import Modal from "./Modal.vue"
export default function $modal (){
    const ModalCtor = Vue.extend(Modal)

    const modalVM = new ModalCtor({
        propsData: {
            showModal: true,
            title: "JetTsang's Title",
            text:"这是text"
        },
        data() {
            return { }
        },
        mounted(){
            console.log('mounted了')
        },
        methods:{
            传入的方法(){
                console.log('Hello JetTsang')
            }
        }
    })
    const div = document.createElement('div')
    document.body.appendChild(div)
    modalVM.$mount(div)
}

打印一下这个modalVM,这就是1个vue组件了啊,可以通过写配置项来传入方法和属性了.

组件销毁和卸载

可以借助下面的流程

perl 复制代码
// `$destroy()` 方法会触发 Vue 实例的生命周期钩子函数 `beforeDestroy` 和 `destroyed`
modalVM.$destroy()
// 真实dom的移除,调用HTMLElement的原生方法remove
modalVM.$el.remove()

最后 $modal(message, title, options)的参数设计,相信难不倒各位

promise调用的实现

这里是有promise的调用形式啊

其实就是在index.js暴露的$modal函数当中返回一个promise嘛,我们直接用promise包装一下即可:

javascript 复制代码
import Vue form 'vue'
import Modal from "./Modal.vue"
export default function $modal (){
    const ModalCtor = Vue.extend(Modal)
    // 返回1个promise实例
    return new Promise((resolve,reject)=>{
        const modalVM = new ModalCtor({
            methods:{
                // 确认
                _confirm(){
                    // 在这里调用
                    resolve()
                    console.log('Hello JetTsang')
                }
            }
        })
        const div = document.createElement('div')
        document.body.appendChild(div)
        modalVM.$mount(div)
    })
    
}

当然这里面方法也是多种多样,相信诸君一定比我想的好。

总结

这种函数式全局组件的封装,比较考验你对vue组件本质的理解。

如果觉得本文对你有帮助,麻烦点一下赞👍

相关推荐
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60619 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment10 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端
爱敲代码的小鱼10 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax