美文网首页
vue手动挂载组件

vue手动挂载组件

作者: lowpoint | 来源:发表于2020-07-17 16:56 被阅读0次

    在一些需求中,手动挂载组件能够让我们实现起来更加优雅。比如一个弹窗组件,最理想的用法是通过命令式调用,就像 elementUI 的 this.$message 。而不是在模板中通过状态切换,这种实现真的很糟糕。

    先来个最简单的例子:

    import Vue from 'vue'
    import Message from './Message.vue'
    
    // 构造子类
    let MessageConstructor = Vue.extend(Message)
    // 实例化组件
    let messageInstance = new MessageConstructor()
    // $mount可以传入选择器字符串,表示挂载到该选择器
    // 如果不传入选择器,将渲染为文档之外的的元素,你可以想象成 document.createElement()在内存中生成dom
    messageInstance.$mount()
    // messageInstance.$el获取的是dom元素
    document.body.appendChild(messageInstance.$el)
    
    

    下面实现一个简易的 message 弹窗组件

    Message/index.vue

    
    <template>
        <div class="wrap">
            <div class="message" :class="item.type" v-for="item in notices" :key="item._name">
                <div class="content">{{item.content}}</div>
            </div>
        </div>
    </template>
    // 默认选项
    const DefaultOptions = {
        duration: 1500,
        type: 'info',
        content: '这是一条提示信息!',
    }
    let mid = 0
    export default {
        data() {
            return {
                notices: []
            }
        },
        methods: {
            add(notice = {}) {
                // name标识 用于移除弹窗
                let _name = this.getName()
                // 合并选项
                notice = Object.assign({
                    _name
                }, DefaultOptions, notice)
    
                this.notices.push(notice)
    
                setTimeout(() => {
                    this.removeNotice(_name)
                }, notice.duration)
            },
            getName() {
                return 'msg_' + (mid++)
            },
            removeNotice(_name) {
                let index = this.notices.findIndex(item => item._name === _name)
                this.notices.splice(index, 1)
            }
        }
    }
    .wrap {
        position: fixed;
        top: 50px;
        left: 50%;
        display: flex;
        flex-direction: column;
        align-items: center;
        transform: translateX(-50%);
    }
    
    .message {
        --borderWidth: 3px;
        min-width: 240px;
        max-width: 500px;
        margin-bottom: 10px;
        border-radius: 3px;
        box-shadow: 0 0 8px #ddd;
        overflow: hidden;
    }
    
    .content {
        padding: 8px;
        line-height: 1.3;
    }
    
    .message.info {
        border-left: var(--borderWidth) solid #909399;
        background: #F4F4F5;
    }
    
    .message.success {
        border-left: var(--borderWidth) solid #67C23A;
        background: #F0F9EB;
    }
    
    .message.error {
        border-left: var(--borderWidth) solid #F56C6C;
        background: #FEF0F0;
    }
    
    .message.warning {
        border-left: var(--borderWidth) solid #E6A23C;
        background: #FDF6EC;
    }
    

    Message/index.js

    
    import Vue from 'vue'
    import Index from './index.vue'
    
    let messageInstance = null
    let MessageConstructor = Vue.extend(Index)
    
    let init = () => {
        messageInstance = new MessageConstructor()
        messageInstance.$mount()
        document.body.appendChild(messageInstance.$el)
    }
    
    let caller = (options) => {
        if (!messageInstance) {
            init(options)
        }
        messageInstance.add(options)
    }
    
    export default {
        // 返回 install 函数 用于 Vue.use 注册
        install(vue) {
            vue.prototype.$message = caller
        }
    }
    

    main.js

    import Message from '@/components/Message/index.js'
    
    Vue.use(Message)
    

    使用

    this.$message({
        type: 'success',
        content: '成功信息提示',
        duration: 3000
    })
    

    仅作收藏记录 出处见下
    作者:扣丁书屋
    链接:https://zhuanlan.zhihu.com/p/148562214
    来源:知乎

    相关文章

      网友评论

          本文标题:vue手动挂载组件

          本文链接:https://www.haomeiwen.com/subject/wftnhktx.html