Angular2组件与指令的小实践——实现一个图片轮播组件
如果说模块系统是Angular2的灵魂,那其组件体系就是其躯体,在模块的支持下渲染出所有用户直接看得见的东西,一个项目最表层的东西就是组件呈现的视图。
而除了直接看的见的躯体之外,一个完整的“生物”还需要有感觉器官,用来感知外界与其的交互,这就是指令要做的事情。
本文将使用Angular2提供的强大的组件与指令等功能制作出一个简单的图片轮播控件,继续上文打的比方的话这就像是一个“器官”,功能是呈现图片,并感知用户的点击或手势来切换图片。
一、创建组件
结束上文打的尴尬的比方,着眼于一个待开发的ng2项目,它有一个空白的特性页面,现在需要在上面呈现一个图片轮播窗口。
图片轮播是一个需要给用户看见的东西,所以应该使用ng2的组件(Component)来实现它,并且这个功能较为通用,可以将其独立出来方便以后再次使用到。
所以在项目中的共享模块(SharedModule)下创建这个组件名为 slide-img.component。
使用ng2提供的组建装饰器来将这个TypeScript模块正式变身成ng2的组件:
1 @Component({ 2 selector: 'my-slide-img', 3 templateUrl: 'slide-img.component.html', 4 styleUrls: ['slide-img.component.css'], 5 animations: [ 6 trigger('imgMove', [ 7 /** 不显示 */ 8 state('off', style({'display': 'none', 'z-index': '0', 'transform': 'translateX(0)'})), 9 /** 上一张图片 */ 10 state('prev', style({'z-index': '1', 11 'transform': 'translateX(-100%)'})), 12 /** 下一张图片 */ 13 state('next', style({'z-index': '2', 'transform': 'translateX(100%)'})), 14 /** 当前图片 */ 15 state('on', style({'z-index': '3', 'transform': 'translateX(0)'})), 16 transition('prev=>on', [ 17 animate('0.3s ease-in') 18 ]), 19 transition('next=>on', [ 20 animate('0.3s ease-in') 21 ]), 22 transition('on=>prev', [ 23 animate('0.3s ease-in') 24 ]), 25 transition('on=>next', [ 26 animate('0.3s ease-in') 27 ]) 28 ]) 29 ] 30 }) 31 export class SlideImgComponent { }
组件的声明
其参数其实已经不能再明确了:
selector就是其使用时的标签名,
templateUrl即组件关联的界面的模板,
styleUrls即仅在此组件内生效的样式表,
animations定义的是一套ng2动画规则。
讲讲最后的这个动画规则:
ng2的动画其实非常简单,步骤为1.定义触发器名,2.定义状态,3.定义切换样式,4.将此触发器应用到具体的标签中,状态作为触发器的值传入。
当ng2检测到动画状态的值更改了,就会套用定义的切换样式,用法思路还算比较明确(当然实际使用时会有一些尴尬的小问题)
二、实现组件
既然是轮播图片组件,要做的事情首先就得是传入轮播图片然后显示出来。
使用过ng1的朋友一定还记得其在定义指令(angular.directive)的时候是通过scope参数(或者link)来传入数据的,而ng2中使用的是Input装饰器,使用的方法如下:
@Input() public imgs: SlideImg[];
使用了此装饰器的变量imgs将可以在运行时接收其他组件传入的图片列表。使用方法如下:
<my-slide-img [imgs]="imgs"></my-slide-img>
关于这里的方括号“[]”,ng2其实提供了多种方式来进行组件模板中值的传入,其中这种变量名用方括号包起来的方法就是其中之一,代表是输入的值,而后面会见到的圆括号来包围的方式,是代表输出的值。
传入了数据后,下一步就是要如何来显示图片到界面上了,没错就是ng1中ng-for指令的升级版*ngFor,除了写法外表面上的差别不大。
关于轮播图片逻辑的具体实现逻辑,笔者使用的方式就是利用ng2动画的状态切换,设置一个当前图片索引值current,*ngFor渲染的图片将其索引与当前索引比较,如果是相邻的图片则设为'prev'状态与'next'状态,ng2会为其加上位置属性为-100%或者100%,如果是当前图片则设为'on'状态,ng2会将其的位置属性设为0,其余均设为'off'状态,ng2会直接将其隐藏,实现的逻辑很简单,考虑也不算周全,笔者就不继续解释献丑了。
最终的轮播图片组件及其模板文件代码如下:
1 <div class="imgs"> 2 <img src="{{img.Url}}" alt="" class="img" 3 *ngFor="let img of imgs;let i=index" 4 (mySwipe)="Change($event)" 5 [@imgMove]="ImgState(i)"> 6 </div> 7 8 <div class="btn" (click)="Prev()">Prev</div> 9 <div class="btn" (click)="Next()">Next</div>
slide-img.component.html
1 .imgs{ 2 position: relative;width: 100%;height: 15em; 3 overflow: hidden; 4 } 5 .img{ 6 position: absolute; 7 width: 100%; 8 height: 100%; 9 background: pink; 10 transition: 0.2s; 11 } 12 .btn{ 13 display: inline-block; 14 padding: 1em 2em;font-size: 1em;border-radius: 0.5em; 15 border: 1px solid #ddd;cursor: pointer; 16 margin: 1em;background: #eee;box-shadow: 0.1em 0.1em 0.2em #aaa; 17 } 18 .btn:active{ 19 background: #eee; 20 box-shadow: none; 21 }
slide-img.component.css
1 import { Component, OnInit, Input, 2 animate, 3 style, 4 transition, 5 trigger, 6 state, 7 HostListener 8 } from '@angular/core'; 9 import { SlideImg } from './slide-img.interface'; 10 11 @Component({ 12 selector: 'my-slide-img', 13 templateUrl: 'slide-img.component.html', 14 styleUrls: ['slide-img.component.css'], 15 animations: [ 16 trigger('imgMove', [ 17 /** 不显示 */ 18 state('off', style({'display': 'none', 'z-index': '0', 'transform': 'translateX(0)'})), 19 /** 上一张图片 */ 20 state('prev', style({'z-index': '1', 21 'transform': 'translateX(-100%)'})), 22 /** 下一张图片 */ 23 state('next', style({'z-index': '2', 'transform': 'translateX(100%)'})), 24 /** 当前图片 */ 25 state('on', style({'z-index': '3', 'transform': 'translateX(0)'})), 26 transition('prev=>on', [ 27 animate('0.3s ease-in') 28 ]), 29 transition('next=>on', [ 30 animate('0.3s ease-in') 31 ]), 32 transition('on=>prev', [ 33 animate('0.3s ease-in') 34 ]), 35 transition('on=>next', [ 36 animate('0.3s ease-in') 37 ]) 38 ]) 39 ] 40 }) 41 export class SlideImgComponent { 42 @Input() public imgs: SlideImg[]; 43 public current; 44 constructor() { 45 this.current = 0; 46 } 47 public ImgState(index) { 48 if (this.imgs && this.imgs.length) { 49 if (this.current === 0) { 50 return index === 0 ? 'on' : 51 index === 1 ? 'next' : 52 index === this.imgs.length - 1 ? 'prev' : 53 'off'; 54 } else if (this.current === this.imgs.length - 1) { 55 return index === this.imgs.length - 1 ? 'on' : 56 index === this.imgs.length - 2 ? 'prev' : 57 index === 0 ? 'next' : 58 'off'; 59 } 60 switch (index - this.current) { 61 case 0: 62 return 'on'; 63 case 1: 64 return 'next'; 65 case -1: 66 return 'prev'; 67 default: 68 return 'off'; 69 } 70 } else { 71 return 'off'; 72 } 73 } 74 public Next() { 75 this.current = (this.current + 1) % this.imgs.length; 76 } 77 public Prev() { 78 this.current = this.current - 1 < 0 ? this.imgs.length - 1 : this.current - 1; 79 } 80 81 public Change(e) { 82 if (e === 'left') { 83 this.Next(); 84 } else if (e === 'right') { 85 this.Prev(); 86 } 87 } 88 }
slide-img.component.ts
其中有两个地方为讲到,一个是组件代码引入了一个slide-img.interface 模块,这个仅仅用来规范一下轮播图片的格式,二是在html中还有一个节点名为(mySwipe)这就是接下来要讲的输出属性,目前知道的它的作用是,当用户滑动图片时,将触发此节点配置的回调方法,所做的事情就是判断发生了左滑事件还是右滑事件,分别触发上一张图或下一张图的切换。
三、给轮播图片控件加上手势效果
轮播图片在移动端很需要加上手势滑动的效果,所以接下来要给这个轮播组件加上一个指令,用于响应用户的滑动手势。代码如下:
1 import { Directive, Input, HostListener, Output, EventEmitter } from '@angular/core'; 2 3 @Directive({ selector: '[mySwipe]' }) 4 export class SwipeDirective { 5 @Output() public mySwipe = new EventEmitter<string>(); 6 7 private touchStartX; 8 private touchStartY; 9 @HostListener('touchstart', ['$event']) public onTouchStart(e) { 10 this.touchStartX = e.changedTouches[0].clientX; 11 this.touchStartY = e.changedTouches[0].clientY; 12 } 13 @HostListener('touchend', ['$event']) public onTouchEnd(e) { 14 let moveX = e.changedTouches[0].clientX - this.touchStartX; 15 let moveY = e.changedTouches[0].clientY - this.touchStartY; 16 if (Math.abs(moveY) < Math.abs(moveX)) { 17 /** 18 * Y轴移动小于X轴 判定为横向滑动 19 */ 20 if (moveX > 50) { 21 this.mySwipe.emit('right'); 22 } else if (moveX < -50) { 23 this.mySwipe.emit('left'); 24 } 25 } else if (Math.abs(moveY) > Math.abs(moveX)) { 26 /** 27 * Y轴移动大于X轴 判定为纵向滑动 28 */ 29 if (moveY > 50) { 30 this.mySwipe.emit('down'); 31 } else if (moveY < -50) { 32 this.mySwipe.emit('up'); 33 } 34 } 35 this.touchStartX = this.touchStartY = -1; 36 } 37 }
swipe.directive.ts
指令的声明甚至简单过组建的声明,因为指令不需要依赖于某个视图模板,只需要有个指令名称就足够了。
需要关心的是指令中定义的输出属性:
@Output() public mySwipe = new EventEmitter<string>();
此属性接收了上文组件中的Change($event)回调方法,在此指令中,所做的事情就是监听组件的滑动,收到滑动事件后就触发这个回调,监听使用的是ng2的HostListener装饰器,用法显而易见了。
现在运行起项目来看看效果吧(比较懒就不截动图了):
总结以及题外话:
本文主要使用了ng2几个比较基本的功能——输入属性(Input装饰器)、输出属性(Outut装饰器)、HostListener装饰器、几个系统指令(ngFor)、ng2动画实现了一个比较基本的图片轮播控件。
使用好ng2的组件以及指令能完成很多的事情,其需要学习的东西绝不仅限与本文提到的,包括其底层的渲染,也很值得去研究。
最后提一个尴尬的问题点:
其实最初写这个轮播图片的时候想过要加上拖动的,也就是图片会随手势的滑动实时更新位置。
但后来发现ng2的动画有个尴尬的地方,那就是一定会从初始状态按照定义好的转换效果变化到目标状态。实时滑动需要我在滑动过程中就改变图片的位置,这样的话在滑动结束需要切换图片时,图片居然强行回到了初始位置然后才开始转换动画,一时还想不到继续使用ng2动画来实现这种实时滑动的完美解决办法,实在是尴尬。
转载于:https://www.cnblogs.com/yitim/p/angular2-component-slide-img.html
Angular2组件与指令的小实践——实现一个图片轮播组件相关推荐
- bootstrap 轮播控制时间_【前端冷知识】如何封装一个图片轮播组件
组件封装是一个前端工程师进阶的必经之路.组件封装是指Web页面上抽出来一个个包含模版(HTML).功能(Javascript)和样式(CSS)的单元.所以,今天的内容,我们将带你了解组件封装的开发思路 ...
- vue 实现无限轮播_使用Vue制作图片轮播组件思路详解
之前一直都没有认真的写过一个组件.以前在写业务代码的过程中,都是用的别人封装好的组件,这次尝试着写了一个图片轮播组件,虽然比不上知名的轮播组件,但它的功能基本完整,而且在写这个组件的过程中,学的东西也 ...
- android 图片轮播组件,Android客户端实现图片轮播控件
本文和大家一起写一个Android图片轮播控件,供大家参考,具体内容如下 1. 轮播控件的组成部分 我们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成: 首先我们要有用来显示 ...
- 造轮子之图片轮播组件(swiper)
图片轮播是种很常见的场景和功能,一般移动网站首页的轮播 banner,商品详情页的商品图片等位置都会用到此功能 像这种常用的场景功能肯定是有人早就写好插件了的,所以遇到这种场景,一般都遵循以下三步: ...
- unity实现图片轮播效果_Unity实现图片轮播组件
游戏中有时候会见到图片轮播的效果,那么这里就自己封装了一个,包括自动轮播.切页按钮控制.页码下标更新.滑动轮播.切页后的回调等等 . 下面,先上一个简陋的gif动态效果图 从图中可以看出,该示例包括了 ...
- Omi-touch实战 移动端图片轮播组件的封装
pc端的轮播,移动端的轮播都很常见.一年前,我还为手机端没有左滑,右滑事件从而封装了一个swipe库,可以自定义超过多少滑动时间就不触发,也可以设置滑动多少距离才触发,这一个功能的代码就达到400多行 ...
- Vue——图片轮播组件
Notices: 这是我一个项目中的一个子组件,要展示的数据.图片地址等的都在父组件data中.所以后面的讲述都是基于从父组件获取的参数进行处理.(如需将这个SlideShow写成一个单独的主组件,将 ...
- Unity之图片轮播组件实现
博客迁移 个人博客站点,欢迎访问,www.jiingfengji.tech 正文 游戏中有时候会见到图片轮播的效果,那么这里就自己封装了一个,包括自动轮播.切页按钮控制.页码下标更新.滑动轮播.切页后 ...
- 微信小程序----开发rui-swiper多样式轮播组件
swiper详解 滑块视图容器.swiper的初始化高度为150px;swiper-item的初始高度和宽度为100%;都可通过css样式进行swiper.swiper-item的样式重置.swipe ...
最新文章
- mysql udf http.so_MySQL-UDF-HTTP + Express + WebSocket 实现数据库推送
- linux 内核调试方法
- 人工智能技术类资源汇聚
- 科学前进的车轮永不停歇 2018-04-28
- 扫地机器人水箱背景_水箱尘盒组件及扫地机器人的制作方法
- 全向轮机器人应用平台
- NeatUpload的安装使用 文件上传。可传大文件。
- 网络邻居没有查看工作组计算机,为什么网上邻居内看不到计算机工作组
- 已知两边求角度公式_已知三边求角度公式
- 【PyG】文档总结以及项目经验(持续更新
- 如何免费建立个人博客网站?
- Android系统epub阅读器分享
- 迈向云原生开发,我眼中的云原生
- UnityShader学习教程之<详解uv坐标,c#类似uv坐标的值以及贴图操作>
- win10每次开机后,D、E、F盘就不见了,需要进入“磁盘管理”重新分配
- VSLAM与VIO的3D建图,重定位与世界观综述
- 为什么现在用的otm8018b型LCD屏的ID不能被读取?
- (已解决)ModuleNotFoundError: No module named ‘pycocotools‘
- AcWing 158. 项链
- java list 分组数量_java8 集合 多字段 分组 统计个数代码