vue.js的提示组件


Posted in Javascript onMarch 02, 2017

这次的教程里,我们要把组件化进行到底!最近半年的几个项目中,都遇到了需要使用Toast或者Notification组件的情况。在目前已有的一些基于Vue.js开发的组件库,都没有找到太合适的,所以自己重头实现了一个。历经几个项目的磨练,这个提示组件的功能已经越来越完善,这次就分享一下组件以及其实现思路吧。

GitHub 仓库: https://github.com/Yuyz0112/vue-notie

Demo 地址: http://lab.myriptide.com/vue-notie/

vue.js的提示组件

深入组件化,组件的拆分、整合与复用

Vue.js的组件化可以说是其招牌特性之一,而在实际应用时,并非一味地追求组件颗粒越小越好,而是需要根据项目的实际需求,来分析自己需要什么级别的组件。

例如在一个SPA中,我可能有主页、文章列表页、文章页、个人中心页4个主要的视图,于是我将其分别对应的写成4个组件。

但是在实际编写的过程中,发现他们共用了同一套侧边栏,而侧边栏对应的代码也在4个组件中重复书写了4次。所以可以将侧边栏单独写成一个组件进行复用。

之后,我们可能发现可以复用的还有一些表单、按钮之类的内容我们都可以复用成组件。但实际上,我们也会发现过度的组件化会导致代码量上升、开发时间增加以及额外的数据传递等等。所以如果不打算制作一个完整的组件库,那么在实际项目中做到按需拆分、整合即可,不用过分的追求每个可复用的部分都写成单个组件。

为什么需要一个提示组件

因为alert大部分时间不能满足我们的需求啊。往往项目里需要一个类似于alert的东西,用美观、可定制的方式提示用户一些信息,因此这样一个提示组件很有必要。

同时,我们也不希望同一时间出现多个提示混淆用户,因此在设计上,我们将提示组件设定为具有 唯一性 ,整个应用中各个视图调用的都是同一个提示组件。

Show me the code

接下来,由简入繁依次实现提示组件的各个功能。

基本功能

最基本的功能当然是触发后显示,并且能够以某种方式关闭。唯一需要自定义的部分,就是具体显示的内容。所以最开始组件长这样:

<template>
 <div class="notification fixed"
 v-if="show"
 transition="slide">
 <div class="delete"
 @click="close()"></div>
 <div class="content">
 {{ options.content }}
 </div>
 </div>
</template>

<script>
export default {
 props: {
 options: {
 type: Object,
 default: () => {
 return {}
 }
 },
 show: {
 type: Boolean,
 default: false
 }
 },
 methods: {
 close () {
 this.show = false
 this.options = {}
 }
 }
}
</script>

<style scoped lang="sass">
 .slide-transition
 transition: all .3s ease
 transform: translate3d(0, 0, 0)
 .slide-enter,
 .slide-leave
 transform: translate3d(0, -100%, 0)
 .delete
 -moz-appearance: none
 -webkit-appearance: none
 background: rgba(51,51,51,0.2)
 cursor: pointer
 display: inline-block
 height: 24px
 position: relative
 vertical-align: top
 width: 24px
 float: right
 &:before,
 &:after
 background: #fff
 content: ""
 display: block
 height: 2px
 left: 50%
 margin-left: -25%
 margin-top: -1px
 position: absolute
 top: 50%
 width: 50%
 &:before
 transform: rotate(45deg)
 &:after
 transform: rotate(-45deg)
 &:hover
 background: rgba(51,51,51,0.5)
 .notification
 width: 100%
 line-height: 2
 z-index: 3
 position: fixed
 top: 0
 left: 0
 .content
 padding: .75rem 2rem
</style>

思路很简单,props传递两个数据,show用于控制显示,options传入包括内容在内的自定义内容。为了让提示的显示更加自然,添加了一个滑动进入和离开的transition。

注意:这里的关闭按钮是通过css实现的,如果在你的项目中有对应的icon,可以将其替换掉。

在此处,也可以使用slot来进行内容的传递,但考虑到之后还有别的参数需要传递至组件内,一次用一个统一的对象options进行传递。

自定义样式

通常提示的内容种类很多,有的是成功提示,有的是警告,有的则是报错。因此我们需要定义不同的样式以表达不同的内容。方法很简单,在options中传入背景色和文字颜色两个参数,如果组件中检测到了传入的样式参数,就用其替换默认样式。

Vue.js在处理动态样式时非常灵活,为了让代码更清晰,我没有选择将动态样式内联,而是单独使用一个计算属性setStyle进行设定:

