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组件本质的理解。

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

相关推荐
JIngJaneIL1 天前
助农惠农服务平台|助农服务系统|基于SprinBoot+vue的助农服务系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·毕设·助农惠农服务平台
云外天ノ☼1 天前
待办事项全栈实现:Vue3 + Node.js (Koa) + MySQL深度整合,构建生产级任务管理系统的技术实践
前端·数据库·vue.js·mysql·vue3·koa·jwt认证
gihigo19981 天前
使用JavaScript和Node.js构建简单的RESTful API
javascript·node.js·restful
一位搞嵌入式的 genius1 天前
前端实战开发(三):Vue+Pinia中三大核心问题解决方案!!!
前端·javascript·vue.js·前端实战
塞纳河畔的歌1 天前
保姆级教程 | 麒麟系统安装Edge浏览器
前端·edge
前端.火鸡1 天前
Vue 3.5 新API解析:响应式革命、SSR黑科技与开发体验飞跃
javascript·vue.js·科技
多睡觉觉1 天前
数据字典:从"猜谜游戏"到"优雅编程"的奇幻之旅
前端
嗝屁小孩纸1 天前
开发集成热门小游戏(vue+js)
前端·javascript·vue.js
赛博切图仔1 天前
深入理解 package.json:前端项目的 “身份证“
前端·javascript
UIUV1 天前
JavaScript 学习笔记:深入理解 map() 方法与面向对象特性
前端·javascript·代码规范