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

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

相关推荐
熊的猫几秒前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn7 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
四喜花露水40 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust1 小时前
css:基础
前端·css
帅帅哥的兜兜1 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
工业甲酰苯胺1 小时前
C# 单例模式的多种实现
javascript·单例模式·c#
yi碗汤园2 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称2 小时前
购物车-多元素组合动画css
前端·css