extend实现一个modal函数式组件

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实现

一、封装一个基础modal弹窗

  • 新建一个messageBox组件
    在这里插入图片描述

messageBox.vue

<template>
  <div :class="['message-box', type]">
    <div class="inner">
      <header class="header">
        <h1 class="title">{{title}}</h1>
        <span class="close-btn" @click="hideMessageBox">x</span>
      </header>
      <div class="content" v-if="typeof content === 'function'">
        <render-content />
      </div>
      <div v-else>
        {{content}}
      </div>
    </div>
  </div>
</template>

<script>
import Vue from 'vue';
export default {
  name: 'MessageBox',
  props: {
    type: {
      type: String,
      default: 'primary',
      validator: (value) => {
       return [
          'primary',
          'success',
          'warn',
          'danger',
        ].includes(value)
      }
    },
    title: {
      type: String,
      default: 'This is title'
    },
    content: {
      type: [String, Function],
      default: 'This is content'
    }
  },
  created () {
      if (typeof this.content === 'function') {
        Vue.component('render-content', {
        render: this.content
      })
    }
  },
  data() {
    return {
      
    };
  },

  mounted() {
   
  },

  methods: {
    hideMessageBox () {
      this.$messageBox.hide (() => {
        console.log('HIDE')
      })
    }
  },
};
</script>

<style lang="less" scoped>
.message-box {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,.5);
  .inner {
    position: absolute;
    top: 100px;
    left: 50%;
    width: 500px;
    margin-left: -250px;
    background-color: #fff;
    box-shadow: 1px 3px 5px #ededed;
    border-radius: 5px;
    overflow: hidden;
    .header {
      height: 44px;
      padding: 0 10px;
      line-height: 44px;
      box-sizing: border-box;
      .title {
        float: left;
        font-size: 16px;
      }
      .close-btn {
        font-size: 24px;
        float: right;
        cursor: pointer;
      }
    }
    .content {
      padding: 20px;
      box-sizing: border-box;
    }

  }
  &.primary {
    header {
      background-color: #1890ff;
      color: #fff;
    }
  }
  &.success {
    header {
      background-color: #52c41a;
      color: #fff;
    }
  }
  &.warn {
    header {
      background-color: #faad14;
      color: #fff;
    }
  }
  &.danger {
    header {
      background-color: #f51a27;
      color: #fff;
    }
  }
}
</style>

content 做兼容,使其支持jsx

  • 在components的index.js中导出

index.js

import MessageBox from '@/components/messageBox'
export {
  MessageBox
}
  • 在main.js中导入使用
import MessageBox from '@/components/messageBox'
Vue.use(MessageBox)  

二、使用extend实现函数式封装

  • messageBox/index.js
import MessageBox from './messageBox'

export default {
  install (Vue) {
    let _messageBox = null
    const show = (props, callback) => {
      console.log('这个是show方法props', props)
      if (!_messageBox) {
        // extent()中的{} 就是export default {} 中的内容
        const MessageBox = Vue.extend({
          render(h) {
            return h('MessageBox', {props})
          }
        })
        console.log('MessageBox', MessageBox)
        // 与Vue构造函数是一样的
        _messageBox = new MessageBox()
        console.log('_MESSAGEBOX',_messageBox )
        this.vm = _messageBox.$mount()
        console.log('this.vm', this.vm)
        // 挂在到body
        document.body.appendChild(this.vm.$el)
        callback && callback()
      }
    }
    const hide = (props, callback) => {
      console.log('这个是hide方法', props)
      document.body.removeChild(this.vm.$el)
      _messageBox.$destroy();
      _messageBox = null
      callback && callback()
    }
    const danger = (props, callback) => {
      show({...props, type: 'danger'}, callback)
    }
    const warn = (props, callback) => {
      show({...props, type: 'warn'}, callback)
    }
    const success = (props, callback) => {
      show({...props, type: 'success'}, callback)
    }
    const info = (props, callback) => {
      show({...props, type: 'primary'}, callback)
    }
    Vue.prototype.$messageBox = {
      show,
      hide,
      danger,
      warn,
      success,
      info
    }
    Vue.component(MessageBox.name, MessageBox)
  }
}

这里的install方法在Vue.use是会自动执行

三、在页面中使用

<template>
  <div>
    <button @click="openMessage">show</button>
    <button @click="openMessageInfo">Info</button>
    <button @click="openMessageSuccess">Success</button>
    <button @click="openMessageDanger">Danger</button>
    <button @click="openMessageWarn">Warn</button>
  </div>
</template>

<script>
export default {
  name: 'PriojectPage',
  components: {},
  data() {
    return {
      
    };
  },

  mounted() {
    
  },

  methods: {
    openMessage () {
      console.log('this.$messageBox', this.$messageBox)
      this.$messageBox.show({
        title: 'APP',
        content: h => {
          return h('div', {'class': 'inner-title'},
          Array.apply(null, {length: 10}).map(() => ['This is content for App', h('div',{style: {color: '#ccc'}}, '换行了')])
           )
        },
        type: 'primary'
      })
    },
    openMessageInfo () {
      this.$messageBox.info({
        title: 'APP',
        content: 'This is content for APP',
      })
    },
    openMessageSuccess () {
       this.$messageBox.success({
        title: 'APP',
        content: 'This is content for APP',
      })
    },
    openMessageDanger () {
       this.$messageBox.danger({
        title: 'APP',
        content: 'This is content for APP',
      })
    },
    openMessageWarn () {
       this.$messageBox.warn({
        title: 'APP',
        content: 'This is content for APP',
      })
    }
  }
}
</script>

<style lang="less">
.inner-title {
  color: red;
}
</style>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值