如何实现一个通过js调用使用的消息提示组件(Vue)

2,932 阅读4分钟

在项目开发过程中可能我们习惯了使用各种现成的UI库,它可以帮助我们快速的完成项目开发,例如我们在项目中经常使用到的Toast、Message提示组件,我们通常只需要通过js来调用就可以使用了,和我们平常使用组件的方式(import导入、components注册)并不一样,那接下来我们就自己来实现一个通过js方法来使用的组件。我们最后要实现的组件就是element-UI的Message消息提示

一、准备工作

我们首先在项目中新建一个文件夹来存放这个组件,我建在了/src/components/Message/,很显然Message就是我放提示组建的目录。

接着我们在Message下再建一个index.vueindex.js的文件,js是我们组件的入出口也是用来导出方法被调用的主体。

二、编写组件模板

我们先写一个基础的样式,然后通过js调用渲染出来,之后我们在对组件进行细节优化

  • index.vue内容
<template>
  <div class="message">
    <p>这是一条消息提示</p>
  </div>
</template>

<script>
export default {
  name: 'Message'
}
</script>

<style scoped lang="stylus">
.message
  position fixed
  top 3vh
  left 50vw
  transform translateX(-50%)
  border 1px solid #EBEEF5
  background-color #edf2fc
  min-width 340px
  min-height 50px
  display flex
  align-items center
  box-sizing border-box
  padding 0 15px
  border-radius 5px
</style>
  • index.js内容
import Vue from 'vue';
import Message from './index.vue';

const MessageConstructor = Vue.extend(Message);

export const $message = () => {
  const instance = new MessageConstructor().$mount();
  document.body.appendChild(instance.$el);
}
  • 在页面中引入$message方法使用
<script>
import { $message } from '@/components/Message/index';
export default {
  name: 'home',
  mounted() {
    // 正常应该在点击按钮或者某些操作执行后调用,我这里为了直观显示就在生命周期内调用了
    $message();
  }
}
</script>
  • 效果

  • 详解

index.vue中是我们编写组件的代码,和我们正常编写Vue组件使一毛一样的。我们之所以可以通过调用js方法来使用组件,最关键的代码是在index.js中。

index.js中只有7行代码,看一眼,很容易猜到最核心的肯定就是extend$mountappendChild三个api,那我们就看下这三个API到底做了什么

  1. extend是Vue的一个全局api,它接收一个包含组件选项的对象,例如这个样子(官方示例)
Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})

然后extend会创建一个Vue‘子类’(猜测就是一个没有被实例化的Vue组件)

  1. $mount:如果我们对extend创建的子类进行实例化的时候没有传入 el 选项,那此时这个组件就处于未挂载的状态,我们就需要调用$mount方法,手动将其挂载,$mount方法如果没有传入参数,那么它挂载后会自动关联此组件的顶层元素,如果传入参数(可以接收元素、元素选择器)则关联传入的元素。基于此其实我们也可以不调用$mount方法,在实例化的时候传入el选项;
import Vue from 'vue';
import Message from './index.vue';

const MessageConstructor = Vue.extend(Message);

export const $message = () => {
  const instance = new MessageConstructor({
    el: document.createElement('div'),
  });
  document.body.appendChild(instance.$el);
}
  1. appendChild: 至此就很容易理解了,最后将组件加入到body主体中渲染出来
  2. 最后使用的时候调用$message方法,没什么说的。

很关键的内容都在这里。那么接下来我们就再实现个东西,Element-UI的这个组件是可以传入自定义消息内容的,也可以传入不同的type来显示成功或警告样式的消息,更进一步,比如我们需要在消息关闭的时候来做别的操作,又要如何处理呢?

三、组件完善

1. 自定义组件内容

  • 修改index.js代码
import Vue from 'vue';
import Message from './index.vue';

const MessageConstructor = Vue.extend(Message);

// 方法接收个options参数,options必须是object类型
export const $message = (options) => {
  const instance = new MessageConstructor({
    el: document.createElement('div'),
    // 组件实例生成的时候在给组件动态传入data
    data: options
  });
  document.body.appendChild(instance.$el);
}
  • 修改index.vue代码
<template>
  <div class="message">
    // 内容改为可变的
    <p>{{message}}</p>
  </div>
</template>

<script>
export default {
  name: 'Message',
  // data是新增的
  data() {
    return {
      message: '',
    }
  }
}
</script>

<style scoped lang="stylus">
.message
  position fixed
  top 3vh
  left 50vw
  transform translateX(-50%)
  border 1px solid #EBEEF5
  background-color #edf2fc
  min-width 340px
  min-height 50px
  display flex
  align-items center
  box-sizing border-box
  padding 0 15px
  border-radius 5px
</style>
  • 调用时传入内容
$message({message: '对不起,注册失败'});

2. 增加提示关闭按钮,提示被关闭后调用者可以感知

  • 修改index.vue代码
<template>
  <div class="message">
    <p>{{message}}</p>
    <i class="close" @click="handleClose">&times;</i>
  </div>
</template>

<script>
export default {
  name: 'Message',
  data() {
    return {
      message: '',
    }
  },
  methods: {
    emitClose() {},
    handleClose() {
      this.$el.parentNode.removeChild(this.$el);
      this.emitClose();
    }
  }
}
</script>

<style scoped lang="stylus">
.message
  position fixed
  top 3vh
  left 50vw
  transform translateX(-50%)
  border 1px solid #EBEEF5
  background-color #edf2fc
  min-width 340px
  max-width 500px
  min-height 50px
  display flex
  align-items center
  justify-content space-between
  box-sizing border-box
  padding 0 15px
  border-radius 5px
  .close
    font-size 25px
    align-self flex-start
    margin-top -5px
    margin-right -9px
    cursor pointer
</style>
  • 修改index.js代码
import Vue from 'vue';
import Message from './index.vue';

const MessageConstructor = Vue.extend(Message);

export const $message = (options,methods = {}) => {
  const instance = new MessageConstructor({
    el: document.createElement('div'),
    data: options,
    methods
  });
  document.body.appendChild(instance.$el);
}
  • 调用
$message({message: '对不起,注册失败对不起'}, {
  emitClose() {
    console.log('组件被关闭了');
  },
});

TIP: 如果关闭的时候希望被调用者可以被感知,除了传methods,其实也可以直接传入data,不过传入的就是一个函数,类似于

$message({
    message: '对不起,注册失败对不起',
    onClose() {
        console.log('组件被关闭了');
    },
});

四、补充

至此其实我们讲这个组件的目的已经完成了,就是告诉你如何通过js来使用”消息提示“这类的组件,其余的成功失败警告定时关闭等功能,就不一一实现了,时间空闲的各位可以自行实现一下。

如果这篇文章对你有作用还望不吝点个赞,如果有其他疑问或内容有误可以在评论留言指正啊。拜拜!