移动端开发实例 | 圖片滑動 | 模擬滾動條

圖片滑動
onmousedown -->> ontouchstart按下瞬间 ;
onmousemove -->> ontouchmove移动过程 ;
onmouseup -->> ontouchend手指抬起 ,只针对单手操作 ;
對象操作:

var touchs = e.changedTouches[0]  
//先获取对象属性,手指操作的集合; 几个手指即有几项,所以单指是[0] ;

所以與元素拖動類似,結構是:

_ul.ontouchstart = function(e){
    _ul.ontouchmove  = function(e){
        ...
    }
    _ul.ontouchend  = function(e){
        ...
         this.ontouchmove = this.ontouchend = null;
    }
}

第一張圖與最後一張圖時速度變慢,所以使用移動距離為1/3

this.style.left = (touchs.pageX - downX) / 3 + 'px'

若第一張與第二張中間切換時,速度不同會出現跳動,所以需要再move過界時重新獲取downX,並且設置開頭只獲取一次;

   b = false
   downX = touchs.pageX

如果快速移動時,可快速滑動,需要設置時間,start時的時間,到end的時間

downTime = Date.now(); 

    _ul.ontouchend = function(e){
    ...
    Date.now() - downTime < 300  
    }
<div id="div">
    <ul id="ul1">
        <li><img src="iosimg/1.jpg" alt=""/></li>
        <li><img src="iosimg/2.jpg" alt=""/></li>
        <li><img src="iosimg/3.jpg" alt=""/></li>
        <li><img src="iosimg/4.jpg" alt=""/></li>
        <li><img src="iosimg/5.jpg" alt=""/></li>
    </ul>
</div>
var _div = document.getElementById('div')
var _ul = document.getElementById('ul1')
var _li = _ul.getElementsByTagName('li')
var w = _li[0].offsetWidth;
_ul.style.width = w * _li.length + 'px'
document.ontouchmove = function (e) {  //阻止默認滑動
    e.preventDefault()
}

var downX = 0;   //手指點下的坐標
var downLeft = 0;
var downTime = 0;
var inow = 0;
_ul.ontouchstart = function (e) {
    var touchs = e.changedTouches[0]  //先获取对象属性,手指操作的集合; 几个手指即有几项,所以单指是[0]

    downX = touchs.pageX
    downLeft = this.offsetLeft;
    var b = true;
    downTime = Date.now();

    _ul.ontouchmove = function (e) {
        var touchs = e.changedTouches[0]
        if (this.offsetLeft >= 0) {
            if (b) { //第二张一点开始滑到,到第一张时,如果不重新获取downX值,第二张速度仅为1/3,所以会突然跳动,设开头的意思是在move移动中,只需获取一次,不然只要move则每一秒都会重新获取;
                b = false
                downX = touchs.pageX
            }
            this.style.left = (touchs.pageX - downX) / 3 + 'px'

        }
        else if (this.offsetLeft < _div.offsetWidth - _ul.offsetWidth) {
            if (b) { //第二张一点开始滑到,到第一张时,如果不重新获取downX值,第二张速度仅为1/3,所以会突然跳动,设开头的意思是在move移动中,只需获取一次,不然只要move则每一秒都会重新获取;
                b = false
                downX = touchs.pageX
            }
            this.style.left = (touchs.pageX - downX) / 3 + (_div.offsetWidth - _ul.offsetWidth) + 'px'

        }
        else {
            this.style.left = touchs.pageX - downX + downLeft + 'px'
        }
    }
    _ul.ontouchend = function (e) {
        var touchs = e.changedTouches[0]
        if (touchs.pageX < downX) { //向左
            if (inow != _li.length - 1) {
                if (downX - touchs.pageX > w / 2 || Date.now() - downTime < 300 && downX - touchs.pageX > 30) {  //必须过一半才滑动
                    inow++ //确定方向,快速滑动,防止点击
                }
            }
            tMove(this, {left: -w * inow}, 500, 'easeOut')

        }
        else { //向右
            if (inow != 0) {
                if (touchs.pageX - downX > w / 2 || Date.now() - downTime < 300 && touchs.pageX - downX > 30) {
                    inow--
                }
            }
            tMove(this, {left: -w * inow}, 500, 'easeOut')
        }
        this.ontouchmove = this.ontouchend = null;
    }
}
    *{ margin: 0; padding: 0;}
    #div{ width: 470px; height: 150px; margin: 50px; position: relative;overflow: hidden; }
    #ul1{ position: absolute; left: 0; } /*这种而已没有宽度则li不会有float效果;*/
    #ul1 li{ width: 470px; height: 150px; float: left;list-style:none;}

