pc端的轮播,移动端的轮播都很常见。一年前,我还为手机端没有左滑,右滑事件从而封装了一个swipe库,可以自定义超过多少滑动时间就不触发,也可以设置滑动多少距离才触发,这一个功能的代码就达到400多行了,当我遇到finger.js后,就直接抛弃自己写的那个库了。

扯了那么多,是时候进入正题,这里用touch插件来写一个轮播组件的封装。

使用姿势如下:

        var banner = new Banner({
images: ['ci5.jpg', 'ci6.jpg', 'ci7.jpg', 'ci8.jpg'],
title: ['原来你不爱我-威仔', '八年的爱', '终结敷衍', '我也憧憬过'],
defaultIndex: 2,
imgPath: './images/',
style: {
height: '210px',
}
}); setTimeout(() => {
banner.setData({
images: ['47.jpg', '48.jpg', '49.jpg'],
title: ['怪我', '异性朋友', '我很快乐'],
defaultIndex: 3,
imgPath: './images/',
style: {
height: '220px',
top: '10%'
}
})
}, 1000);

说明:实例化轮播对象时,可以传入数据。

images: 图片名,

title: 标题,

defaultIndex: 轮播默认显示第几个图,

imgPath: 图片的路径(为了你方便少写点重复的路径名),

style: 样式, height:指轮播图的高度, top指轮播距离屏幕顶部的距离,单位随意,可以px, rem, %.

有时候换数据,则使用实例的setData方法,传入参数即可,轮播会自己换数据和title.

