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里模拟sleep(两种实现方式)
Jan 25 Javascript
css transform 3D幻灯片特效实现步骤解读
Mar 27 Javascript
jQuery实现下拉框左右选择的简单实例
Feb 22 Javascript
深入分析JQuery和JavaScript的异同
Oct 23 Javascript
Javascript非构造函数的继承
Apr 27 Javascript
JavaScript中var关键字的使用详解
Aug 14 Javascript
详解javascript高级定时器
Dec 31 Javascript
jquery输入数字随机抽奖特效的简单实现代码
Jun 10 Javascript
微信小程序 石头剪刀布实例代码
Jan 04 Javascript
vue组件之Alert的实现代码
Oct 17 Javascript
详解JSONObject和JSONArray区别及基本用法
Oct 25 Javascript
使用JavaScript实现贪吃蛇游戏
Sep 29 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
Apache2 httpd.conf 中文版
2006/12/06 PHP
php中实现xml与mysql数据相互转换的方法
2014/12/25 PHP
PHP SPL标准库之SplFixedArray使用实例
2015/05/12 PHP
ThinkPHP框架分布式数据库连接方法详解
2017/03/14 PHP
jQuery实现form表单reset按钮重置清空表单功能
2012/12/18 Javascript
解决window.opener=null;window.close(),只支持IE6不支持IE7,IE8的问题
2014/01/14 Javascript
JS将所有对象s的属性复制给对象r(原生js+jquery)
2014/01/25 Javascript
html5+javascript制作简易画板附图
2014/04/25 Javascript
用javascript读取xml文件读取节点数据
2014/08/12 Javascript
Nodejs如何搭建Web服务器
2016/03/28 NodeJs
AngularJS 霸道的过滤器小结
2017/04/26 Javascript
webpack 开发和生产并行设置的方法
2018/11/08 Javascript
CryptoJS中AES实现前后端通用加解密技术
2018/12/18 Javascript
Vue项目中配置pug解析支持
2019/05/10 Javascript
微信小程序地图绘制线段并且测量(实例代码)
2020/01/02 Javascript
从0搭建vue-cli4脚手架
2020/06/17 Javascript
[07:06]2018DOTA2国际邀请赛寻真——卫冕冠军Team Liquid
2018/08/10 DOTA
python操作xml文件示例
2014/04/07 Python
Python实现备份文件实例
2014/09/16 Python
Python模块搜索概念介绍及模块安装方法介绍
2015/06/03 Python
Python找出文件中使用率最高的汉字实例详解
2015/06/03 Python
Python中文分词实现方法(安装pymmseg)
2016/06/14 Python
Python3利用print输出带颜色的彩色字体示例代码
2019/04/08 Python
介绍一款python类型检查工具pyright(推荐)
2019/07/03 Python
python中的反斜杠问题深入讲解
2019/08/12 Python
Python在OpenCV里实现极坐标变换功能
2019/09/02 Python
Python+OpenCV实现将图像转换为二进制格式
2020/01/09 Python
tensorflow将图片保存为tfrecord和tfrecord的读取方式
2020/02/17 Python
Django启动时找不到mysqlclient问题解决方案
2020/11/11 Python
css3media响应式布局实例
2016/07/08 HTML / CSS
马来西亚演唱会订票网站:StubHub马来西亚
2018/10/18 全球购物
音乐教师求职信
2014/06/28 职场文书
写得不错的求职信范文
2014/07/11 职场文书
学校安全工作汇报材料
2014/08/16 职场文书
一年级班主任工作总结2014
2014/11/08 职场文书
什么是创业计划书?什么是商业计划书?这里一一解答
2019/07/12 职场文书