模擬滾動條:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title><meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
    <meta name="format-detection" content="telephone=no"/>
    <meta name="format-detection" content="email=no"/>
</head>
<body>
<style>
    *{ margin: 0; padding: 0;}
    #div1{ width: 200px; height: 200px;border:1px solid #000; position: relative; margin:100px;}
    #ul1{ position: absolute; top: 0;width: 100%;}
    #bar{ width: 2px; height: 100px; position: absolute; top: 0;right: 2px; background: #999; border-radius: 20px; display: none;}/* divH/ulH = barH/divH borH = divH*divH/ulH */
</style>
<div id="div1">
    <ul id="ul1">
    </ul>
    <div id="bar"></div>
</div>
</body>
<script>
    document.ontouchmove = function (e) {
        e.preventDefault()
    }
    var _div = document.getElementById('div1')
    var _ul = document.getElementById('ul1')
    var _bar = document.getElementById('bar')
    for(var i=0;i<101;i++){
        var _li = document.createElement('li')
        _li.innerHTML = i;
        _ul.appendChild(_li)
    }
    var downY = 0;
    var downTop = 0;
    var prevY = 0;

    var _t = null;

    var barH = _div.offsetHeight*_div.offsetHeight/_ul.offsetHeight
    if(barH<=40){
        barH = 40;
    }
    else if(_ul.offsetHeight<_div.offsetHeight){
        barH = 0;
    }
    _bar.style.height =barH + 'px'
    
    _ul.ontouchstart = function (e) {
        var touchs = e.changedTouches[0]

        downY = touchs.pageY
        downTop = this.offsetTop;
        prevY = touchs.pageY;

        var _speedY = 0;
        var b = true;

        _ul.ontouchmove= function (e) {

            _bar.style.opacity = 1;
            _bar.style.display = 'block';

          var touchs = e.changedTouches[0]
            _speedY = touchs.pageY - prevY; //出手速度 move时的点 - 前一个点,
            prevY = touchs.pageY;  //注意永运是最后一个点 - 前一个点,所以给值后要把prevY还原回前一个点;注意理解;
            if(this.offsetTop>=0){ //头部
                if(b){
                    b = false;
                    downY = touchs.pageY
                }
                this.style.top = (touchs.pageY - downY)/3 + downTop + 'px'
                _bar.style.height = barH * (1- this.offsetTop/_div.offsetHeight) +'px'//原高度 * 比例
                _bar.style.top = 0
            }
            else if(this.offsetTop<=_div.offsetHeight - _ul.offsetHeight){
                if(b){
                    b = false;
                    downY = touchs.pageY
                }
                this.style.top = (touchs.pageY - downY)/3 + _div.offsetHeight - _ul.offsetHeight + 'px'
                _bar.style.height = barH * (1- Math.abs((this.offsetTop-(_div.offsetHeight - _ul.offsetHeight))/_div.offsetHeight)) +'px'//原高度 * 比例  //尾部找一个0-1越来越小的值
                _bar.style.top = _div.offsetHeight - _bar.offsetHeight + 'px'
            }
            else{this.style.top = touchs.pageY - downY + downTop + 'px';

            //在move时找bar的滚动位置比例
                var scaleY = this.offsetTop/(_div.offsetHeight - _ul.offsetHeight) //最小值即move时不断变化的this.offsetTop,最大值为div.offsetHeight - _ul.offsetHeight; 0-1的比值
                _bar.style.top = scaleY * (_div.offsetHeight - _bar.offsetHeight)+'px'
            }
        }
        _ul.ontouchend = function () {
            this.ontouchmove = this.ontouchend = null;
            //1/手指起时开始做运动
            //_speedY
            var _this = this
            clearInterval(_t)
            _t = setInterval(function () {
                if(Math.abs(_speedY)<=1 || _this.offsetTop>50 || _this.offsetTop<=_div.offsetHeight - _ul.offsetHeight - 50){  //停
                    clearInterval(_t)
                    if(_this.offsetTop>=0){ //限制头
                        tMove(_this,{top:0},400, function () {
                            tMove(_bar,{opacity:0},400, function () {
                                this.style.display = 'none'
                            })

                        })
                        tMove(_bar,{height:barH},400)
                    }
                    else if(_this.offsetTop <= _div.offsetHeight - _ul.offsetHeight  ){ //限制尾
                        tMove(_this,{top:_div.offsetHeight - _ul.offsetHeight },400, function () {
                            tMove(_bar,{opacity:0},400, function () {
                                this.style.display = 'none'
                            })

                        })
                        tMove(_bar,{height:barH,top:_div.offsetHeight - barH},400, function () {
                            tMove(_bar,{opacity:0},400)
                            _bar.style.display = 'none'
                        })
                    }
                    else{  tMove(_bar,{opacity:0},400, function () {
                        this.style.display = 'none'
                    })

                    }
                }
                else{  //走
                    _speedY *=0.95;
                    _this.style.top = _this.offsetTop+ _speedY + 'px'

                    //bar头尾加运动

                    if(_this.offsetTop>=0){
                        _bar.style.height = barH * (1- _this.offsetTop/_div.offsetHeight) +'px'//原高度 * 比例
                        _bar.style.top = 0
                    }
                    else if(_this.offsetTop<=_div.offsetHeight - _ul.offsetHeight){
                        _bar.style.height = barH * (1- Math.abs((_this.offsetTop-(_div.offsetHeight - _ul.offsetHeight))/_div.offsetHeight)) +'px'//原高度 * 比例  //尾部找一个0-1越来越小的值
                        _bar.style.top = _div.offsetHeight - _bar.offsetHeight + 'px'
                    }
                    else{}
                    //在move时找bar的滚动位置比例
                    var scaleY = _this.offsetTop/(_div.offsetHeight - _ul.offsetHeight) //最小值即move时不断变化的this.offsetTop,最大值为div.offsetHeight - _ul.offsetHeight; 0-1的比值
                    _bar.style.top = scaleY * (_div.offsetHeight - _bar.offsetHeight)+'px'
                    tMove(_bar,{top:scaleY * (_div.offsetHeight - _bar.offsetHeight)},400)
                }
            },30)
        }
    }

    function tMove(obj, json, times, fx, fn) {
        if (typeof times == 'undefined') {
            times = 400;
            fx = 'linear';
        }
        if (typeof times == 'string') {
            if (typeof fx == 'function') {
                fn = fx;
            }
            fx = times;
            times = 400;
        }
        else if (typeof times == 'function') {
            fn = times;
            times = 400;
            fx = 'linear';
        }
        else if (typeof times == 'number') {
            if (typeof fx == 'function') {
                fn = fx;
                fx = 'linear';
            }
            else if (typeof fx == 'undefined') {
                fx = 'linear';
            }
        }
        var iCur = {
        }; //不變,不能寫在定時器裏  b
        for (var attr in json) {
            iCur[attr] = 0;
            if (attr == 'opacity') {
                iCur[attr] = Math.round(css(obj, attr) * 100);
            }
            else {
                iCur[attr] = parseInt(css(obj, attr));
            }
        }
        var startTime = now();
        clearInterval(obj._t);
        obj._t = setInterval(function () {
            var changeTime = now();
            var t = times - Math.max(0, startTime - changeTime + times);
            //在time的範圍內越來越小  2000-0;
            for (var attr in json) {
                var value = Tween[fx](t, iCur[attr], json[attr] - iCur[attr], times); //目的,通過js獲取tbcd值
                if (attr == 'opacity') {
                    obj.style.opacity = value / 100;
                    obj.style.filter = 'alpha(opacity=' + value + ')';
                }
                else {
                    obj.style[attr] = value + 'px';
                }
            }
            if (t == times) {
                clearInterval(obj._t);
                fn && fn.call(obj);
            }
        }, 13)
    }
    function now() {
        return (new Date()).getTime();
    }
    var Tween = {
        linear: function (t, b, c, d) { //匀速
            return c * t / d + b;
        },
        easeIn: function (t, b, c, d) { //加速曲线
            return c * (t /= d) * t + b;
        },
        easeOut: function (t, b, c, d) { //减速曲线
            return - c * (t /= d) * (t - 2) + b;
        },
        easeBoth: function (t, b, c, d) { //加速减速曲线 缓冲
            if ((t /= d / 2) < 1) {
                return c / 2 * t * t + b;
            }
            return - c / 2 * ((--t) * (t - 2) - 1) + b;
        },
        easeInStrong: function (t, b, c, d) { //加加速曲线
            return c * (t /= d) * t * t * t + b;
        },
        easeOutStrong: function (t, b, c, d) { //减减速曲线
            return - c * ((t = t / d - 1) * t * t * t - 1) + b;
        },
        easeBothStrong: function (t, b, c, d) { //加加速减减速曲线
            if ((t /= d / 2) < 1) {
                return c / 2 * t * t * t * t + b;
            }
            return - c / 2 * ((t -= 2) * t * t * t - 2) + b;
        },
        elasticIn: function (t, b, c, d, a, p) { //正弦衰减曲线(弹动渐入)
            if (t === 0) {
                return b;
            }
            if ((t /= d) == 1) {
                return b + c;
            }
            if (!p) {
                p = d * 0.3;
            }
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            } else {
                var s = p / (2 * Math.PI) * Math.asin(c / a);
            }
            return - (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
        },
        elasticOut: function (t, b, c, d, a, p) { //正弦增强曲线(弹动渐出)
            if (t === 0) {
                return b;
            }
            if ((t /= d) == 1) {
                return b + c;
            }
            if (!p) {
                p = d * 0.3;
            }
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            } else {
                var s = p / (2 * Math.PI) * Math.asin(c / a);
            }
            return a * Math.pow(2, - 10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
        },
        elasticBoth: function (t, b, c, d, a, p) {
            if (t === 0) {
                return b;
            }
            if ((t /= d / 2) == 2) {
                return b + c;
            }
            if (!p) {
                p = d * (0.3 * 1.5);
            }
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            }
            else {
                var s = p / (2 * Math.PI) * Math.asin(c / a);
            }
            if (t < 1) {
                return - 0.5 * (a * Math.pow(2, 10 * (t -= 1)) *
                        Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
            }
            return a * Math.pow(2, - 10 * (t -= 1)) *
                    Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
        },
        backIn: function (t, b, c, d, s) { //回退加速(回退渐入)
            if (typeof s == 'undefined') {
                s = 1.70158;
            }
            return c * (t /= d) * t * ((s + 1) * t - s) + b;
        },
        backOut: function (t, b, c, d, s) {
            if (typeof s == 'undefined') {
                s = 3.70158; //回缩的距离
            }
            return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
        },
        backBoth: function (t, b, c, d, s) {
            if (typeof s == 'undefined') {
                s = 1.70158;
            }
            if ((t /= d / 2) < 1) {
                return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
            }
            return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
        },
        bounceIn: function (t, b, c, d) { //弹球减振(弹球渐出)
            return c - Tween['bounceOut'](d - t, 0, c, d) + b;
        },
        bounceOut: function (t, b, c, d) {
            if ((t /= d) < (1 / 2.75)) {
                return c * (7.5625 * t * t) + b;
            } else if (t < (2 / 2.75)) {
                return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
            } else if (t < (2.5 / 2.75)) {
                return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
            }
            return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
        },
        bounceBoth: function (t, b, c, d) {
            if (t < d / 2) {
                return Tween['bounceIn'](t * 2, 0, c, d) * 0.5 + b;
            }
            return Tween['bounceOut'](t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
        }
    }
    function css(obj, attr) {
        return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj) [attr]
    }