computed: {
 setStyle () {
 return {
 color: this.options.textColor || '#fff',
 background: this.options.backgroundColor || '#21e7b6'
 }
 }
}

这样一来,只要在options中一并传入textColor和backgroundColor两个属性,就可以轻松自定义提示样式了。

自动关闭

很多时候,我们希望提示在一定时间之后可以自动关闭,因此组件也需要扩展出一个自动关闭的模式。同样的,在“数据驱动”的思想下,我们应该提供一个数据,用来表明这个提示是否自动关闭。

options中的autoClose属性就是这个作用。同样的,自动关闭的延迟时间显然也要能够自定义,因此还一同添加了showTime这一属性。

自动关闭本身不太复杂,我们只需要使用setTimeout,定义一个计时器即可。

首先是监听提示组件的显示。

在这里,我通过watch监听options的变化来处罚计时器。由于我们已经定义了一个close方法用于关闭计时器,并且在关闭时重置了show和options的值,所以在options变化时,只需要判断options中的autoClose是否为true,就能知道是否需要启动计时器了。这里单独使用一个countdown方法来处理定时器相关的操作。

新增代码如下:

data () {
 return {
 timers: []
 } 
},
methods: {
 countdown () {
 if (this.options.autoClose) {
 const t = setTimeout(() => {
 this.close()
 }, this.options.showTime || 3000)
 this.timers.push(t)
 }
 }
},
watch: {
 options () {
 this.timers.forEach((timer) => {
 window.clearTimeout(timer)
 })
 this.timers = []
 this.countdown()
 }
}

细心地你肯定会发现,这段代码中,有一些奇怪的处理。我们定义了一个空数组timers,并且每次开始一个计时器的时候,就把计时器存入数组中,而每次options变化时,我们也从timers中遍历所有计时器并取消,之后清空timers。

这个做法,主要是为了避免一个计时器还没有结束时,又开始一个新的提示所引发的提示被提前关闭的清空。举个例子,如果没有这样的处理,那么先发出一个自动关闭的提示,在其没自动关闭之前,就再发出一个新的提示。那么第一个提示的定时器依然会错误的关闭新提示。

这样的问题主要是由于我们所有的计时器都是在同一个组件中,本质上都是同一个提示,因此需要清除计时器,避免冲突。许多组件库中类似的功能组件,是采用每一条提示就新生成一个提示组件的方式来实现的。但是那样在多个提示连续出现时,就会出现堆叠在一起,又各自离开的情况。

之前的版本中,我的提示组件也采用了类似的设计方式,但是在最近的一个项目中,需要实现半透明的提示组件,就出现了堆叠后看不清提示文字的现象,才使用了现在新的模式。

进一步扩展

紧接着,我拓展了一个自动关闭模式下的倒计时条功能。思路上没有使用Vue.js的transition系统,而是采用了Css3本身的动画系统。在一个自动关闭的提示被初始化时,为计时条添加一个样式,效果是向X轴负方向移动100%,transition时间则通过计算属性对应设定。具体实现可以参考源代码,这里不多做赘述。

增强灵活性

最后则是让提示组件更灵活。有的时候,我们想展示的可能是可以自定义样式的文本、亦或是一个超链接甚至更多。而Vue.js实现起来不要太简单。我们只需要将组件中用于渲染的 {{ options.content }} 变为 {{{ options.content }}} 即可,对于3重花括号的模板,Vue.js会将其中的HTML标签按照正常内容渲染。

如此一来,我们就可以将任何HTML内容放入提示中了。 当然一定要注意避免将用户输入的内容渲染到3重花括号的模板中,避免XSS攻击。

结合vuex

很多时候,我们会把提示组件引入到App.vue这个根组件中,但是发出提示的可能是组件树中的任何一个组件。如果不想代码中遍布各种dispatch和broadcast,那么引入vuex来进行管理是个很好的方案。

大致的思路如下:

// store.js
const state = {
 show: false,
 options: {
 autoClose: false,
 content: 'notice content'
 }
}

const mutations = {
 NEW_NOTICE (state, options) {
 state.show = true
 state.options = options
 },
 CLOSE_NOTICE (state) {
 state.show = false
 state.options = {}
 }
}

// actions.js

export const newNotice = ({dispatch}, options) => {
 dispatch('NEW_NOTICE', options)
}
export const closeNotice = ({dispatch}) => {
 dispatch('CLOSE_NOTICE')
}

// Notification.vue

vuex: {
 getters: {
 show: state => state.show
 options: state => state.options
 },
 actions: {
 close: closeNotice
 }
}

// 任意调用notice的组件

vuex: {
 actions: {
 notice: newNotice
 }
}