来看看具体实现:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>touch_banner</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
</head>
<body>
<script src="../src/omi_soda.js"></script>
<script>
Omi.OmiTouch.init();
class Banner extends Omi.Component {
constructor(data) {
super(data);
this.bannerVar = {
aA: null,
at: null,
tickId: null
};
this.data.imgWidth = this.data.imgCount = this.data.divWidth = this.data.minValue = 0;
this.setData(null, true);
} installed() {
this.bannerVar.aA = this.refs.aTagDiv.getElementsByTagName('a');
this.fixDefaultIndexImage();
this.fixStyle();
} setData(option, first) {
clearInterval(this.bannerVar.tickId);
option = option || this.data;
if (option.imgPath) {
option.images = option.images.map(function(imgDom) {
return option.imgPath + imgDom;
});
};
this.data.title = option.title;
this.data.images = option.images;
this.data.style = option.style;
if (option.defaultIndex >= 0 && option.defaultIndex <= option.images.length - 1) {
this.data.defaultIndex = option.defaultIndex;
} else {
this.data.defaultIndex = 0;
};
this.data.imgCount = option.images.length;
this.data.imgWidth = 100 / this.data.imgCount;
this.data.divWidth = 100 * this.data.imgCount;
this.data.minValue = -(window.innerWidth) * (this.data.imgCount - 1);
this.touch && (this.touch.min = -(window.innerWidth) * (this.data.imgCount - 1)); if (!first) {
banner.update();
this.fixDefaultIndexImage();
this.fixStyle();
};
} fixDefaultIndexImage() {
this.touch.currentPage = this.data.defaultIndex;
this.touch.to(- (this.touch.currentPage)*(this.touch.step));
this.animationEnd();
this.loop();
} fixStyle() {
if (this.data.style && this.data.style.top) this.refs.carousel_container.style.top = this.data.style.top;
if (this.data.style && this.data.style.height) {
var aImg = Array.prototype.slice.call(this.refs.scroller.getElementsByTagName('img'));
aImg.forEach(function(img) {
img.style.height = this.data.style.height;
}, this);
};
} style() {
return `
.carousel_container {
position: absolute;
top: 0%;
}
.carousel {
overflow: hidden;
position: relative;
}
.carousel_div {
position: relative;
font-size: 0;
}
.nav {
position: absolute;
bottom: .3rem;
right: .5rem;
}
.nav a {
display: inline-block;
width: 6px;
height: 6px;
background: #ffffff;
cursor: pointer;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: 1px solid #808080;
transition: all .5s ease-in;
margin: 0 .15rem;
}
.nav a.active {
background-color: #ffd800;
width: 10px;
}
.title {
position: absolute;
bottom: .0rem;
left: .3rem;
color: #fff;
width: auto;
height: 1.8rem;
line-height: 1.8rem;
font-size: 15px;
/*background: red;*/
}
`;
} touchStart() {
clearInterval(this.bannerVar.tickId);
} touchEnd(evt, v, index) {
var value = -(this.touch.step * index);
var dt = v - value;
// console.log(dt); if (v > this.touch.max) { // 属性值大于最大值取最大值
this.touch.to(this.touch.max);
/*this.touch.target.translateX = this.touch.min + this.touch.step;
this.touch.to(this.touch.min);*/
} else if (v < this.touch.min) { // 属性值小于最小值取最小值
this.touch.to(this.touch.min);
/*this.touch.target.translateX = -this.touch.step;
this.touch.to(this.touch.max);*/
} else if (Math.abs(dt) < 30) { // 2边空隙小于30就回到当前值
this.touch.to(value);
} else if (dt > 0) { // 大于0往右边滚动一个
this.touch.to(value + this.touch.step);
} else { // 小于0就往左边滚动一个
this.touch.to(value - this.touch.step);
};
this.loop();
return false;
} animationEnd(v) {
Array.prototype.slice.call(this.bannerVar.aA).forEach(function(item) {
item.className = '';
});
this.bannerVar.aA[this.touch.currentPage].className = 'active';
this.refs.title.innerHTML = this.data.title[this.touch.currentPage];
} // 循环播放
loop() {
this.bannerVar.tickId = setInterval(function() {
this.touch.currentPage += 1;
if (this.touch.currentPage > this.data.imgCount - 1) {
this.touch.currentPage = 0;
this.touch.target.translateX = -this.touch.step;
};
this.touch.to(-(this.touch.currentPage * this.touch.step));
}.bind(this), 2000);
} render() {
return `
<div omi-touch ref="carousel_container" motionRef="scroller" touchInstance="touch" vertical="false" property="translateX" max="0" step="window.innerWidth" min="{{minValue}}" touchStart="touchStart" touchEnd="touchEnd" animationEnd="animationEnd" class="carousel_container">
<div class="carousel">
<div ref="scroller" style="width: {{divWidth}}%" class="carousel_div">
<img o-repeat="imgItem in images" style="width: {{imgWidth}}%" src="{{imgItem}}">
</div>
<div id="nav" class="nav" ref="aTagDiv">
<a o-repeat="aItem in images" data-index="{{$index}}" class=" "></a>
</div>
<div class="title">
<span ref="title"></span>
</div>
</div>
</div>
`;
}
}; var banner = new Banner({
images: ['ci5.jpg', 'ci6.jpg', 'ci7.jpg', 'ci8.jpg'],
title: ['原来你不爱我-威仔', '八年的爱', '终结敷衍', '我也憧憬过'],
defaultIndex: 2,
imgPath: './images/',
style: {
height: '210px',
}
}); setTimeout(() => {
banner.setData({
images: ['47.jpg', '48.jpg', '49.jpg'],
title: ['怪我', '异性朋友', '我很快乐'],
defaultIndex: 3,
imgPath: './images/',
style: {
height: '220px',
top: '10%'
}
})
}, 1000); setTimeout(() => {
banner.setData({
images: ['47.jpg', '48.jpg', '49.jpg', '50.jpg'],
title: ['怪我', '异性朋友', '我很快乐', '隔阂'],
defaultIndex: 3,
imgPath: './images/',
style: {
height: '220px',
top: '20%'
}
})
}, 2000); setTimeout(() => {
banner.setData({
images: ['47.jpg', '48.jpg', '49.jpg', '50.jpg', '48.jpg'],
title: ['怪我', '异性朋友', '我很快乐', '隔阂', '如果这是命'],
defaultIndex: 3,
imgPath: './images/',
style: {
height: '250px',
top: '30%'
}
})
}, 3000); setTimeout(() => {
banner.setData({
images: ['47.jpg', '48.jpg', '49.jpg', '50.jpg', '48.jpg', '51.jpg'],
title: ['怪我', '异性朋友', '我很快乐', '隔阂', '如果这是命', '别爱'],
defaultIndex: 3,
imgPath: './images/',
style: {
height: '270px',
top: '40%'
}
})
}, 4000); Omi.render(banner, 'body');
</script>
</body>
</html>

注意:

使用dnt原作者的omi-touch,以上代码并不能成功运行。

原因: 1. AlloyTouch 的实例没有抛出,或者挂在到Component实例对象上去。

(改进版的,挂在到实例上去了,用户可以指定实例名,不指定会自动生成一个touchInstancs+id , id自增)

2. dom上的属性,只能是字符串,原作者只是简单的把字符串转换为数值,其实也够用了,也许当时作者没想太多。

(改进版的,属性名对应的属性值可以是任意表达式,会自动计算的)

3. 组件每一次更新时,都会实例化一个AlloyTouch对象,比较浪费

(改进版的,如果实例名一样的话,则不再重新实例化,只需把要运动的属性值更新即可)

