问题形容
工作中尽管应用工具库很高兴很高效,但咱们还是要抽空看看工具库的源码,因为源码中会用到一些不常常应用的api办法,记住这些api办法,可晋升本人的编程能力,有助于当前封装本人的工具库,从而更好的实现一些需要。
需要剖析
组件封装之前,咱们要想一下要封装的这个组件的利用场景和应用需要有哪些,以此为突破口,便于更好的实现代码逻辑
利用场景和需要:音讯提醒
愚认为,message次要是信息提醒,利用场景在于用户执行了一些操作,是否胜利或失败之类的交互反馈。所以,咱们能够定义这个要封装的组件有以下需要:
- 须要能够输出信息文字 message参数
- 须要message信息的类型反馈(胜利反馈、正告反馈、谬误反馈、一般信息反馈)type参数
- 须要提醒完当前,能够设定默认隐没工夫 duration参数
- 当鼠标悬浮的时候保留这个音讯提醒,不让其隐没 定时器timer参数
- 其余诸如 提醒小图标的类型和文字是否居中 之类的
如果咱们看饿了么UI官网的组件,咱们会发现官网思考的还是非常具体的,给到了很多配置项Options参数,不过在咱们本人理论封装组件中,不须要像官网那样,做很多的配置项,只须要实现罕用的配置项即可,保留最实用的性能即可。
饿了么UI官网el-message组件:https://element.eleme.cn/#/zh...
效果图
了解形式
对于这个性能成果,集体倡议能够如下了解
- 先温习一下平时用的不多的api
- 再把代码clone下来,跑起来(文末附上github代码仓库地址)
- 联合正文,既可疾速了解了
知识点温习之:class的数组用法和:style用法
// html<div :class="[ 'messageBox', /* .messageBox这个类名确定要加到div这个标签上 */ center ? 'horizontal' : '', /* 是否给div标签加上.horizontal这个类名取决于center这个变量的值是否为true */ typeArr.includes(type) ? type : '', /* 是否给div这个标签加上type变量值的类名,取决于typeArr变量数组是否蕴含type的值 */ ]" :style="controlTop" /* 等价于:style={top: `12px`} 等价于 style="top: 12px" 即间隔顶部top值为12像素 */></div>// jsdata() { return { center: false, // 是否让程度文字居中,默认false type: "info", // 默认info类型 typeArr: ["info", "success", "warning", "error"], // 总共4种类型 };},computed: { controlTop() { return { top: `12px` }; }, },
为什么要提到:class的数组用法以及:style的用法呢?
因为在本例中,给message绑定四种类型(胜利、正告、谬误、信息)的款式,就须要应用到;
用户屡次点击触发message的呈现,管制下一个message的地位在上一个的下方,就须要让一直的更改下一个message的top值;
知识点温习之transition过渡钩子函数
// html<transition v-on:before-enter="beforeEnter" /* 过渡呈现进入之前 */ v-on:enter="enter" /* 过渡呈现进入 */ v-on:after-enter="afterEnter" /* 过渡呈现进入之后 */ v-on:enter-cancelled="enterCancelled" /* 勾销进入过渡 */ v-on:before-leave="beforeLeave" /* 过渡隐没来到之前 */ v-on:leave="leave" /* 过渡隐没来到 */ v-on:after-leave="afterLeave" /* 过渡隐没来到之后 */ v-on:leave-cancelled="leaveCancelled" /* 勾销过渡隐没来到 */> <!-- ... --> </transition>// jsmethods: { // ... afterLeave(){ /* 本例中应用了这个钩子,当过渡隐没的时候会触发这个钩子函数, 咱们能够在钩子函数中写一些js逻辑代码,进行相应操作 */ } // ...}
那么,什么时候,过渡隐没,什么时候过渡呈现?
最显著的就是,v-show由true改为false、由false改为true的时候,会主动触发transition的过渡钩子函数执行
本例中应用过渡钩子函数次要是因为,当隐没一个message的时候,须要缩小一个message的计数,所以须要通过这个钩子去进行js逻辑代码曹组欧
过渡钩子详见官网文档:https://cn.vuejs.org/v2/guide...
知识点温习之vue销毁组件的形式
- 应用
v-if
官网举荐最好的形式 - 应用key 个别用的不是特地多
this.$destroy(true)
vue的1.x版本经常应用,从2.x版本就不反对了,相当于兼容写法- 本人手动移除
this.$el.parentNode.removeChild(this.$el);
本例应用之
对于第3点和第4点,尤大佬还亲自答复了对于这个问题的issues。简略截图如下:
issues地址如下:https://github.com/vuejs/vue/...
为什么提到这个销毁dom形式呢?
因为咱们应用v-show加上去transition管制message的暗藏和隐没的,这个成果丝滑一些,没有应用v-if间接干掉dom。所以须要手动写代码,在过渡隐没当前,当咱们看不到message的时候,再偷偷的给message移除掉即可
残缺代码
整体代码思路
- 搞一个message组件用于继承
- 应用Vue.extend继承这个组件造成一个结构器
- 定义一个函数,函数一执行,就应用结构器创立一个message显示,默认3秒主动隐没
- 把这个函数挂载在原型上,并裸露进来,不便拜访应用
对于Vue.extend继承不太熟悉的,能够先看看笔者的另外两篇文章哦
继承... https://segmentfault.com/a/11...
继承... https://segmentfault.com/a/11...
应用的.vue文件代码
// html<button @click="showMessage1">信息弹出</button><button @click="showMessage2">胜利弹出</button><button @click="showMessage3">正告弹出</button><button @click="showMessage4">谬误弹出</button><button @click="showMessage5">弹出5秒敞开</button><button @click="showMessage6">文字居中哦</button><button @click="showMessage7">引入应用</button>// 一种是原型链应用形式,另一种是引入应用形式import MyMessage from "@/components/index.js";methods: {showMessage1() { this.$myMessage({ message: "信息弹出", type: "info", });},showMessage2() { this.$myMessage({ message: "胜利弹出", type: "success", });},showMessage3() { this.$myMessage({ message: "正告弹出", type: "warning", });},showMessage4() { this.$myMessage({ message: "谬误弹出", type: "error", });},showMessage5() { this.$myMessage({ message: "弹出5秒敞开", });},showMessage6() { this.$myMessage({ message: "文字居中哦", center: true, });},showMessage7() { MyMessage({ message: "引入应用", type: "success", });},},
通过继承挂载原型上便于动态创建文件代码
import Vue from 'vue';import messageComponent from './src/index.vue' // 引入组件,不便继承let MessageConstructor = Vue.extend(messageComponent); // 引入一个message结构器,不便new之let instance = null // 定义组件实例let count = 0 // 定义统计次数,便于晓得创立多少个实例const MyMessage = function (options) { if (options.duration & typeof options.duration !== 'number') { // 对于duration数字类型的校验 console.error('Error! duration Must be a numeric type ') // 用户乱传递非数字类型参数,就抛错不执行后续代码 return } count = count + 1 // MyMessage函数调用一次,统计次数加一个 instance = new MessageConstructor({ // 实例化一个组件实例 data: options, // data传参数,组件的data接管(即传递配置项) propsData: { // propsData传参, count: count, // 将统计的次数传递给子组件 cutCount: cutCount // 传递一个函数,当MyMessage隐没的时候,告诉外界 }, }); instance.$mount(); // 实例组件挂载 document.body.appendChild(instance.$el); // 把这个组件实例的dom元素,追加到document文档中 instance.isShowMyMessage = true; // 将组件的isShowMyMessage属性值置为true,即让实例呈现,即音讯呈现 return instance; // MyMessage函数执行一次,就会返回一个加工好的实例对象}function cutCount() { // 当message隐没一个 count = count - 1 // 就把外界统计的数量缩小一个 let messageBoxDomList = document.querySelectorAll('.messageBox') // 而后选中所有的messageDOM元素 for (let i = 0; i < messageBoxDomList.length; i++) { // 遍历一下这个DOM伪数组 let dom = messageBoxDomList[i] // 所有的都往上挪动60像素 dom.style['top'] = parseInt(dom.style['top']) - 60 + 'px' }}export default MyMessage // 裸露进来Vue.prototype.$myMessage = MyMessage; // 挂载在vue原型上,不便this.$myMessage调用
用于继承的message组件代码
<template> <transition name="message-fade" @after-leave="handleAfterLeave"> <div :class="[ 'messageBox', center ? 'horizontal' : '', typeArr.includes(type) ? type : '', ]" :style="controlTop" v-show="isShowMyMessage" @mouseenter="clearTimerFn" @mouseleave="startTimerFn" > <span> {{ iconObj[type] }} {{ message }}</span> </div> </transition></template><script>export default { name: "myMessage", props: { count: { // 统计次数 type: Number, default: 1, }, cutCount: { // dom隐没告诉外界函数 type: Function, }, }, data() { return { isShowMyMessage: false, // v-show的标识布尔值 message: "", // 提醒的音讯文字 timer: null, // 用来革除的定时器 duration: 3000, // 默认3秒隐没 center: false, // 是否让程度文字居中,默认false type: "info", // 默认info类型 typeArr: ["info", "success", "warning", "error"], // 总共4种类型 iconObj: { // 这里的对应图标,就以 红桃、黑桃、方块、梅花 为例吧 info: "♥", success: "♠", warning: "♦", error: "♣", }, }; }, computed: { controlTop() { return { // 间隔顶部的地位,取决于创立了几个message top: `${12 + (this.count - 1) * 60}px`, }; }, }, mounted() { this.startTimerFn(); // 开启定时器,默认3秒后销毁组件 }, methods: { // 开始定时器计时,要销毁dom元素 startTimerFn() { // 工夫大于0,才做计时隐没暗藏 if (this.duration > 0) { this.timer = setTimeout(() => { this.close(); // 达到计时工夫,就暗藏这个notice }, this.duration); } }, // 鼠标移入,革除定时器,使dom永远存在;鼠标移出,再从新计时筹备移除dom clearTimerFn() { clearTimeout(this.timer); }, // 过渡动画隐没时,会执行此钩子函数,销毁组件,同时移除dom handleAfterLeave() { // 在移除一个dom之前,要先告诉外界的计数count减去一个,并让余下的所有dom都往上挪动,即更改地位 this.cutCount(); // 而后移除dom this.$destroy(true); this.$el.parentNode.removeChild(this.$el); }, // 敞开暗藏dom close() { this.isShowMyMessage = false; /** * 留神当v-show为false的时候,会触发过渡动画隐没钩子handleAfterLeave函数执行 * 相当于在close函数中,执行了 this.handleAfterLeave() * */ }, },};</script><style lang="less" scoped>// 默认款式.messageBox { min-width: 320px; height: auto; // 高度由内容撑开 padding: 16px; // 加上内边距 border: 1px solid #e9e9e9; position: fixed; // 应用固定定位,使地位凑近顶部并居中 top: 20px; left: 50%; transform: translateX(-50%); // 管制居中 box-sizing: border-box; border-radius: 4px; // 加圆角难看一些 background-color: #edf2fc; // 过渡成果 transition: opacity 0.3s, transform 0.4s, top 0.4s; display: flex; // 开启弹性盒垂直居中 align-items: center;}// 文字居中款式.horizontal { justify-content: center;}// 胜利提醒款式.success { color: #67c23a; background-color: #f0f9eb;}// 正告提醒款式.warning { color: #e6a23c; background-color: #fdf6ec;}// 谬误提醒款式.error { color: #f56c6c; background-color: #fef0f0;}// 过渡成果款式.message-fade-enter,.message-fade-leave-active { opacity: 0; -webkit-transform: translate(-50%, -100%); transform: translate(-50%, -100%);}</style>
github仓库代码地址
elementui源码学习仿写组件,筹备工作不忙的时候,写一个系列,我会尽可能多写点正文哦。与大家共同进步成长^_^
github地址:https://github.com/shuirongsh...