前端网页特效

一.PC端网页特效

1.元素偏移量offset系列

offset系列相关属性可以动态得到元素的位置(偏移)、大小等。

offset系列属性作用
element.offsetTop返回元素相对带有定位父元素上方的偏移
element.offsetLeft返回元素相对带有定位父元素左侧的偏移
element.offsetWidth返回自身包括padding、边框、内容的宽度,返回数值不带单位
element.offsetHeight返回自身包括padding、边框、内容的高度,返回数值不带单位
element.offsetParent返回带有定位的父级,如果父级都没有带定位,则返回body
		var div = document.querySelector('div')

        // 1.offset获取位置
        console.log(div.offsetTop);
        console.log(div.offsetLeft);

        // 2.offset获取元素大小(width+border+padding)
        console.log(div.offsetWidth);
        console.log(div.offsetHeight);

        // 3.offset获取带有定位的父元素  
        console.log(div.offsetParent)

offset和style的区别:

  • offset能获取任意样式表中元素的样式值,style只能得到行内样式表中的样式值
  • offset获取到的数值是没有单位的,style获取到的是带有单位的字符串
  • offset获取元素大小(width+boder+padding),style获取到的元素大小不包含padding,border
  • offset只能读取属性,不能赋值,style能读取属性,也能赋值

2.元素可视区client系列

client(可视区),client相关属性来获取元素的可视区的信息,通过client的相关属性可以动态的获取到元素的边框大小、元素大小等。

client系列属性作用
element.clientTop获取元素上边框
element.clientLeft获取元素左边框
element.clientWidth返回自身包括padding、内容的宽度,不包含边框,返回数值不单单位
element.clientHeight返回自身包括padding、内容的高度,不包含边框,返回数值不单单位
 		var div = document.querySelector('div');
        // 1.获取元素上边框
        console.log(div.clientTop);
        // 2.获取元素左边框
        console.log(div.clientLeft);
        // 3.获取元素大小   
        console.log(div.clientWidth);
        console.log(div.clientHeight);

client和offset的区别:

  • client得到的元素大小不包含边框(border)

3.元素滚动scroll系列

scroll意为滚动的。scroll系列的相关属性可以动态的获得元素的大小,滚动距离等。

scroll系列属性作用
element.scrollTop返回被卷去的上侧距离,返回数值不带单位
element.scrollLeft返回被卷去的左侧距离,返回数值不带单位
element.scrollWidth返回自身实际的宽度,不包含边框,返回数值不带单位
element.scrollHeight返回自身实际的高度,不包含边框,返回数值不带单位
		var div = document.querySelector('div');
        // 1.获取自身实际的大小
        console.log(div.scrollWidth);
        console.log(div.scrollHeight);       

        // 2.返回被卷去上侧的距离(滚动距离)
        div.addEventListener('scroll', function () {
            console.log(div.scrollTop);     
        })

        // 3.返回被全局左侧的距离(滚动距离)
        console.log(div.scrollLeft);

scroll和client的区别:

  • croll也client获取元素大小都不包含边框,scroll得到的是元素自身(包括内容)的大小,client得到的元素就是元素(盒子)的大小。

扩展

  • 获取元素被卷去的(上、左侧距离)用element.scrollTop,element.scrollLeft
  • 获取页面被卷去的(上、左侧距离)用window.pageYOffset,window.pageXOffset

4.立即执行函数

​ 立即执行函数就是不需要调用就能够直接执行的函数,它有两种书写方式。

1.(function(){})()

		(function (a, b) {

            console.log(a + b);

        })(1, 2);       

2.(function(){}())

    	(function (a, b) {

            console.log(a + b);

        }(1, 2))
  • 立即执行函数最大的作用就是,独立创建了一个作用域,里面所有的变量都是局部变量,不会有命名冲突的情况
  • 如果一个js文件的代码都封装到立即执行函数里,此时引入其他js文件,不会存在命名冲突

mouseentermouseover的区别:

  • mouseover经过自身和他的子盒子都会触发,mouserenter只会经过自身盒子触发。
  • mouseenter和mouseleave不会冒泡。

4.动画函数封装

​ 动画的核心原理: 通过定时器setInterval()不断移动盒子位置。