说了那么多废话,上一下omi-touch源码(已修改部分代码,但是不会影响别的)

    (function () {

        var OmiTouch = {};    // OmiTouch集合对象
var AlloyTouch = Omi.AlloyTouch;
var Transform = Omi.Transform; var noop = function() { }; // 空函数
OmiTouch._instanceId = 0; // touch实例id
OmiTouch.getInstanceId = function () {
return OmiTouch._instanceId ++; // 自增
};
var preTouchInstanceName = null; // 获取绑定的函数
var getHandler = function(name, dom, instance) { // name: 属性值, dom: 反馈触摸的dom, instance实例
var value = dom.getAttribute(name); // 获取属性值
if (value === null) { // 没有函数就绑定noop空函数
return noop;
}else{
return instance[value].bind(instance); // 否则返回一个新函数
}
}; // 获取数值
/* var getNum = function(name, dom){ // name: 属性值, dom: 反馈触摸的dom
var value = dom.getAttribute(name); // 获取属性值
if (value) {
return parseFloat(value); // 把字符串转成数字返回
};
};*/ var getNum = function(name, dom){ // name: 属性值, dom: 反馈触摸的dom
var value = eval('(' + dom.getAttribute(name) + ')'); // 获取属性值 return Object.prototype.toString.call(value) !== '[object Null]' ? value : undefined;
}; OmiTouch.init = function(){
Omi.extendPlugin('omi-touch',function(dom, instance){
var target = instance.refs[dom.getAttribute('motionRef')]; // 找到要运动的dom
var touchInstanceName = dom.getAttribute('touchInstance') || 'touchInstance' + OmiTouch.getInstanceId(); // 获取touch实例名, 默认touchInstance+id 自增
Transform(target, target.getAttribute('perspective') ? false : true); // 不在运动对象上写perspective属性,默认不要透视(perspective="true/false" 则开启透视,只有不写才关闭)
var initialValue = dom.getAttribute('initialValue'); // 初始值
if (initialValue) {
target[dom.getAttribute('property') || "translateY"] = parseInt(initialValue); // 默认有初始值,是上下滑动
}; if (preTouchInstanceName !== touchInstanceName) { // 实例名一样的话,就没必要重新生成实例了
instance[touchInstanceName] = new AlloyTouch({
touch: dom,//反馈触摸的dom
vertical: dom.getAttribute('vertical') === 'false' ? false : true,//不必需,默认是true代表监听竖直方向touch
target: target, //运动的对象
property: dom.getAttribute('property') || "translateY", //被运动的属性
min: getNum('min', dom), //不必需,运动属性的最小值
max: getNum('max', dom), //不必需,滚动属性的最大值
sensitivity: getNum('sensitivity', dom) ,//不必需,触摸区域的灵敏度,默认值为1,可以为负数
factor: getNum('factor', dom) ,//不必需,表示触摸位移与被运动属性映射关系,默认值是1
step: getNum('step', dom),//用于校正到step的整数倍
bindSelf: dom.getAttribute('bindSelf') === 'true' ? true : false,
touchStart: getHandler('touchStart', dom, instance),
change: getHandler('change', dom, instance),
touchMove: getHandler('touchMove', dom, instance),
touchEnd: getHandler('touchEnd', dom, instance),
tap: getHandler('tap', dom, instance),
pressMove: getHandler('pressMove', dom, instance),
animationEnd: getHandler('animationEnd', dom, instance)
});
preTouchInstanceName = touchInstanceName;
}; });
} OmiTouch.destroy = function() { // 从Omi的插件集合移除该插件
delete Omi.plugins['omi-touch'];
}; Omi.OmiTouch = OmiTouch;
})();

这样就可以了,虽然改了些库代码。

