likes
comments
collection
share

基于单例模式下实现的vue全局组件

作者站长头像
站长
· 阅读数 14

前言

前段时间,公司产品提了一个需求,希望可以有一个图片查看器,不是蒙层形式,支持边看图片边操作其它,并支持拖动。当然,具体的业务需求比这复杂的多,基于以上功能放弃了使用elment-ui的<el-image>,而是从无到有实现一个图片查看器。然而,本文不是讲如何实现图片查看器,而是如何实现一个全局的组件,像消息组件那样方便调用。

实现一个简单的图片查看组件

<template>
    <span class="box" v-if="visible">
        <img :src="url" alt="加载失败" />
    </span>
</template>

<script>
export default {
    name: "viewer",
    data() {
        return {
            visible: false,
            url: "",
        };
    },
};
</script>

<style scoped>
.box {
    padding: 10px;
    background: pink;
    border-radius: 4px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
</style>

基于Vue.extend()构造出vue子类

Vue.extend(options)用法:使用基础Vue构造器,创建一个“子类”。参数是一个包含组件选项的对象。

注意:data选项是特例,在Vue.extend()中它必须是函数

import Vue from "vue";
import Message from "./Message.vue";

const Component = Vue.extend(Message);

let instance = null;

function MessageBox(options) {
    // 单例模式,先判断实例是否存在,保证页面上只存在一个实例组件
    if (!instance) {
        instance = new Component({
            el: document.createElement("div"),
            data() {
                return options;
            }
        });
        document.body.appendChild(instance.$el);
        // 上一步刚挂载dom,因此使用nextick确保dom已更新
        Vue.nextTick(() => {
            instance.visible = true;
        });
    } else {
        // 存在实例,则合并options,更新视图
        instance.visible = true;
        Object.assign(instance, options);
    }
}

// 提供close方法,方便直接调用
MessageBox.close = () => {
    if (instance) {
        instance.visible = false;
    }
};

export default {
    // 提供install方法,便于Vue.use()注册。将方法挂载在Vue原型上,方便全局使用。
    install() {
        Vue.prototype.$message = MessageBox;
    }
};

Vue.use()注册

main.js中:

import Vue from "vue";
import App from "./App.vue";
import MessageBox from "./components/index.js";

// 注册组件
Vue.use(MessageBox);
Vue.config.productionTip = false;

new Vue({
    render: (h) => h(App)
}).$mount("#app");

让我们来写个页面调用看看,是否可行

这里借助了一个生成随机图片的接口https://picsum.photos/200/200?random=1,来测试图片的切换效果。

<template>
    <div id="app">
        <button @click="click(1)">图片1</button>
        <button @click="click(2)">图片2</button>
        <button @click="click(3)">图片3</button>
        <button @click="click(4)">图片4</button>
        <button @click="close">关闭</button>
    </div>
</template>

<script>
export default {
    name: "App",
    methods: {
        click(key) {
            this.$message({
                text: `图片${key}`,
                url: `https://picsum.photos/200/200?random=${key}`,
            });
        },
        close() {
            this.$message.close();
        },
    },
};
</script>

效果图

来回切换图片,无问题,关闭也无问题。

文本代码皆在codesandbox中实现的,想看效果的:codesandbox.io/s/brave-vil…

总结

  • 基于Vue.extend()实现一个全局组件
  • 实现单例模式下的全局组件

尽管该案例无法实现业务的需求,实际开发中也没有使用此方法,因为无法实现vuex数据通信的能力,但作为一个实际开发中遇到的场景,简单的demo功能也够用了。

转载自:https://juejin.cn/post/7072704321774682119
评论
请登录