实现步骤:

  • 获得盒子当前位置
  • 让盒子在当前位置加上一个移动距离
  • 利用定时器不断重复这个操作
  • 加一个结束定时器的条件
  • 实现动画的元素需要添加定位,这样才能使用到element.style.left

(1).简单的动画封装函数

function 函数名(目标对象,目标位置) {}

		// 1.函数声明
		function animate(obj, target) {
			// 设置定时器
            var Timer = setInterval(function () {

                if (obj.offsetLeft > target) {
                    clearInterval(Timer);
                }
                // 元素添加移动距离
                obj.style.left = obj.offsetLeft + 2 + 'px';
            }, 50)
        }
		var div = document.querySelector('div');
		// 2.调用函数
		animate(div, 300);
  • 参数1(obj)代表目标对象,参数2(target)代表目标位置

(1). 给不同元素添加不同的定时器

​ 核心原理:利用 JS 是一门动态语言,可以很方便的给当前对象添加属性。

		function animate(obj, target) {

            // 在调用定时器前,先清除一次原先的定时器
            clearInterval(obj.Timer);
            obj.Timer = setInterval(function () {

                if (obj.offsetLeft > target) {
                    clearInterval(obj.Timer);
                }
                obj.style.left = obj.offsetLeft + 2 + 'px';
            }, 50)
        }
  • 函数内如果用var Timer声明,每有一个对象调用,内存就多开辟一个空间(变量Timer),如果对象太多了,浪费内层空间
  • 使用obj.Timer(对象.属性)的赋值形式就能很好的解决这个问题
  • 先清除之前的定时器,只保留当前的一个定时器执行,这样能很好的解决连续点击事件动画连续调用animate()使得动画效果移动很快的bug

(3). 缓动动画

 		 	function animate(obj, target) {

            clearInterval(obj.Timer);
            obj.Timer = setInterval(function () {
                
                // 把步长值改为整数,不要出现小数的问题
                var step = (target - obj.offsetLeft) / 10;
                // 正着走时,向上取整,回来走时,向下取整
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) { 
                    clearInterval(obj.Timer);
                }
                // 把每次+1这个步长值改为一个慢慢变小的值(step)
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 15)
        }
  • 缓动动画就是让元素速度有所变化,最常见的就是让速度慢慢停下来。

  • 核心算法: (目标值-当前位置) / 10 做每次移动的距离(步长)

  • 判断步长是正值还是负值,如果是正值,则步长往大了取整,反之亦然

  • 停止条件: 让当前盒子位置等于目标位置就停止定时器

(4). 缓动动画添加回调函数

​ 函数回调原理: 函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当另一个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。

 		// 1.函数声明
		function animate(obj, target, callback) {  
            clearInterval(obj.Timer);
            obj.Timer = setInterval(function () {

                var step = (target - obj.offsetLeft) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) {
                    clearInterval(obj.Timer);
                    // 在定时器结束之后调用
                    if (callback) {  // 判断有没有回调函数参数传过来,有就调用
                        
                        callback();
                    }
                }
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 15)
        }
		// 2.函数调用
		animate(span, 800, function () {
                span.style.backgroundColor = 'red';
            });
        })
  • animate()函数中的第三个参数用了函数作为实参,传递给函数内的形参callback
  • callback接收传过来的实参(函数),相当于callback = function() {} 所以调用的时候就是callback()
  • 在定时器结束之后,在进行函数回调

动画函数使用:

​ 可以将动画函数写入到一个js文件,当需要使用到动画效果时,直接引入动画函数进行调用即可。

5.常见网页特效案例

1.网页轮播图(js部分)