Omi-touch实战 移动端图片轮播组件的封装的更多相关文章

  1. iOS开发项目实战——Swift实现图片轮播与浏览

    近期開始开发一个新的iOS应用,自己决定使用Swift.进行了几天之后,发现了一个非常严峻的问题.那就是无论是书籍,还是网络资源,关于Swift的实在是太少了,随便一搜全都是OC实现某某某功能.就算是 ...

  2. 一分钟搞定AlloyTouch图片轮播组件

    轮播图也涉及到触摸和触摸反馈,同时,AlloyTouch可以把惯性运动打开或者关闭,并且设置min和max为运动区域,超出会自动回弹. 除了一般的竖向滚动,AlloyTouch也可以支持横向滚动,甚至 ...

  3. Angular2组件与指令的小实践——实现一个图片轮播组件

    如果说模块系统是Angular2的灵魂,那其组件体系就是其躯体,在模块的支持下渲染出所有用户直接看得见的东西,一个项目最表层的东西就是组件呈现的视图.而除了直接看的见的躯体之外,一个完整的" ...

  4. 如何将angular-ui的图片轮播组件封装成一个指令

    在项目开发中我们经常会遇到图片轮播的功能点: 如果我们开发人员自己原生手写,将会花费很多的时间,最终得不偿失. 接下来就详细说说如何使用angular-ui发热图片轮播模块,并且将它写成一个指令(便于 ...

  5. Vue学习—Vue写一个图片轮播组件

    1.先看效果: 熟悉的图片轮播,只要是个网站,百分之90以上会有个图片轮播.我认为使用图片轮播. 第一可以给人以一种美观的感受,而不会显得网站那么呆板, 第二可以增加显示内容,同样的区域可以显示更多内 ...

  6. 如何将angular-ui-bootstrap的图片轮播组件封装成一个指令

    在项目开发中我们经常会遇到图片轮播的功能点: 如果我们开发人员自己原生手写,将会花费很多的时间,最终得不偿失. 接下来就详细说说如何使用angular-ui发热图片轮播模块,并且将它写成一个指令(便于 ...

  7. 移动端图片轮播效果:depth模式总结

    最近公司app改版首页增加了一处轮播图效果,但是跟普通的轮播效果不同,是类似于下图的样式,找了一些兼容移动端的插件以及jQuery源码,总结一下使用心得: 1:jquery源码:缺点是在手机端的滑动很 ...

  8. 移动端图片轮播—swipe滑动插件

    swipe是一个轻量级的移动滑动组件,它可以支持精确的触滑移动操作,能解决移动端对滑动的需求. swipe插件的使用主要有四大块: 一.html <div id='slider' class=' ...

  9. JavaScript实现图片轮播组件

    效果: 自动循环播放图片,下方有按钮可以切换到对应图片. 添加一个动画来实现图片切换. 鼠标停在图片上时,轮播停止,出现左右两个箭头,点击可以切换图片. 鼠标移开图片区域时,从当前位置继续轮播. 提供 ...

随机推荐

  1. javascript基础知识学习

    javascript中几种基础函数的介绍 1.typeof 注意: ① typeof 是操作符,不是函数: ② typeof 操作符 接收一个参数,用来判断参数数据类型,存在六种返回值类型,非别是:u ...

  2. 微信小程序下拉框之二维数组或对象

    在项目中,我们大多数时候传的值并不是需要这个下标,而是其他的值.像我项目中,需要获取到的是它对应的Id,那么我们如何通过它的这个下标值返回你想要的值呢? 通过picker返回的索引值,去获取匹配你想获 ...

  3. 【读书笔记】iOS-动态类型和动态绑定

    id是泛类型,可以用来存放各种类型的对象,使用id也就是使用“动态类型”. 动态类型,就是指,对象实际使用的是哪一个类是在执行期间确定的,而非在编译期间. 虽然id类型可以定义任何类型的对象,但是不要 ...

  4. HTML中令人惊喜的全局属性

    1.accesskey 属性 : 规定激活元素的快捷键. 浏览器支持:几乎所有浏览器均 accesskey 属性,除了 Opera. 定义和用法 accesskey 属性规定激活(使元素获得焦点)元素 ...

  5. Nginx 反向代理工作原理简介与配置详解

    Nginx反向代理工作原理简介与配置详解   by:授客  QQ:1033553122   测试环境 CentOS 6.5-x86_64 nginx-1.10.0 下载地址:http://nginx. ...

  6. python同步原语--线程锁

    多线程锁是python多种同步原语中的其中一种.首先解析一下什么是同步原语,python因为GIL(全局解析锁)的缘故,并没有真正的多线性.另外python的多线程存在一个问题,在多线程编程时,会出现 ...

  7. memcached分析

    memcache介绍 memcache是一个高性能的分布式的内存对象缓存系统,用于动态Web应用以减轻数据库负担.它通过在内存中缓存数据和对象,来减少读取数据库的次数.从而提高动态.数据库驱动网站速度 ...

  8. [20180423]flashback tablespace与snapshot standby.txt

    [20180423]flashback tablespace与snapshot standby.txt --//缺省建立表空间是打开flashback on,如果某个表空间flashback off, ...

  9. [20171225]没有备份数据文件的恢复.txt

    [20171225]没有备份数据文件的恢复.txt --//别人问的问题,增加了数据文件没有备份,如何恢复,实际上很简单,因为当前控制文件有记录建立时间只要从建立数据文件开始的--//归档日志都存在恢 ...

  10. AMP架构补充与wordpress部署

    1.httpd的虚拟主机不能使用的问题 httpd中新建一个虚拟主机,并添加访问URI路径的时候,需要给此路径指定访问权限.今天遇到一个虚拟主机不能使用的问题,语法检测没有报错,并且还可以正常启动服务 ...