Extend

使用 Vue.extend 方法使用创建一个“子类”。参数是一个包含组件选项的对象

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

<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')

结果如下:

<p>Walter White aka Heisenberg</p>

平时会使用 Vue.extend 制作 Vue 公共插件

下面通过两个组件示例来了解一下用法

例子一-Toast组件

首先实现一个 Toast 组件

先实现 Toast 组件部分

// Toast.vue
<template>
  <transition name="fade">
    <div class="wrap" v-show="visible">{{title}}</div>
  </transition>
</template>
<script>
  export default {
    data(){
      return {
        title: '',
        visible: false,
      }
    },
  }
</script>

<style scoped>
  .wrap{
    position: fixed;
    left: 50%;
    top:100px;
    background: rgba(0,0,0,.6);
    padding: 10px;
    border-radius: 5px;
    /*transform: translateX(-50%);*/
    color:#fff;
    max-width: 400px;
    min-width: 100px;
    font-size: 15px;
    text-align: center;
    z-index: 9999;
  }
  .fade-enter-active, .fade-leave-active {
    transition: .3s ease-out;
  }
  .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
    opacity: 0;
    transform: translateY(-20px);
  }
/*  .fade-enter-to, fade-leave{
    opacity: 1;
    transform: translateY(50px);
  }*/
</style>

使用 vue.extend 生成 toast 组件实例

// toast.js
import vue from 'vue'

// 这里就是我们刚刚创建的那个静态组件
import toastComponent from './Toast.vue'

let instance

// 返回一个 扩展实例构造器
const ToastConstructor = vue.extend(toastComponent)

const initInstance = () => {
  // 生成 toast 组件实例
  instance = new ToastConstructor({
    el: document.createElement('div')
  })
  // 获者 instance = new ToastConstructor().$mount(document.createElement('div'))
}

// 通过 vue 实例就可以设置和获取实例中的属性和方法了
function initToast(options){
  if(!instance) {
    initInstance()
  }
  for(let item in options) {
    instance[item] = options[item]
  }
  if(instance) {
    // 将这个 vue 插入到 DOM 中
    document.body.appendChild(instance.$el)
  }
  // 显示这个 toast
  instance.visible = true
  // 过一定时间后隐藏这个组件
  setTimeout(() => {
    instance.visible = false
  }, options.duration)

}

const defaultOptions = {
  title: '',
  type: 'success',
  duration: 1500
}
// 注册为全局组件的函数
function registryToast(options) {
  if( Object.prototype.toString.call(options) !== '[object Object]') {
    options = {}
  }
  return initToast({ ...defaultOptions, ...options })
}
export default registryToast

然后再组装成插件,将方法保存到 Vue.prototype 中,这样就可以在作用所有组件中使用这个 toast 方法了

// ./index.js
import toast from './toast.js'

export default {
  install(Vue, args = {}) {
    Vue.prototype.$toast = toast
  }
}

安装这个插件

import Vue from 'vue'
import toast from '../components/toast/index'

Vue.use(toast)

// 在组件中使用这个组件
this.$toast({
  title: '成功显示了',
  duration: 2000
})

例子二-Alert

这个组件相比之前的 Toast 组件它多了一个回调方法

先实现组件

// MeaasgeBox.vue
<template>
  <div class="hello-message-box-bg" v-show="visible">
    <div class="hello-message-box">
      <div class="hello-content">
        <div class="hello-title" v-if="title">{{title}}</div>
        <div class="hello-des" v-if="type === 'test' && content">{{content}}</div>
        <div class="hello-des" v-if="type === 'html' && content" v-html="content"></div>
      </div>
      <div class="hello-btn-operate">
        <div class="hello-btn cancel" v-show="showCancel" @click="cancel(false)">{{cancelText}}</div>
        <div class="hello-btn confirm" @click="cancel(true)">{{confirmText}}</div>
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    data(){
      return {
        title: '',
        content: '',
        confirmText: '',
        cancelText: '',
        type: 'test',
        visible: false,
        showCancel: true
      }
    },
    methods: {
      cancel(arg) {
        this.callback(arg)
      }
    },
    mounted() { }
  }
</script>

<style scoped lang="less">
  .hello-message-box-bg{
    position: fixed;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, .1);
    left: 0;
    top: 0;
    z-index: 999;
  }
  .hello-message-box{
    position: absolute;
    left: 50%;
    top:50%;
    background: #fff;
    border-radius: 8px;
    transform: translate(-50%,-50%);
    width: 300px;
    box-shadow: 0 0 3px 1px #c7c7c7;
    color: #333;
  }
  .hello-message-box .hello-title{
    text-align: center;
    font-weight: bold;
    font-size: 17px;
    margin-bottom: 5px;
  }
  .hello-content{
    padding: 15px;
    text-align: center;
  }
  .hello-des{
    word-break: break-all;
  }
  .hello-btn-operate{
    text-align: right;
    display: flex;
    border-top: solid 1px #c7c7c7;
  }
  .hello-btn-operate .hello-btn{
    flex: 1;
    text-align: center;
    padding: 10px 0;
    cursor: pointer;
  }
  .hello-btn-operate .confirm{
    color: dodgerblue;
  }
  .hello-btn-operate .hello-btn.cancel{
  }
  .hello-btn:not(:last-child) {
    border-right: solid 1px #c7c7c7;
  }
</style>
<style lang="less">
  .hello-message-box-bg{
    img{
      max-width: 200px;
      max-height: 500px;
    }
  }
</style>

使用 vue.extend 创建 MeaasgeBox 组件实例

import vue from 'vue'

// 这里就是我们刚刚创建的那个静态组件
import toastComponent from './MessageBox.vue'

let instance, tempPro;

const MessageBoxConstructor = vue.extend(toastComponent)
const defaultCallback = action => {
  instance.visible = false;
  tempPro(action) // 执行回调
}

const initInstance = () => {
  instance = new MessageBoxConstructor({
    el: document.createElement('div')
  })
  instance.callback = defaultCallback // 接收组件回调
}


function showNextMsg(options) {
  if(!instance){
    initInstance()
  }
  for(let item in options) {
    instance[item] = options[item] // 属性赋值
  }
  if(instance){
    document.body.appendChild(instance.$el);
  }
  instance.visible = true;
}
function MessageBox(options){
  return new Promise((resolve, reject) => {
    tempPro = resolve // 将`resolve`保存到全局
    showNextMsg(options)
  })
}
const defaultOptions = {
  title: '',
  content: '',
  theme: 'confirm', // 'confirm',  'warn'
  type: 'test',
  confirmText: '确定',
  cancelText: '取消',
  showCancel: true
}

// 调用 Alert 后返回一个 Promise, 所以 MessageBox 也需要返回一个 Promise
function helloAlert(options){
  if( Object.prototype.toString.call(options) !== '[object Object]') {
    options = {}
  }
  return MessageBox({ ...defaultOptions, ...options })
}
export default helloAlert

使用

helloAlert({title: 'title', content: 'content'})
  .then(res => {
    alert(res)
  })
Last Updated:
Contributors: 156081289@qq.com