window.addEventListener('load', function () {

    var focus = document.querySelector('.focus');
    var left = document.querySelector('.left-arrow');
    var right = document.querySelector('.right-arrow');

    // 1. 鼠标经过/离开focus 左右箭头显示/隐藏
    focus.addEventListener('mouseenter', function () {

        left.style.display = 'block';
        right.style.display = 'block';
        clearInterval(timer);
        timer = null;
    })

    focus.addEventListener('mouseleave', function () {

        left.style.display = 'none';
        right.style.display = 'none';
        timer = setInterval(function () {
            // 手动调用点击右按钮的事件
            right.click();
        }, 2000);
    })

    // 2.动态生成小圆圈(有几张图,就有多少小圆圈,利用循环)
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('ol');
    // focusWidth放到外面来,点击右箭头时,图片滚动需要用到这个变量
    var focusWidth = focus.offsetWidth;

    for (var i = 0; i < ul.children.length; i++) {

        // 创建小圆圈节点
        var li = document.createElement('li');
        // 创建小圆点(li)的同时,给每个小圆点设置索引号(自定义属性)
        li.setAttribute('index', i);
        // 将li放到ol中
        ol.appendChild(li);
        // 3.创建li的同时,给每个li添加点击事件
        li.addEventListener('click', function () {

            //排他思想清除其他li的current类
            for (var i = 0; i < ol.children.length; i++) {

                ol.children[i].className = '';
            }
            // 设置当前li的类名为current
            this.className = 'current';

            //4.添加动画函数 (target就是小圆点的索引号*图片的宽度  图片的宽度就是focus的宽度,获取过来)
            // 获取当前li的索引号,并且乘上图片宽度,作为target参数
            var index = this.getAttribute('index');
            // 当我们点击了某个li,就要把这个li的索引号给num,circle(num控制下一张图片的播放,circle控制下一个小圆圈的播放,当前索引号给他们,他们就保持到了同步)
            num = index;
            circle = index;
            // ul是往左走的,所以要的是负值
            animate(ul, -index * focusWidth);


        })
        // 将第一个li的类名设置成current
        ol.children[0].className = 'current';
    }

    // 5. 克隆ul的第一个孩子li,放到最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);

    // 6.点击左/右侧按钮,图片滚动一张
    //声明一个变量,每点击一次就自增1,让这个变量乘图片的宽度,就是每次ul滚动的距离
    var num = 0;
    var circle = 0;
    // flag节流阀  (我们点击按钮的时候,图片切换的很快(动画播放效果效果并没有完成就切换到下一张图片了),我们想让点击按钮很快的情况下,也要让动画先播放完成)
    var flag = true;
    right.addEventListener('click', function () {

        if (flag) {

            flag = false;   // 关闭节流阀
            // 做无缝滚动效果(如果走到了最后一张复制的图片,ul快速复原为left = 0)
            if (num == ul.children.length - 1) {

                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function () {

                flag = true;    // 开启节流阀(让动画函数执行完成后,再打开节流阀)
            });

            // 点击右侧按钮,小圆圈跟随变化,可以声明一个变量cicle控制小圆圈
            circle++;
            // 判断当cicle == 4了,说明走到了最后一张图(克隆出来的图片),circle复原
            if (circle == ol.children.length) {
                circle = 0;
            }

            circleChange();
        }

    })

    // 7.左侧按钮做法
    left.addEventListener('click', function () {

        if (flag) {

            flag = false;
            if (num == 0) {

                // num走到最后一张
                num = ul.children.length - 1;
                // ul快速切换到最后一张
                ul.style.left = -num * focusWidth + 'px';

            }
            num--;
            animate(ul, -num * focusWidth, function () {

                flag = true;
            });

            // 点击右侧按钮,小圆圈跟随变化,可以声明一个变量cicle控制小圆圈
            circle--;
            // 判断当cicle == 4了,说明走到了最后一张图(克隆出来的图片),circle复原
            if (circle < 0) {
                circle = ol.children.length - 1;
            }

            circleChange();
        }
    })

    function circleChange() {

        // 先清除其余的小圆圈的类名 
        for (var i = 0; i < ol.children.length; i++) {

            ol.children[i].className = '';
        }


        // 留下当前小圆圈的current类名
        ol.children[circle].className = 'current';

    }

    // 8.自动播放轮播图
    // 和点击右侧类型非常之相似
    var timer = setInterval(function () {
        // 手动调用点击右按钮的事件
        right.click();
    }, 2000);
})

二.移动端网页特效

1.触屏事件

​ 移动端浏览器兼容性较好,不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。

1.常见的触屏事件:

触屏touch事件说明
touchstart手指触摸到一个DOM元素时触发
touchmove手指在一个DOM元素上滑动触发
touchend手指在一个DOM元素移开时触发

示例:

var div = document.querySelector('div');
div.addEventListener('touchstart', function () {
            console.log('hello');
        })

div.addEventListener('touchmove', function () {
            console.log('hello');
        })
        
div.addEventListener('touchend', function () {
            console.log('hello');
        })