</script>
</html>

移动Web前端开发资源整合

<h2>meta篇</h2>
<h3>1.视窗宽度</h3>
<style>
.codex{padding: 2px 4px;
color: #d14;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;}
</style>

<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>

其中 width=device-width 是设置视窗宽度为设备视窗宽度,还可以固定宽度,例如: width=640 则是640px的宽度(常见于微信);


initial-scale=1.0 :设置缩放比例为1.0;


minimum-scale=1.0maximum-scale=1.0 :最小缩放比例和最大缩放比例;


user-scalable=no :禁止用户自由缩放,user-scalable 默认值为 yes 。


提示:刚刚那个是带全部参数的,一般常用的,有 user-scalable=no 就不用使用 minimum-scale=1.0maximum-scale=1.0 来强制禁止缩放了。

<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>

<h3>2.自动识别格式</h3>

<meta name="format-detection" content="telephone=no"/>

content 里面的参数:telephone=no 是禁止浏览器自动识别手机号码,email=no 是禁止浏览器自动识别Email。


<h3>3.完整模板</h3>

<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="format-detection" content="email=no"/>

<h2>CSS篇</h2>

content 里面的参数:telephone=no 是禁止浏览器自动识别手机号码,email=no 是禁止浏览器自动识别Email。

3.完整模板

<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="format-detection" content="email=no"/>
CSS篇

body {
    font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif; /*使用无衬线字体*/
}

a, img {
    -webkit-touch-callout: none; /*禁止长按链接与图片弹出菜单*/
}

html, body {
    -webkit-user-select: none; /*禁止选中文本*/
    user-select: none;
}

button,input,optgroup,select,textarea {
    -webkit-appearance:none; /*去掉webkit默认的表单样式*/
}

a,button,input,optgroup,select,textarea {
    -webkit-tap-highlight-color:rgba(0,0,0,0); /*去掉a、input和button点击时的蓝色外边框和灰色半透明背景*/
}

input::-webkit-input-placeholder {
    color:#ccc; /*修改webkit中input的planceholder样式*/
}

input:focus::-webkit-input-placeholder {
    color:#f00; /*修改webkit中focus状态下input的planceholder样式*/
}

body {
    -webkit-text-size-adjust: 100%!important; /*禁止IOS调整字体大小*/
}

input::-webkit-input-speech-button {
    display: none; /*隐藏Android的语音输入按钮*/
}

<h2>Flex基础篇</h2>

这里假设flex容器为 .box ,项目为.item


<h3>1.定义容器为flex布局</h3>

.box{
    display: -webkit-flex; /*webkit*/
    display: flex;
}

/*行内flex*/
.box{
    display: -webkit-inline-flex; /*webkit*/
    display:inline-flex;
}
``
<h3>2.容器样式</h3>

.box{

flex-direction: row | row-reverse | column | column-reverse;
/*主轴方向:左到右(默认) | 右到左 | 上到下 | 下到上*/

flex-wrap: nowrap | wrap | wrap-reverse;
/*换行:不换行(默认) | 换行 | 换行并第一行在下方*/

flex-flow: <flex-direction> || <flex-wrap>;
/*主轴方向和换行简写*/

justify-content: flex-start | flex-end | center | space-between | space-around;
/*主轴对齐方式:左对齐(默认) | 右对齐 | 居中对齐 | 两端对齐 | 平均分布*/

align-items: flex-start | flex-end | center | baseline | stretch;
 /*交叉轴对齐方式:顶部对齐(默认) | 底部对齐 | 居中对齐 | 上下对齐并铺满 | 文本基线对齐*/

align-content: flex-start | flex-end | center | space-between | space-around | stretch;
/*多主轴对齐:顶部对齐(默认) | 底部对齐 | 居中对齐 | 上下对齐并铺满 | 上下平均分布*/

}

<h3>3.项目样式</h3>

.item{

order: <integer>;
/*排序:数值越小,越排前,默认为0*/

flex-grow: <number>; /* default 0 */
/*放大:默认0(即如果有剩余空间也不放大,值为1则放大,2是1的双倍大小,以此类推)*/

flex-shrink: <number>; /* default 1 */
/*缩小:默认1(如果空间不足则会缩小,值为0不缩小)*/

flex-basis: <length> | auto; /* default auto */
/*固定大小:默认为0,可以设置px值,也可以设置百分比大小*/

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
/*flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto,*/

align-self: auto | flex-start | flex-end | center | baseline | stretch;
/*单独对齐方式:自动(默认) | 顶部对齐 | 底部对齐 | 居中对齐 | 上下对齐并铺满 | 文本基线对齐*/

}

<h2>小技巧篇</h2>
<h3>1.自定义苹果图标</h3>
<p>在网站文件根目录放一个<span class='codex'> apple-touch-icon.png </span>文件,苹果设备保存网站为书签或桌面快捷方式时,就会使用这个文件作为图标,文件尺寸建议为:180px × 180px。</p>
<h3>2.自定义favicon:</h3>

<link rel="icon" href="favicon.ico" mce_href="favicon.ico" type="image/x-icon">

<h3>3.定义浏览器点击行为:</h3>

打电话给:020-10086
发短信给: 10086
发送邮件: me@22278.club

<h3>4.定义上传文件类型和格式</h3>

<input type=file accept="image/*">

<p>上面的文件上传框中,<span class='codex'> accept</span> 可以限制上传文件的类型,参数为 image/* 是所有图片类型,点击会弹出图库,也可以指定图片格式,参数设置成<span class='codex'>  image/png</span> 则可以限制图片类型为png;参数如果为<span class='codex'>   video/*</span> 则是选择视频的意思;accept 还可以设置多个文件格式,语法为<span class='codex'>  accept="image/gif, image/jpeg"</span> ;</p>
<h3>5.使用box-shadow改变(挡住)表单自动填充后的黄色</h3>

input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill{

box-shadow:inset 0 0 0 1000px #fff;

}

<h3>6.用CSS实现省略号文字截断</h3>

white-space: nowrap;
text-overflow: ellipsis;


感谢来源:http://www.ccwebsite.com/development-of-resource-integration-in-mobile-terminal/