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

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

相关推荐
IT女孩儿1 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡2 小时前
commitlint校验git提交信息
前端
天天进步20152 小时前
Vue+Springboot用Websocket实现协同编辑
vue.js·spring boot·websocket
虾球xz2 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇2 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐3 小时前
前端图像处理(一)
前端
程序猿阿伟3 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒3 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript