elementui源码学习之仿写一个el-message
问题描述
工作中虽然使用工具库很快乐很高效,但我们还是要抽空看看工具库的源码,因为源码中会用到一些不经常使用的api方法,记住这些api方法,可提升自己的编程能力,有助于以后封装自己的工具库,从而更好的实现一些需求。
需求分析
组件封装之前,我们要想一下要封装的这个组件的应用场景和使用需求有哪些,以此为突破口,便于更好的实现代码逻辑
应用场景和需求:消息提示
愚以为,message主要是信息提示,应用场景在于用户执行了一些操作,是否成功或失败之类的交互反馈。所以,我们可以定义这个要封装的组件有以下需求:
- 需要可以输入信息文字 message参数
- 需要message信息的类型反馈(成功反馈、警告反馈、错误反馈、普通信息反馈)type参数
- 需要提示完以后,可以设定默认消失时间 duration参数
- 当鼠标悬浮的时候保留这个消息提示,不让其消失 定时器timer参数
- 其他诸如 提示小图标的类型和文字是否居中 之类的
如果我们看饿了么UI官方的组件,我们会发现官方考虑的还是十分详细的,给到了很多配置项Options参数,不过在我们自己实际封装组件中,不需要像官方那样,做很多的配置项,只需要实现常用的配置项即可,保留最实用的功能即可。
饿了么UI官方el-message组件:http://element.eleme.cn/#/zh-CN/component/message
效果图
理解方式
关于这个功能效果,个人建议可以如下理解 - 先复习一下平常用的不多的api - 再把代码clone下来,跑起来(文末附上github代码仓库地址) - 结合注释,既可快速理解了
知识点复习之:class的数组用法和:style用法
``js
// 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像素 */
// js
data() {
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过渡钩子函数
```js // 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" / 取消过渡消失离开 /
<!-- ... -->
// js methods: { // ... afterLeave(){ / 本例中使用了这个钩子,当过渡消失的时候会触发这个钩子函数, 我们可以在钩子函数中写一些js逻辑代码,进行相应操作 / } // ...
} ``` 那么,什么时候,过渡消失,什么时候过渡出现?
最明显的就是,v-show由true改为false、由false改为true的时候,会自动触发transition的过渡钩子函数执行
本例中使用过渡钩子函数主要是因为,当消失一个message的时候,需要减少一个message的计数,所以需要通过这个钩子去进行js逻辑代码曹组欧
过渡钩子详见官方文档:http://cn.vuejs.org/v2/guide/transitions.html
知识点复习之vue销毁组件的方式
- 使用
v-if
官方推荐最好的方式 - 使用key 一般用的不是特别多
this.$destroy(true)
vue的1.x版本常常使用,从2.x版本就不支持了,相当于兼容写法- 自己手动移除
this.$el.parentNode.removeChild(this.$el);
本例使用之 关于第3点和第4点,尤大佬还亲自回答了关于这个问题的issues。简单截图如下:
issues地址如下:http://github.com/vuejs/vue/issues/3534
为什么提到这个销毁dom方式呢?
因为我们使用v-show加上去transition控制message的隐藏和消失的,这个效果丝滑一些,没有使用v-if直接干掉dom。所以需要手动写代码,在过渡消失以后,当我们看不到message的时候,再偷偷的给message移除掉即可
完整代码
整体代码思路
- 搞一个message组件用于继承
- 使用Vue.extend继承这个组件形成一个构造器
- 定义一个函数,函数一执行,就使用构造器创建一个message显示,默认3秒自动消失
- 把这个函数挂载在原型上,并暴露出去,方便访问使用
关于Vue.extend继承不太熟悉的,可以先看看笔者的另外两篇文章哦
继承... http://juejin.cn/post/7021724333391216677
继承... http://juejin.cn/post/7108542695387168799
使用的.vue文件代码
```js // html
// 一种是原型链使用方式,另一种是引入使用方式 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", }); }, }, ```
通过继承挂载原型上便于动态创建文件代码
```js 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组件代码
```js
```
github仓库代码地址
elementui源码学习仿写组件,准备工作不忙的时候,写一个系列,我会尽可能多写点注释哦。与大家共同进步成长^_^
github地址:http://github.com/shuirongshuifu/elementSrcCodeStudy
- 什么?后端要一次性返回我10万条数据!且看我这8种方案机智应对!
- 性能优化之通俗易懂学习requestAnimationFrame和使用场景举例
- 23个css动画效果,持续更新中...
- elementui源码学习之仿写一个el-message
- 项目优化之使用compression-webpack-plugin插件开启gzip压缩,以vue为例
- 巧妙使用Vue.extend继承组件实现el-table双击可编辑(不使用v-if和v-else)
- 通俗易懂讲解并手写一个vue数据双向绑定案例
- vue中使用docx-preview插件预览word文档(后端express)
- react组件通信方式之~图解父子组件通信和兄弟组件通信pubsub-js
- 解决react警告:findDOMNode is deprecated in StrictMode. findDOMNode was passed an...
- vue自定义指令使用~以仿写v-show和实现v-copy为例讲解
- el-table表头文字换行的三种方式
- elementUI时间日期选择器更改小图标的位置和icon
- 两种方式解决页面刷新vuex中数据丢失问题(详细讲解)
- vue组件的递归自调用~代码思路分析
- el-tree树组件的懒加载写法步骤