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控制网页层收起和展开效果的方法
Apr 15 Javascript
JQuery中节点遍历方法实例
May 18 Javascript
js+html5绘制图片到canvas的方法
Jun 05 Javascript
JS模态窗口返回值兼容问题的完美解决方法
May 28 Javascript
textarea 在浏览器中固定大小和禁止拖动的实现方法
Dec 03 Javascript
详解vue事件对象、冒泡、阻止默认行为
Mar 20 Javascript
ES6中的箭头函数实例详解
Apr 06 Javascript
Angular.Js中过滤器filter与自定义过滤器filter实例详解
May 08 Javascript
react路由配置方式详解
Aug 07 Javascript
JavaScript封装的常用工具类库bee.js用法详解【经典类库】
Sep 03 Javascript
微信小程序 调用微信授权窗口相关问题解决
Jul 25 Javascript
react的hooks的用法详解
Oct 12 Javascript
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
Oracle Faq(Oracle的版本)
2006/10/09 PHP
php stream_get_meta_data返回值
2013/09/29 PHP
PHP面向对象五大原则之接口隔离原则(ISP)详解
2018/04/04 PHP
日期 时间js控件
2009/05/07 Javascript
Extjs 3.3切换tab隐藏相应工具栏出现空白解决
2013/04/02 Javascript
js(jQuery)获取时间的方法及常用时间类搜集
2013/10/23 Javascript
jquery获取html元素的绝对位置和相对位置的方法
2014/06/20 Javascript
JavaScript立即执行函数的三种不同写法
2014/09/05 Javascript
js点击文本框后才加载验证码实例代码
2015/10/20 Javascript
js窗口关闭提示信息(兼容IE和firefox)
2015/10/23 Javascript
全面解析JavaScript里的循环方法之forEach,for-in,for-of
2020/04/20 Javascript
JS快速实现移动端拼图游戏
2016/09/05 Javascript
Vue中如何实现轮播图的示例代码
2017/07/27 Javascript
详解vue axios用post提交的数据格式
2018/08/07 Javascript
关于AOP在JS中的实现与应用详解
2019/05/06 Javascript
jQuery实现本地存储
2020/12/22 jQuery
Python求出0~100以内的所有素数
2018/01/23 Python
Python for循环中的陷阱详解
2018/07/13 Python
Python+Pandas 获取数据库并加入DataFrame的实例
2018/07/25 Python
django 将model转换为字典的方法示例
2018/10/16 Python
PyQt5 QListWidget选择多项并返回的实例
2019/06/17 Python
python的几种矩阵相乘的公式详解
2019/07/10 Python
python调用接口的4种方式代码实例
2019/11/19 Python
python pandas移动窗口函数rolling的用法
2020/02/29 Python
家具促销活动方案
2014/02/16 职场文书
读群众路线的心得体会
2014/09/03 职场文书
微笑面对生活演讲稿
2014/09/23 职场文书
项目合作意向书
2015/05/08 职场文书
家长意见和建议怎么写
2015/06/04 职场文书
党员转正大会主持词
2015/07/02 职场文书
小学数学教师研修日志
2015/11/13 职场文书
《鸡兔同笼》教学反思
2016/02/19 职场文书
python glom模块的使用简介
2021/04/13 Python
PyQt5爬取12306车票信息程序的实现
2021/05/14 Python
Python中的socket网络模块介绍
2022/07/23 Python
win10截图快捷键win+shift+s没有反应无法截图怎么解决?
2022/08/14 数码科技