引入vuex后,按上述代码进行配置,就可以在任意一处组件中,使用 this.notice({options}) 传递数据。不过由于vuex的单项数据流动特性,所有对state数据的操作都必须经过actions调用mutations实现,包括提示组件中的close方法也要替换成actions中的closeNotice方法。

综述

通过这个提示组件,我们更熟练的掌握了Vue.js的组件系统、数据传递、计算属性、transition动画等特性,另外此组件已经可以直接用于生产环境中。

本文已被整理到了《Vue.js前端组件学习教程》,欢迎大家学习阅读。

关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 事件处理程序介绍
Jun 27 Javascript
jQuery+css+html实现页面遮罩弹出框
Mar 21 Javascript
javascript随机将第一个dom中的图片添加到第二个div中示例
Oct 08 Javascript
JQ获取动态加载的图片大小的正确方法分享
Nov 08 Javascript
Javascript中String的常用方法实例分析
Jun 13 Javascript
JS与jQuery实现隔行变色的方法
Sep 09 Javascript
利用python分析access日志的方法
Oct 26 Javascript
Bootstrap table的使用方法
Nov 02 Javascript
详解webpack打包vue时提取css
May 26 Javascript
随机生成10个不重复的0-100的数字(实例讲解)
Aug 16 Javascript
vue模块拖拽实现示例代码
Mar 09 Javascript
vue导入.md文件的步骤(markdown转HTML)
Dec 31 Vue.js
js实现功能比较全面的全选和多选
Mar 02 #Javascript
jQuery实现三级联动效果
Mar 02 #Javascript
Spring Boot+AngularJS+BootStrap实现进度条示例代码
Mar 02 #Javascript
纯js仿淘宝京东商品放大镜功能
Mar 02 #Javascript
JSONP跨域请求
Mar 02 #Javascript
jquery easyui dataGrid动态改变排序字段名的方法
Mar 02 #Javascript
JavaScript正则替换HTML标签功能示例
Mar 02 #Javascript
You might like
第十四节 命名空间 [14]
2006/10/09 PHP
CI框架中通过hook的方式实现简单的权限控制
2015/01/07 PHP
ThinkPHP中获取指定日期后工作日的具体日期方法
2018/10/14 PHP
YII2框架中日志的配置与使用方法实例分析
2020/03/18 PHP
Gambit vs CL BO3 第三场 2.13
2021/03/10 DOTA
基于jquery自定义的漂亮单选按钮RadioButton
2013/11/19 Javascript
js怎么判断flash swf文件是否加载完毕
2014/08/14 Javascript
DOM节点的替换或修改函数replaceChild()用法实例
2015/01/12 Javascript
谈谈PHP中相对路径的问题与绝对路径的使用
2016/08/16 Javascript
ES6新特性之解构、参数、模块和记号用法示例
2017/04/01 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
2017/07/17 Javascript
Vue2.0实现将页面中表格数据导出excel的实例
2017/08/09 Javascript
node.js中stream流中可读流和可写流的实现与使用方法实例分析
2020/02/13 Javascript
[03:59]5分钟带你了解什么是DOTA2(第二期)
2017/02/07 DOTA
python动态监控日志内容的示例
2014/02/16 Python
Python 不同对象比较大小示例探讨
2014/08/21 Python
Python中的sort()方法使用基础教程
2017/01/08 Python
Python 关于反射和类的特殊成员方法
2017/09/14 Python
Pycharm 操作Django Model的简单运用方法
2018/05/23 Python
python实现微信每日一句自动发送给喜欢的人
2019/04/29 Python
python正则-re的用法详解
2019/07/28 Python
pytorch构建多模型实例
2020/01/15 Python
python同义词替换的实现(jieba分词)
2020/01/21 Python
TensorBoard 计算图的可视化实现
2020/02/15 Python
Python collections.deque双边队列原理详解
2020/10/05 Python
关于老式浏览器兼容HTML5和CSS3的问题
2016/06/01 HTML / CSS
CSS3 画基本图形,圆形、椭圆形、三角形等
2016/09/20 HTML / CSS
应届生骨科医生求职信
2013/10/31 职场文书
大学生职业生涯规划书的基本内容
2014/01/06 职场文书
交通事故检查书范文
2014/01/30 职场文书
法学毕业生自我鉴定
2014/01/31 职场文书
办公室副主任职责范本
2014/03/08 职场文书
知识竞赛主持词
2014/03/26 职场文书
党员干部廉洁承诺书
2014/05/28 职场文书
群众路线教育实践活动方案
2014/10/31 职场文书
《平行四边形的面积》教学反思
2016/02/16 职场文书