在平时的开发过程中,我们总是先写好一个组件,然后在需要的页面中用 import 引入即可,但如果是下面这种类型的组件呢👇
上面这种类型的浮层提示有一个很大的特点,就是使用频率特别高,几乎每个页面都会用到它,于是乎我们就要在每个页面中去引入该组件,并且在每个页面都得通过一个变量来控制它的显隐,这显然不是我们想要的🙅。。。那我们想要的是什么样呢🤔?用过一些 UI 框架的同学们应该知道有这样一种用法:
this.$toast({ duration: 3000, content: '这是一条消息提示' });
没错,就是这么简单的一句话就万事大吉了(就是用 js 调用组件而已啦🧐)。那这种效果究竟是怎么实现的呢?今天就让我们来(手把手🤝 )一探究竟吧!
前置知识
不知道小伙伴们有没有用过 Vue.extend() 这个东东,反正我是很少碰过,印象不深,所以这里我们先来短暂了解一下 Vue.extend() 主要是用来干嘛的。先来个官方说明(不多的,坚持下):
没怎么看懂?😴没关系,不重要,你只要记住(加少许理解)以下用法即可:
// 导入以往的普通组件 import Main from './main.vue'; // 用 Vue.extend 创建组件的模板(构造函数) let mainConstructor = Vue.extend(Main); // 实例化组件 let instance = new mainConstructor(); // 挂载到相应的元素上 instance.$mount('#app');
不知道你看懂没有,上面的 Vue.extend(Main) 就是一个基于 main.vue 的组件模板(构造函数),instance 是实例化的组件,$mount() 是手动挂载的意思。其中 Vue.extend() 和 $mount() 就是我们通过 js 调用、渲染并挂载组件的精髓所在,相当于早前的 createElement 和 appendChild,有异曲同工之效。这个点需要我们好好熟悉一下,所以你可以先停下来屡屡思路🤔。
补充一下🤐:$mount() 里面如果没有参数,说明组件只是渲染了但还没有挂载到页面上,如果有正确的(元素)参数则直接挂载到元素下面。
写一个 toast 组件
js 调用归调用,最原始的组件还是要有的,只是我们不通过 import 来引入到页面中而已。ok,我们就以最开始的那个 toast 图片来简单写一下这个 vue 组件(message 和 alert 也是一样的)。这里就直接上代码啦,毕竟它的结构简单到爆了,也不是本章节的重点:
<!-- main.vue --> <template> <div> <p>服务器错误,请稍后重试</p> </div> </template> <script> export default { name: "Toast", mounted() { setTimeout(() => { // 3s 后通过父级移除子元素的方式来移除该组件 this.$el.parentNode.removeChild(this.$el); }, 3000); } }; </script> <style lang="scss" scoped> .toast { display: flex; align-items: center; justify-content: center; position: fixed; top: 0; bottom: 0; left: 0; right: 0; color: #fff; z-index: 9999; background: transparent; > p { padding: 12px 22px; font-size: 18px; border-radius: 4px; background: rgba(17, 17, 17, 0.7); } } </style>
上面的内容想必大家应该都能看懂,所以这里就直接讲下面的重点了。
写一个 main.js
我们在 main.vue 的同级目录下新建一个 main.js 文件。我们先瞟一眼文件内容(也不多,已经是个最简版了)👇:
// main.js import Vue from "vue"; // 引入 Vue 是因为要用到 Vue.extend() 这个方法 import Main from "./main.vue"; // 引入刚才的 toast 组件 let ToastConstructor = Vue.extend(Main); // 这个在前面的前置知识内容里面有讲到 let instance; const Toast = function() { instance = new ToastConstructor().$mount(); // 渲染组件 document.body.appendChild(instance.$el); // 挂载到 body 下 }; export default Toast; 。
上面的代码暴露了一个 Toast 函数。为什么要暴露一个函数呢?原因很简单:你想想,我们最终是不是要根据 this.$toast() 来调用一个组件,说白了,通过 js 调用,本质就是调用一个 函数。也就是说 this.$toast() 就是执行了上面代码中导出的 export default Toast,也就是执行了 Toast 函数(const Toast = function() {}),所以当我们调用 this.$toast() 的时候其实就是执行了 Toast() 函数。而 Toast() 函数只做了一件事情:就是通过手动挂载的方式把组件挂载到 body 下面。
补充一下🤐:一般来说我们常见的是 $mount("#app"),也就是把组件挂载到 #app 下面,<router-view /> 也包含在 #app 中,但是我们这种 toast 提示是放在 body 下面的,也就是说它不受 #app 和 <router-view /> 的管控,所以当我们切换页面(路由)的时候,这个 toast 组件是不会跟着立马消失的,这点要注意哦😯。
这里顺便给个组件的目录结构,如下图所示:
开始调用