2.touchEvent触摸事件对象

touchEvent是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等。

触摸事件对象常见的三个对象列表:

触摸列表说明
touches正在触摸屏幕的所有手指列表
targetTouches正在触摸当前DOM元素的手指的列表
changeTouches手指状态发生了改变的列表(从无到右,从右到无的变化)

示例:

		var div = document.querySelector('div');

        div.addEventListener('touchstart', function (e) {
            // 一般都是触摸元素,所以最常用的是targetTouches
            console.log(e.targetTouches[0]);    // 可以获得正在触摸元素的第一个手指信息
        })

        div.addEventListener('touchend', function (e) {

            console.log(e);
            // 当我们手指离开了,就没有touches和targetTouches列表,但是会有changeTouches 
        })

3.移动端拖动元素

​ 移动端拖动的原理: 手指移动中,计算出手指移动的距离,然后用盒子原来的位置 + 手指移动的距离

touchstarttouchmovetouchend可以实现拖动元素。

思路:

  • touchstart: 获取手指的初始坐标以及盒子原来的位置
  • touchmove: 计算手指滑动的距离并且移动盒子。

示例:

        var div = document.querySelector('div');

        // 保存手指初始位置的变量
        var startX = 0;
        var startY = 0;
        // 保存盒子原来的位置的变量
        var x = 0;
        var y = 0;
        div.addEventListener('touchstart', function (e) {

            // 1.获取手指的初始位置
            startX = e.targetTouches[0].pageX;
            startY = e.targetTouches[0].pageY;
            // 2.获取盒子原来的位置
            x = this.offsetLeft;
            y = this.offsetTop;
        })

        div.addEventListener('touchmove', function (e) {

            // 3.获取手指移动的距离(手指移动后的距离 - 手指的初始位置)
            var moveX = e.targetTouches[0].pageX - startX;
            var moveY = e.targetTouches[0].pageY - startY;

            // 4.移动盒子(盒子原来的位置 + 手指移动距离)
            this.style.left = x + moveX + 'px';
            this.style.top = y + moveY + 'px';

            // 5.阻止屏幕滚动后的默认行为
            e.preventDefault();
        })
  • e.targetTouches[0].pageX/.pageY可以获取到第一个手指触摸到元素的x轴或y轴坐标
  • 用户在滑动屏幕上的DOM元素过程中,可能也会滑动到屏幕,使用e.preventDefault()可以阻止屏幕滚动后的默认行为

4.classList的使用

classList属性是HTML5新增的一个属性,返回元素的类名。ie10以上版本支持。

​ 该属性用于在元素中添加,移除及切换类。

(1) 添加类

element.classList.add('类名')

var div = document.querySelector('.one');
div.classList.add('three');

(2) 删除类

element.classList.remove('类名')

div.classList.remove('one')

(3)切换类

div.classList.toggle('one')
  • classList.toggle()使用时,无该类名则添加,有该类名则删除

2.移动端常见特效

移动端轮播图

​ 移动端轮播图功能和PC端基本一致,可以自动播放图片,也可以用手指拖动播放轮播图。

