WebAPI(四)-JS特效
PC 端网页特效
元素偏移量 offset 系列
- offset 概述
- offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度高度)
- 注意: 返回的数值都不带单位
-
offset 系列常用属性:
element.offsetParent 返回作为该元素带有定位(position)的父级元素,如果父级都没有定位则返回body element.offsetTop 返回元素相对带有定位(position)父元素上方的偏移 element.offsetLeft 返回元素相对带有定位(position)父元素左边框的偏移 element.offsetWidth 返回自身包括padding、边框、内容的宽度,返回值不带单位 element.offsetHeight 返回自身包括padding、边框、内容的高度,返回值不带单位
- 注意:offsetParent、offsetTop、offsetLeft有个关键词带有定位,即父元素必须是定位元素。
- 只有父元素是定位元素,这样才能返回offsetTop、offsetLeft距离父元素的顶部和左边的距离,否则就返回距离body的左边、顶部的距离
-
代码举例:
* { margin: 0; padding: 0; } .father { width: 100px; height: 100px; background-color: #ff0; margin: 100px; /* position: relative; */ } .son { width: 50px; height: 50px; background-color: #0f0; margin-left: 25px; } <div class="father"> <div class="son"></div> </div> <script> var father = document.querySelector('.father'); var son = document.querySelector('.son'); // 距离父盒子顶部,100 console.log(father.offsetTop); // 距离父盒子左边,100 console.log(father.offsetLeft); // 父类不是定位元素,所以参照为body // 125 console.log(son.offsetLeft); // 如果给father元素添加position: relative;属性,则参照物就是father // 100 // console.log(son.offsetLeft); // 100 console.log(son.offsetTop); </script>
- offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
- offset 与 style 区别
- offset
- offset 可以得到任意样式表中的样式值
- offset 系列获得的数值是没有单位的
- offsetWidth 包含padding+border+width
- offsetWidth 等属性是只读属性,只能获取不能赋值
- 所以,我们想要获取元素大小位置,用offset更合适
- style
- style 只能得到行内样式表中的样式值
- style.width 获得的是带有单位的字符串
- style.width 获得不包含padding和border 的值
- style.width 是可读写属性,可以获取也可以赋值
- 所以,我们想要给元素更改值,则需要用style改变
- offset
案例使用
-
案例1:获取鼠标在盒子内的坐标
<style> * { margin: 0; padding: 0; } .box { width: 100px; height: 100px; margin: 100px; background-color: #ff0; } </style> <body> <!-- 获取鼠标点击在盒子中的坐标 --> <div class="box"></div> <script> var box = document.querySelector('.box'); box.onclick = function(e){ // 鼠标点击的位置距离文档的坐标 console.log(e.pageX,e.pageY); // 盒子距离body的距离 console.log(this.offsetTop,this.offsetLeft); // 计算出点击点距离盒子的坐标 var y = e.pageY - this.offsetTop; var x = e.pageX - this.offsetLeft; console.log(x,y); } </script> </body>
-
案例2:模态框弹出+拖拽
- 案例分析
- 点击弹出层, 模态框和遮挡层就会显示出来 display:block;
- 点击关闭按钮,模态框和遮挡层就会隐藏起来 display:none;
- 在页面中拖拽的原理: 鼠标按下并且移动, 之后松开鼠标
- 触发事件是鼠标按下 mousedown, 鼠标移动mousemove 鼠标松开 mouseup
- 拖拽过程: 鼠标移动过程中,获得最新的值赋值给模态框的left和top值, 这样模态框可以跟着鼠标走了
- 鼠标按下触发的事件源是 最上面一行,就是 id 为 title
- 鼠标的坐标 减去 鼠标在盒子内的坐标, 才是模态框真正的位置。
- 鼠标按下,我们要得到鼠标在盒子的坐标。
- 鼠标移动,就让模态框的坐标 设置为 : 鼠标坐标减去盒子坐标即可,注意移动事件写到按下事件里面。(因为只有按下了,才会移动)
- 鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除
-
代码举例:
<style> .login-header { width: 100%; text-align: center; height: 30px; font-size: 24px; line-height: 30px; } ul,li,ol,dl,dt,dd,div,p,span,h1,h2,h3,h4,h5,h6,a { padding: 0; margin: 0; } .login { display: none; width: 512px; height: 280px; position: fixed; border: #ebebeb solid 1px; left: 50%; top: 50%; background: #ffffff; box-shadow: 0px 0px 20px #ddd; z-index: 9999; transform: translate(-50%, -50%); } .login-title { width: 100%; margin: 10px 0px 0px 0px; text-align: center; line-height: 40px; height: 40px; font-size: 18px; position: relative; cursor: move; } .login-input-content { margin-top: 20px; } .login-button { width: 50%; margin: 30px auto 0px auto; line-height: 40px; font-size: 14px; border: #ebebeb 1px solid; text-align: center; } .login-bg { display: none; width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; background: rgba(0, 0, 0, .3); } a { text-decoration: none; color: #000000; } .login-button a { display: block; } .login-input input.list-input { float: left; line-height: 35px; height: 35px; width: 350px; border: #ebebeb 1px solid; text-indent: 5px; } .login-input { overflow: hidden; margin: 0px 0px 20px 0px; } .login-input label { float: left; width: 90px; padding-right: 10px; text-align: right; line-height: 35px; height: 35px; font-size: 14px; } .login-title span { position: absolute; font-size: 12px; right: -20px; top: -30px; background: #ffffff; border: #ebebeb solid 1px; width: 40px; height: 40px; border-radius: 20px; } </style> <body> <div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div> <div id="login" class="login"> <div id="title" class="login-title">登录会员 <span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span> </div> <div class="login-input-content"> <div class="login-input"> <label>用户名:</label> <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input"> </div> <div class="login-input"> <label>登录密码:</label> <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input"> </div> </div> <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div> </div> <!-- 遮盖层 --> <div id="bg" class="login-bg"></div> <script> // 1. 获取元素 var login = document.querySelector('.login'); var mask = document.querySelector('.login-bg'); var link = document.querySelector('#link'); var closeBtn = document.querySelector('#closeBtn'); var title = document.querySelector('#title'); // 2. 点击弹出层这个链接 link 让mask 和login 显示出来 link.addEventListener('click', function() { mask.style.display = 'block'; login.style.display = 'block'; }) // 3. 点击 closeBtn 就隐藏 mask 和 login closeBtn.addEventListener('click', function() { mask.style.display = 'none'; login.style.display = 'none'; }) // 4. 开始拖拽 // (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标 title.addEventListener('mousedown', function(e) { var x = e.pageX - login.offsetLeft; var y = e.pageY - login.offsetTop; // (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值 document.addEventListener('mousemove', move) function move(e) { login.style.left = e.pageX - x + 'px'; login.style.top = e.pageY - y + 'px'; } // (3) 鼠标弹起,就让鼠标移动事件移除 document.addEventListener('mouseup', function() { document.removeEventListener('mousemove', move); }) }) </script> </body>
- 案例分析
元素可视区 client 系列
- client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列 的相关属性可以动态的得到该元素的边框大小、元素大小等。
-
client 系列属性
element.clientTop 返回元素上边框的大小 element.clientLeft 返回元素左边框的大小 element.clientWidth 返回自身包括padding、内容区的宽度,不包含边框,返回数值不带单位 element.clientHeight 返回自身包括padding、内容区的高度,不包含边框,返回数值不带单位
-
代码举例:
div { width: 100px; height: 100px; background-color: #ff0; border: 10px solid #000; } <body> <div></div> <script> var div = document.querySelector('div'); // 不包含边框的尺寸 // 100 console.log(div.clientWidth); // 100 console.log(div.clientHeight); // 边框尺寸10 console.log(div.clientTop); console.log(div.clientLeft); </script> </body>
元素滚动 scroll 系列
- 元素 scroll 系列属性
-
scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。
element.scrollTop 返回被卷去的顶部距离,返回数据不带单位 element.scrollLeft 返回被卷去的左侧距离,返回数据不带单位 element.scrollWidth 返回自身实际的宽度,不含边框,返回数值不带单位 element.scrollHeight 返回自身实际的高度,不含边框,返回数值不带单位
-
- 页面被卷去的头部
- 如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏 掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发 onscroll事件。
- 拖动滚动条就会触发onscroll事件
- 页面被卷去的头部兼容性解决方案
- 需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:
- 声明了 DTD,使用 document.documentElement.scrollTop
- 未声明 DTD,使用 document.body.scrollTop
- 新方法 window.pageYOffset 和 window.pageXOffset,IE9 开始支持
-
代码:
function getScroll() { return { left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0, top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0 }; } //使用的时候 getScroll().left
- 需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:
- 代码举例:
-
案例1
div { width: 100px; height: 100px; background-color: pink; border: 10px solid red; padding: 10px; /* 显示滚动条 */ overflow: auto; } <body> <div>很多内容 很多内容 很多内容 很多内容 很多内容 很多内容 很多内容 很多内容 很多内容 很多内容</div> <script> var div = document.querySelector('div'); // 176 console.log(div.scrollHeight); // 100 console.log(div.scrollWidth); // 监听滚动条事件 div.onscroll = function() { console.log(div.scrollTop); } </script> </body>
- 案例2:监听页面滚动,滚动到一定位置,页面上的侧边栏元素悬浮固定
- 效果
- 原先侧边栏是绝对定位
- 当页面滚动到一定位置,侧边栏改为固定定位
- 页面继续滚动,会让 “返回顶部”显示出来
- 需要用到页面滚动事件 scroll 因为是页面滚动,所以事件源是document
- 滚动到某个位置,就是判断页面被卷去的上部值。
- 页面被卷去的头部:可以通过window.pageYOffset获得 如果是被卷去的左侧 window.pageXOffset
- 注意,元素被卷去的头部是 element.scrollTop , 如果是页面被卷去的头部 则是 window.pageYOffset
- 其实这个值 可以通过盒子的 offsetTop 可以得到,如果大于等于这个值,就可以让盒子固定定位了
- 效果
-
代码举例:
<style> .slider-bar { position: absolute; left: 50%; top: 300px; margin-left: 600px; width: 45px; height: 130px; background-color: pink; } .w { width: 1200px; margin: 10px auto; } .header { height: 150px; background-color: purple; } .banner { height: 250px; background-color: skyblue; } .main { height: 1000px; background-color: yellowgreen; } span { display: none; position: absolute; bottom: 0; } </style> <div class="slider-bar"> <span class="goBack">返回顶部</span> </div> <div class="header w">头部区域</div> <div class="banner w">banner区域</div> <div class="main w">主体部分</div> <script> //1. 获取元素 var sliderbar = document.querySelector('.slider-bar'); var banner = document.querySelector('.banner'); // banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面 var bannerTop = banner.offsetTop // 当我们侧边栏固定定位之后应该变化的数值 var sliderbarTop = sliderbar.offsetTop - bannerTop; // 获取main 主体元素 var main = document.querySelector('.main'); var goBack = document.querySelector('.goBack'); var mainTop = main.offsetTop; // 2. 页面滚动事件 scroll document.addEventListener('scroll', function() { // console.log(11); // window.pageYOffset 页面被卷去的头部 // console.log(window.pageYOffset); // 3 .当我们页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位 if (window.pageYOffset >= bannerTop) { sliderbar.style.position = 'fixed'; sliderbar.style.top = sliderbarTop + 'px'; } else { sliderbar.style.position = 'absolute'; sliderbar.style.top = '300px'; } // 4. 当我们页面滚动到main盒子,就显示 goback模块 if (window.pageYOffset >= mainTop) { goBack.style.display = 'block'; } else { goBack.style.display = 'none'; } }) </script>
-
三大系列总结
- 区别:
- element.offsetWidth:返回自身包括padding、边框、内容的宽度,返回值不带单位
- element.clientWidth:返回自身包括padding、内容区的宽度,不包含边框,返回数值不带单位
- element.scrollWidth:返回自身实际的宽度,不含边框,返回数值不带单位
- 他们主要用法:
- offset系列 经常用于获得元素位置 offsetLeft offsetTop
- client 经常用于获取元素大小 clientWidth clientHeight
- scroll 经常用于获取滚动距离 scrollTop scrollLeft
- 注意:页面滚动的距离通过 window.pageXOffset 获得
mouseenter 和mouseover的区别
- 当鼠标移动到元素上时就会触发 mouseenter 事件
- 类似 mouseover,它们两者之间的差别是
- mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。 mouseenter 只会经过自身盒子触发
- 之所以这样,就是因为mouseenter不会冒泡,mouseover会冒泡
- 跟mouseenter搭配 鼠标离开 mouseleave 同样不会冒泡
动画函数封装
- 动画实现原理
- 核心原理:通过定时器 setInterval() 不断移动盒子位置。
- 实现步骤:
- 获得盒子当前位置
- 让盒子在当前位置加上1个移动距离
- 利用定时器不断重复这个操作
- 加一个结束定时器的条件
- 注意:此元素需要添加定位,才能使用element.style.left
- 动画函数简单封装
-
注意函数需要传递2个参数,动画对象和移动到的距离。
div { width: 100px; height: 100px; /* 盒子必须定位,才能使用动画 */ position: absolute; background-color: #0f0; left: 0; } // 1. 获取盒子当前位置 var div = document.querySelector('div'); animate(div,300); function animate(obj,target) { // 1. 获取盒子当前位置 // var div = document.querySelector('div'); // 2. 让盒子在当前位置加上1个移动距离 // 3. 利用定时器不断重复这个操作 var timer = setInterval(() => { if(obj.offsetLeft >= target){ clearInterval(timer); } obj.style.left = obj.offsetLeft + 1 + 'px'; }, 30); }
-
- 动画函数给不同元素记录不同定时器
- 如果多个元素都使用这个动画函数,每次都要var 声明定时器。我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)。
-
核心原理:利用 JS 是一门动态语言,可以很方便的给当前对象添加属性。
// 给obj添加一个timer,obj专属定时器 function animate(obj,target) { // 每次执行前先需取消已存在的定时器 clearInterval(obj.timer); //obj自己专门用自己的定时器 obj.timer = setInterval(() => { if(obj.offsetLeft >= target){ clearInterval(obj.timer); } obj.style.left = obj.offsetLeft + 1 + 'px'; }, 30); }
- 缓动效果原理
- 缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来
- 思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
- 核心算法: (目标值 - 现在的位置 ) / 10 做为每次移动的距离 步长
- 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
- 注意:步长值需要取整
-
代码:
// 给obj添加一个timer,obj专属定时器 function animate(obj,target) { // 每次执行前先需取消已存在的定时器 clearInterval(obj.timer); obj.timer = setInterval(() => { // 步长 // 减速移动 // (目标值 - 现在的位置 ) / 10 做为每次移动的距离 步长 // 把步长改为整数,不要小数,小数直接取大于整数 var step = Math.ceil((target - obj.offsetLeft)/10); if(obj.offsetLeft = target){ clearInterval(obj.timer); } obj.style.left = obj.offsetLeft +step + 'px'; }, 15); }
- 动画函数多个目标值之间移动
- 可以让动画函数从 800 移动到 500。
- 当我们点击按钮时候,判断步长是正值还是负值
- 如果是正值,则步长 往大了取整
- 如果是负值,则步长 向小了取整
div { position: absolute; left: 0; width: 100px; height: 100px; background-color: pink; } span { position: absolute; left: 0; top: 200px; display: block; width: 150px; height: 150px; background-color: purple; } <button class="btn500">点击夏雨荷到500</button> <button class="btn800">点击夏雨荷到800</button> <span>夏雨荷</span> <script> // 缓动动画函数封装obj目标对象 target 目标位置 // 思路: // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。 // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长 // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器 function animate(obj, target) { // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步长值写到定时器的里面 // 把我们步长值改为整数 不要出现小数的问题 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); } // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); } var span = document.querySelector('span'); var btn500 = document.querySelector('.btn500'); var btn800 = document.querySelector('.btn800'); btn500.addEventListener('click', function() { // 调用函数 animate(span, 500); }) btn800.addEventListener('click', function() { // 调用函数 animate(span, 800); }) // 匀速动画 就是 盒子是当前的位置 + 固定的值 10 // 缓动动画就是 盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10) </script>
- 动画函数添加回调函数
- 回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执行完之后 ,再执行传进去的这个函数,这个过程就叫做回调。
-
回调函数写的位置:定时器结束的位置。
<button class="btn500">点击夏雨荷到500</button> <button class="btn800">点击夏雨荷到800</button> <span>夏雨荷</span> <script> // 缓动动画函数封装obj目标对象 target 目标位置 // 思路: // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。 // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长 // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器 function animate(obj, target, callback) { // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步长值写到定时器的里面 // 把我们步长值改为整数 不要出现小数的问题 // var step = Math.ceil((target - obj.offsetLeft) / 10); 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(); } } // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); } var span = document.querySelector('span'); var btn500 = document.querySelector('.btn500'); var btn800 = document.querySelector('.btn800'); btn500.addEventListener('click', function() { // 调用函数 animate(span, 500); }) btn800.addEventListener('click', function() { // 调用函数 animate(span, 800, function() { // alert('你好吗'); span.style.backgroundColor = 'red'; }); }) // 匀速动画 就是 盒子是当前的位置 + 固定的值 10 // 缓动动画就是 盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10) </script> </body>
- 动画函数封装到单独JS文件里面
- 因为以后经常使用这个动画函数,可以单独封装到一个JS文件里面,使用的时候引用这个JS文件即可。
- 单独新建一个JS文件。
- HTML文件引入 JS 文件。
- 因为以后经常使用这个动画函数,可以单独封装到一个JS文件里面,使用的时候引用这个JS文件即可。
常见网页特效案例
- 网页轮播图案例(第六天,略)
- 节流阀
- 防止轮播图按钮连续点击造成播放过快。
- 节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
- 核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
- 开始设置一个变量 var flag = true;
- If(flag) {flag = false; do something} 关闭水龙头
- 利用回调函数 动画执行完毕, flag = true 打开水龙头
- 返回顶部
- 滚动窗口至文档中的特定位置。
window.scroll(x, y)
-
注意,里面的x和y 不跟单位,直接写数字
// 3. 当我们点击了返回顶部模块,就让窗口滚动的页面的最上方 goBack.addEventListener('click', function() { // 里面的x和y 不跟单位的 直接写数字即可 // window.scroll(0, 0); // 因为是窗口滚动 所以对象是window animate(window, 0); }); // 动画函数 function animate(obj, target, callback) { // console.log(callback); callback = function() {} 调用的时候 callback() // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步长值写到定时器的里面 // 把我们步长值改为整数 不要出现小数的问题 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - window.pageYOffset) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (window.pageYOffset == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); // 回调函数写到定时器结束里面 // if (callback) { // // 调用函数 // callback(); // } callback && callback(); } // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10 // obj.style.left = window.pageYOffset + step + 'px'; window.scroll(0, window.pageYOffset + step); }, 15); }
- 筋头云案例(略)
移动端网页特效
触屏事件
- 触屏事件概述
- 移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS书写效果,但是移动 端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。
- touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控 笔)对屏幕或者触控板操作。
-
常见的触屏事件如下:
touchstart 手指触摸到一个DOM元素时触发 touchmove 手指在一个DOM上移动时触发 touchend 手指从一个DOM上移开时触发
- 触摸事件对象(TouchEvent)
- TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多 个触点,使开发者可以检测触点的移动,触点的增加和减少,等等
- touchstart、touchmove、touchend 三个事件都会各自有事件对象。
-
触摸事件对象重点我们看三个常见对象列表:
touches 正在触摸屏幕的所有手指的一个列表,检测的是当前屏幕 targetTouches 正在触摸当前DOM元素上的手指的一个列表,检测的是标签元素 changedTouches 手指状态发生了改变的列表,从无到有,从右到无的变化
- 因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes
- 移动端拖动元素
- touchstart、touchmove、touchend 可以实现拖动元素
- 但是拖动元素需要当前手指的坐标值 我们可以使用 targetTouches[0] 里面的pageX 和 pageY
- 移动端拖动的原理: 手指移动中,计算出手指移动的距离。然后用盒子原来的位置 + 手指移动的距离
- 手指移动的距离: 手指滑动中的位置 减去 手指刚开始触摸的位置
- 拖动元素三步曲:
- 触摸元素 touchstart: 获取手指初始坐标,同时获得盒子原来的位置
- 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子
- 离开手指 touchend:
- 注意: 手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动
e.preventDefault();
-
代码举例:
<div></div> <script> var div = document.querySelector('div'); div.onclick = function(){ console.log('pc点击'); } // 将浏览器切换到手机状态 // 手触摸事件 div.ontouchstart = function(e){ console.log('手机点击'); console.log(e); // 下面3个对象都有 console.log(e.touches); console.log(e.targetTouches); console.log(e.changedTouches); // 第一个手指的相关信息 console.log(e.targetTouches[0]); } div.addEventListener('touchmove',function(){ console.log('手指移动'); }) div.addEventListener('touchend',function(){ console.log('手指离开'); // 只有这一个对象 console.log(e.changedTouches); }) </script>
-
手指移动
div { position: absolute; left: 0; width: 100px; height: 100px; background-color: pink; } <div></div> <script> // (1) 触摸元素 touchstart: 获取手指初始坐标,同时获得盒子原来的位置 // (2) 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子 // (3) 离开手指 touchend: var div = document.querySelector('div'); var startX = 0; //获取手指初始坐标 var startY = 0; var x = 0; //获得盒子原来的位置 var y = 0; div.addEventListener('touchstart', function(e) { // 获取手指初始坐标 startX = e.targetTouches[0].pageX; startY = e.targetTouches[0].pageY; x = this.offsetLeft; y = this.offsetTop; }); div.addEventListener('touchmove', function(e) { // 计算手指的移动距离: 手指移动之后的坐标减去手指初始的坐标 var moveX = e.targetTouches[0].pageX - startX; var moveY = e.targetTouches[0].pageY - startY; // 移动我们的盒子 盒子原来的位置 + 手指移动的距离 this.style.left = x + moveX + 'px'; this.style.top = y + moveY + 'px'; e.preventDefault(); // 阻止屏幕滚动的默认行为 }); </script>
移动端常见特效
- banner滚动图,(day-7略)
- 手指滑动轮播图
- 本质就是ul跟随手指移动,简单说就是移动端拖动元素
- 触摸元素 touchstart: 获取手指初始坐标
- 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子
- 离开手指 touchend: 根据滑动的距离分不同的情况
- 如果移动距离小于 某个像素 就回弹原来位置
- 如果移动距离大于某个像素就上一张下一张滑动
- 滑动也分为左滑动和右滑动 判断的标准是 移动距离正负 如果是负值就是左滑 反之右滑
- 如果是左滑 就播放下一张 (index++)
- 如果是右滑 就播放上一张 (index–)
- 手指滑动轮播图
- 返回顶部(略)
classList 属性
- classList属性是HTML5新增的一个属性,返回元素的类名。但是ie10以上版本支持。
- 该属性用于在元素中添加,移除及切换 CSS 类。有以下方法
-
添加类:
element.classList.add(’类名’); focus.classList.add(‘current’);
-
移除类:
element.classList.remove(’类名’); focus.classList.remove(‘current’);
-
切换类:
element.classList.toggle(’类名’); focus.classList.toggle(‘current’);
-
- 注意以上方法里面,所有类名都不带点
-
举例:
.on{ background-color: #000; } <div class="one two"></div> <button>切换类名(开关灯)</button> <script> var div = document.querySelector('div'); var button = document.querySelector('button'); // 返回元素的类名[one,two] console.log((div.classList)); // 添加类名 div.classList.add('three'); // 返回元素的类名[one,two,three] console.log((div.classList)); // 移除类名 div.classList.remove('one'); // 返回元素的类名[two,three] console.log((div.classList)); // 切换类名 button.onclick = function() { // 如果div没有two类,就给他加上,如果有,就删除,来回切换 div.classList.toggle('two'); // [two,three]/[three],之间切换 console.log((div.classList)); // 开关灯切换 document.body.classList.toggle('on'); } </script>
click 延时解决方案
- 移动端 click 事件会有300ms的延时,原因是移动端屏幕双击会缩放(double tap to zoom) 页面。
- 300ms就是一个等待时间,看看用户是否要双击
- 解决方案:
-
方案1:禁用缩放。 浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟。(常用!)
<meta name="viewport" content="user-scalable=no">
-
方案2:利用touch事件自己封装这个事件解决 300ms 延迟。原理就是:
- 当我们手指触摸屏幕,记录当前触摸时间
- 当我们手指离开屏幕, 用离开的时间减去触摸的时间
- 如果时间小于150ms,并且没有滑动过屏幕, 那么我们就定义为点击
-
-
click 延时解决方案
//封装tap,解决click 300ms 延时 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; }); } //调用 tap(div, function(){// 执行代码});
- 解决方案3:使用插件
- 使用插件。fastclick 插件解决 300ms 延迟。
移动端常用开发插件
- 什么是插件
- 移动端要求的是快速开发,所以我们经常会借助于一些插件来帮我完成操作,那么什么是插件呢?
- JS 插件是 js 文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用。如轮播图和瀑布流插件。
- 特点:它一般是为了解决某个问题而专门存在,其功能单一,并且比较小。
- 我们以前写的animate.js 也算一个最简单的插件
- fastclick 插件解决 300ms 延迟。 使用延时
- GitHub官网地址: https://github.com/ftlabs/fastclick
- 插件的使用
- 到github找到lib文件夹,打开拿到fastclick.js文件
- 将fastclick.js文件拖入到项目文件中
- 引入 js 插件文件。
- 按照规定语法使用。
-
fastclick 插件解决 300ms 延迟。 使用延时
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- 进入第三方插件 --> <script type='application/javascript' src='/path/to/fastclick.js'></script> </head> <body> <div></div> <script> // dom元素加载完毕(DOMContentLoaded)执行这个代码 // 当前dom元素中所有的元素都去掉300ms延时问题了 if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } var div = document.querySelector('div'); div.addEventListener('click',function() { alert(11); }); </script> </body>
- Swiper 插件的使用
- 中文官网地址: https://www.swiper.com.cn/
- 引入插件相关文件。
- 按照规定语法使用
- 作用:
- 一个开源强大的触摸滑动的各种功能
- 轮播图、上下滑动等
- 中文官网地址: https://www.swiper.com.cn/
- 其他移动端常见插件
- superslide: http://www.superslide2.com/
- iscroll: https://github.com/cubiq/iscroll
- 插件的使用总结
- 确认插件实现的功能
- 去官网查看使用说明
- 下载插件
- 打开demo实例文件,F12查看源码,查看需要引入的相关文件,并且引入
- 复制demo实例文件中的结构html,样式css以及js代码,到自己项目中
- 移动端视频插件 zy.media.js
- H5 给我们提供了 video 标签,但是浏览器的支持情况不同。
- 不同的视频格式文件,我们可以通过source 解决。
- 但是外观样式,还有暂停,播放,全屏等功能我们只能自己写代码解决。
- 这个时候我们可以使用插件方式来制作。
移动端常用开发框架
- 框架概述
- 框架,顾名思义就是一套架构,它会基于自身的特点向用户提供一套较为完整的解决方案。框架的控制权在框架 本身,使用者要按照框架所规定的某种规范进行开发。
- 插件一般是为了解决某个问题而专门存在,其功能单一,并且比较小。
- 前端常用的框架有 Bootstrap、Vue、Angular、React 等。既能开发PC端,也能开发移动端
- 前端常用的移动端插件有 swiper、superslide、iscroll等。
- 框架: 大而全,一整套解决方案
- 插件: 小而专一,某个功能的解决方案
- Bootstrap
- Bootstrap 是一个简洁、直观、强悍的前端开发框架,它让 web 开发更迅速、简单。
- 它能开发PC端,也能开发移动端
- Bootstrap JS插件使用步骤:
- 引入相关js 文件
- 复制HTML 结构
- 修改对应样式
- 修改相应JS 参数
- 用Bootstrap就可以做轮播图效果