示例(js部分):

	window.addEventListener('load', function () {

    // 获取元素
    var focus = document.querySelector('.focus');
    var ul = focus.children[0];
    var ol = focus.children[1];

    // 1.利用定时器自动轮播图片
    var index = 0;
    var w = focus.offsetWidth;
    var timer = setInterval(function () {

        index++;
        var translatex = -index * w;
        // 移动端可以使用过渡做动画效果
        ul.style.transition = 'all .3s'
        ul.style.transform = 'translateX(' + translatex + 'px)';
    }, 2000);

    // 2.无缝滚动(等着过渡完成之后,再加上判断)   transitionend 过渡完成事件
    ul.addEventListener('transitionend', function () {
        // 判断滚动到最后一张图(复制出来的图)时
        if (index >= 3) {

            index = 0;
            // 关闭过渡效果 ul能快速跳到目标位置
            ul.style.transition = 'none';
            // 用最新索引号乘图片宽度
            var translatex = -index * w;
            // 回到第一张的图片
            ul.style.transform = 'translateX(' + translatex + 'px)';
        } else if (index < 0) {

            // 滚动到最后一张
            index = 2;
            ul.style.transition = 'none';
            var translatex = -index * w;
            ul.style.transform = 'translateX(' + translatex + 'px)';
        }

        //3.小圆点跟随变化
        // 把ol里面li带有current类名的全部选出来去掉
        ol.querySelector('.current').classList.toggle('current');
        // 给当前的li添加current类
        ol.children[index].classList.add('current');
    })

    //4.手指拖动轮播图
    // 触摸元素: 获取手指初始坐标
    var startX = 0;
    var moveX = 0; //全局变量 后面还要使用到
    var flag = false;
    ul.addEventListener('touchstart', function (e) {

        startX = e.targetTouches[0].pageX;
        // 手指触摸时,定时器关闭
        clearInterval(timer);
    })
    // 移动手指: 计算手指滑动距离,并且移动盒子
    ul.addEventListener('touchmove', function (e) {
        // 计算移动距离
        moveX = e.targetTouches[0].pageX - startX;
        // 原先盒子位置下移动盒子
        var translatex = -index * w + moveX;
        // 手指拖动时,不需要动画效果,关闭过渡
        ul.style.transition = 'none';
        ul.style.transform = 'translateX(' + translatex + 'px)';
        // 如果用户手指移动过 我们再去判断否则不做判断效果(有时候可能犹豫了,只是点了一下并没有拖动,)
        flag = true;
        e.preventDefault();     //阻止滚动屏幕行为

    })

    // 手指离开: 根据移动距离判断是回弹还是播放上一张/下一张
    ul.addEventListener('touchend', function () {

        if (flag) {

            // 1.移动距离大于50 播放上/下一张
            if (Math.abs(moveX) > 50) { // 要取绝对值,因为左右两边滑动距离得出的数值有正有负

                if (moveX > 0) {  // 如果是向右滑动(moveX是正值),则播放上一张图片
                    index--;

                } else {
                    index++;    // 如果是向左滑动(moveX是负值),则播放下一张图片
                }

                var translatex = -index * w;
                ul.style.transition = 'all .3s';
                ul.style.transform = 'translateX(' + translatex + 'px)';

            } else {
                // 2.移动距离小于50 回弹当前
                var translatex = -index * w;
                ul.style.transition = 'all .3s';
                ul.style.transform = 'translateX(' + translatex + 'px)';
            }
        }

        // 3.手指离开后,继续开启定时器
        // 开启前,先清除之前的定时器
        clearInterval(timer);
        timer = setInterval(function () {

            index++;
            var translatex = -index * w;
            // 移动端可以使用过渡做动画效果
            ul.style.transition = 'all .3s'
            ul.style.transform = 'translateX(' + translatex + 'px)';
        }, 2000);

    })

    //5.返回顶部模块
    var goBack = document.querySelector('.goBack');
    var nav = document.querySelector('nav');
    window.addEventListener('scroll', function () {

        if (window.pageYOffset >= nav.offsetTop) { 

            goBack.style.display = 'block';
        } else {

            goBack.style.display = 'none';
        }
    });

    goBack.addEventListener('click', function () {

        window.scroll(0, 0);
    })

})

2.移动端解决click延迟300ms问题方案

(1).禁用用户缩放

 <meta name="viewport" content="user-scalable=no"

(2).利用touch事件自己封装这个事件解决300ms延迟

	    // 1.封装tap
        function tap(obj, callback) {
            var isMove = false;
            var startTime = 0;  //  记录触摸时的时间变量
            obj.addEventListener('touchstart', function (e) {
                startTime = Date.now(); //  记录触摸时间
            });
            obj.addEventListener('touchmove', function (e) {
                isMove = true;  // 判断是否有滑动,有滑动算拖拽,不算点击
            })
            obj.addEventListener('touchend', function (e) {
                if (!isMove && (Date.now() - startTime) < 150) {    //  如果手指触摸和离开时间小于150ms,就算点击
                    callback && callback(); // 执行回调函数
                }
                isMove = false; // 取反 重置
                startTime = 0;
            });
        }

        // 2.调用tap
        tap(div, function () {

            // 执行代码
        });

(3).使用fastclick插件

  <!-- 引入插件 -->
  <script src="./fastclick.js">

        if ('addEventListener' in document) {
            document.addEventListener('DOMContentLoaded', function () {
                FastClick.attach(document.body);
            }, false);
        }
  </script>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值