画一个时钟
demo与效果

将元素按圆弧排放的两种方法
css方法 –表盘刻度
将元素旋转后,自身坐标系改变,再对所有元素等距离等方向位移即可。
计算坐标点方法 –表盘数字
见上面《css方法》图
度与弧度制转换
π 相当于 180度, 1度转换为弧度制的值就是 π /180:
1度=π /180=Math.PI/180
cos、sin与圆几何度经典应用
transform-origin的细微处理
时针与刻度都用了transform-origin:left center;
更多讲解参考
全屏切换效果(轮播)
demo与效果
轮播切换设计方案
三层div设计
如下图,代码如下,说明的是,设置overflow: hidden;起到裁剪的作用,设置外层(container)是为了在文档流中预定位置。1
2
3
4
5
6
7
8
9
10
11
12<div id="container" data-PageSwitch>
<div class="sections">
<div class="section active" id="section0">
</div>
<div class="section" id="section1">
</div>
<div class="section" id="section2">
</div>
<div class="section" id="section3">
</div>
</div>
</div>
1 | #container{ |
translateY实现切换显示
根据上面的三层div设置后,外层因为使用overflow hidden 遮挡了 sections壳的全部内容,形成裁剪效果,不过sections实际是全部显示的,
因此对sections使用translateY实现切换显示。
内外三层都使用 height: 100%技巧
如上面代码, #container,.sections,.section都使用了height: 100%;让三者的高度保持一致。因为切换显示也是将内层的section全屏展示在container上,因此这种方法非常棒。
offsetTop获取translateY偏移值
offsetTop是非常棒的方法,使用方法自行网上查询。虽然上面的section0 section1 section2 section3可能没有被显示,但是它们相对于container或sections的offsetTop是确定好的。
每次轮播的时候,记住index值,根据index获取轮播单元 section,获取它的offsetTop获取translateY偏移值。
记住轮播单元的index很关键
显示哪一页都是index进行标识,设计这个轮播插件,关键是处理index,处理好index了,其他都是围绕这个处理。
有趣的动画监听事件transitionend
本demo为了效果立体,设置了transitionend,有兴趣可参看demo
图片跑马灯(轮播)
demo与效果
这里还有一个jquery版本的demo jquery版本的demo 效果,方便理解,可以看看。
基本原理同上面的《全屏切换效果(轮播)》
最后位置重复添加第一张图片
如果不在最后的位置添加第一张图片,会有一个留白的效果。
原理在于,当transform: translateX(-1800px);时,此时页面将显示那张重复放置的第一张图片,
因为animation的动画在translateX(-1800px)时完成,设置的infinite特性,将瞬间0秒回到初始位置,也就是页面只有第一张图片的时候,此时就不会出现空白页,且图片循环播放流畅。1
2
3
4
5
6
7
8
9<div class="marquee">
<div class="content">
<div class="list"><img src="./../css/i/timg.jpg" alt=""></div>
<div class="list"><img src="./../css/i/timg1.jpg" alt=""></div>
<div class="list"><img src="./../css/i/timg2.jpg" alt=""></div>
<!-- 重复放置第一张图片 -->
<div class="list"><img src="./../css/i/timg.jpg" alt=""></div>
</div>
</div>
1 | .marquee, .content, .list{ |
页面留白问题分析与解决
参考上面《最后位置重复添加第一张图片》
使用animation的infinite特性保持循环流畅
参考上面《最后位置重复添加第一张图片》
怎么做左到右的循环播放
上面的例子是右到左的轮播,因此在最后的位置添加了第一张图片,如果需要左到右轮播,则在最开始的位置添加最后一张图片。
JS实现京东无延迟菜单效果
demo与效果
介绍
一级菜单与二级菜单
如上图,左侧菜单称之为一级,右侧内容显示称之为二级菜单。
需求分析
垂直运动不延时
在一级菜单如下图做垂直运动时不延时,当测斜运动并处于三角区内时,做延时显示右侧面板,以达到选择好一级后,光标移到右侧二级时,二级不消失。
三角区内移到二级时做延时
分析如上《垂直运动不延时》
判断三角区内的方案
方案设计
通过mousemove记录光标的移动路径,在全局内存储光标移动路径(坐标点),以二级菜单区域的右上角和右下角作为三角区内亮点,
给一级菜单都绑定mouseenter。
当mouseenter触发时,取全局移动路径的最后两个点,倒数第二个点为三角区第三个点,最后一个点为p点,判断p点是否处于上面三个点构成的三角区内。
document 绑定mouseenter
以此记录光标移动路径,这是常规做法。记住不用的时候需要解绑。
一级菜单mouseenter触发时计算三角区
如上面《方案分析》
二维向量叉乘判断是否在三角内
- 向量:Vab=Pb-Pa
- 二维向量叉乘公式:
a(x1,y1)b(x2,y2)=x1y2-x2*y1 - 用叉乘法判断点在三角形内
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28//判断 a b 是否全部为负数 或 正数;
function sameSign(a, b) {
return(a * b) > 0
}
function vector(p, b) {
return {
x: b.x - p.x,
y: b.y - p.y
}
}
function vectorProduct(v1, v2) {
return v1.x * v2.y - v2.x * v1.y
}
function isPointInTrangle(p, a, b, c) {
var pa = vector(p, a)
var pb = vector(p, b)
var pc = vector(p, c)
var t1 = vectorProduct(pa, pb)
var t2 = vectorProduct(pb, pc)
var t3 = vectorProduct(pc, pa)
return sameSign(t1, t2) && sameSign(t2, t3)
}
isPointInTrangle(currMousePos, leftCorner, topLeft, bottomLeft)
二级菜单定义mouseenter
二级菜单定义mouseenter,当鼠标移到二级菜单时,说明二级菜单处于打开状态,此时,在延时处理时不做任何处理。
光标路径移动趋势分析
通过光标移动的最后两个点,来判断光标的移动方向(趋势),这点非常妙。
向量二叉乘
只需要知道坐标,就可以通过向量二叉乘知道某一点是否处于区域内。太妙。
tab二级菜单显示方案
二级菜单样式都一样
二级菜单的布局样式都一样(大小宽高等),需要显示哪一个时,display block/none进行切换。
display的none/block
每次只显示对应的二级菜单,其他二级菜单 display :none。
动画demo 及 css动画知识点
会动的兔八公 与 step
demo与效果
step是针对keyframes内定义的每个百分比的
下面有方式一和方式二,效果是一样的,
step是针对keyframes内定义的每个百分比的,在方式一中keyframes内只定义了一个100%,
因此步进范围与速度为 100%/121
2
3
4
5
6
7
8
9
10
11
12//方式一
.tuzi0 {
width: 200px;
height: 200px;
animation: run2 0.2s steps(12) infinite;
background: url(./i/tuzi.png) no-repeat;
}
@keyframes run2 {
100% {
background-position-x: -2400px;
}
}
在方式二中keyframes内只定义了一个50% 100%,
在0到50%时,步进范围与速度为 50%/6;
在50%到100%时,步进范围与速度为(100%-50%)/6;
因此方式一方式二效果一致。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//方式二
.tuzi {
width: 200px;
height: 200px;
animation: run 0.2s steps(6) infinite;
background: url(./i/tuzi.png) no-repeat;
}
@keyframes run {
50% {
background-position-x: -1200px;
}
100% {
background-position-x: -2400px;
}
}
step的一些认识
动画片一定要用step,比如loading demo;
loading为什么定义成线性时间函数时,会出现晕眼的情况,是因为两个原因:
上一个loading刻度到下一个step时,没有完全踩在上一步step的脚印上,会乱,同时也会造成晕眼;
反之推算出,要实现这种拍浪或loading的效果,或跑火车的效果,就只能完全踩在上一步的脚印上的方案。
step更适合动画片相关场景
参考上面《会动的兔八公 与 step》讲解。
loading效果 - step
demo与效果
step时间函数的经典应用
看demo的效果就知道,loading图片是一个12个刻度的圆,为了不晕图或者混乱,有一种递进的效果,就必须每走一个step,每个刻度踩在上一个刻度的上面,这样就不晕眼,因此,设置了step(12),每个step旋转30度;
而原图的每个刻度之间刚好也是30度;
因此每走一个step,刚好完全踩在上一个刻度上。1
2
3
4
5
6
7
8
9
10
11
12.loading {
width: 108px;
height: 108px;
background: url(../css/i/loading.png) no-repeat;
border-radius: 50%;
animation: round 1s steps(12) 3;
}
@keyframes round {
100% {
transform: rotate(360deg);
}
}
红包雨
demo与效果
核心代码
1 | .content .yudi { |
1 | let $content = $('.content'); |
animation-delay的应用
见上面代码
position: relative 与 absolute的方案;
见源码
彩蛋 - background-size
见上面代码
animation的时间函数
介绍
下面的ease-in-out就是时间函数,animation的时间函数分为线性时间函数与非线性;
线性时间函数全部是三次贝塞尔函数(浏览器控制台调试css时间函数时,通常显示的是一个三次贝塞尔函数正好印证了这一点),
非线性时间函数主要指step。1
2
3
4
5
6.tuzi {
width: 200px;
height: 200px;
animation: run 0.2s ease-in-out infinite;
background: url(./i/tuzi.png) no-repeat;
}
线性函数 - 三次贝塞尔函数bezier
animation的线性时间函数都是三次贝塞尔函数(cubic-bezier):1
2
3
4
5.demo-3 {
margin: 40px auto;
border-radius: 50%;
animation: jump 1s cubic-bezier(0.41, -0.04, 0.93, 0.29) infinite alternate;
}
有一些常规的cubic-bezier(x, x, x, x)值,我们直接用linear ease ease-in ease-out ease-in-out这些关键字来表示,这些关键字也称之为预设值。
就好比 我们用 black 关键字表示 #000000 这种颜色一样。
非线性函数 - step
时间函数的非线性函数一般用step,参考上面的讲解。
预设值linear ease ..
参考上面《线性函数-三次贝塞尔函数bezier》
时间函数的控制台调试
谷歌浏览器提供了强大的css时间函数调试功能,参考一位朋友的博客 - CSS3 动画
动画监听事件animationstart等等
demo
demo效果
用这个的时候,注意以下兼容问题。1
2
3
4$loading.addEventListener('animationstart',runstart);
$loading.addEventListener('webkitAnimationStart',runstart);
$loading.addEventListener('animationend',runend)
$loading.addEventListener('animationiteration',intertation)
虚拟列表
实现原理
写一个div,内部有两个div,一个用于撑开高度,让滚动条真实显示,不过隐藏显示;
一个用于真正渲染数据的div;
下面监听整个div的 scroll事件,通过滑动距离scrollTop,计算实时显示的数据。
主要通过scrollTop与每条数据高度进行计算此时scrollTop应该位于哪个start index,然后通过整个div高度,计算出end index, 实时改变渲染的data。
注意的是,需要通过Transform来模拟滚动的这个技巧。1
2
3
4
5
6
7
8updateVisibleData(scrollTop) {
scrollTop = scrollTop || 0;
const visibleCount = Math.ceil(this.$el.clientHeight / this.itemHeight);
const start = Math.floor(scrollTop / this.itemHeight);
const end = start + visibleCount;
this.visibleData = this.data.slice(start, end);
this.$refs.content.style.webkitTransform = `translate3d(0, ${ start * this.itemHeight }px, 0)`;
},
css与html设计

1 | <div class="list-view"> |
1 | .list-view { |
虽然滚动在list-view-content,但会冒泡到 父层;
当滚动发生时,.list-view-content 也随着滚动上去,因为我们只给.list-view-content渲染可视区域长度,滚动发生时,.list-view-content内容将马上被滚动上去,内容隐藏看不见,此时,就必须给.list-view-content一个webkitTransform = translate3d(0, ${ start * this.itemHeight }
. 才能让页面正常显示。
1 | /* 也可以不使用绝对定位,直接普通 */ |
高度不定时
预判高度的策略
参考《高度不定时,预判高度设计为固定高度》
没有滚动到底时,总高度一直在变
高度不定时,一直滚动,总高度一直变,这时因为没有滚动到底时,总高度用的是预判高度,而预判高度与实际计算高度有差距。
当滚到底后,使用的是缓存高度,总高度不变。
你想不到的
监听到的scrollTop值用于list-view偏移时非常精确
监听到父层到scrolltop值,用于给list-view偏移,非常精确,始终让list-view基本上达到不偏不倚正常显示内容区。
高度不定时,预判高度设计为固定高度
当高度不定时,需要预先计算位置的剩余index高度,这些高度虽然实际高度不一样,但在未滚动到前,一律设定一个默认高度,
用于计算整个列表高度。
如何保证滚动条正常高度

解决之道在于要设计一个div框拥有实际列表总长,隐藏这个div,但又让此div撑开父层,因此设计z-index -1 。
要设计一个div框拥有实际列表总长
参考《如何保证滚动条正常高度》
不用担心父层滚动条被遮住问题
就算你有多层div叠加,上层div也不会覆盖父层滚动条,浏览器只会让滚动条在右侧再增加个位置放置滚动条。
被误解的滚动条遮住问题
一开始以为如果上层 left 0 right 0 时,父层的滚动条会被遮住,后来发现是对浏览器的滚动行为误解了。
参考上面《不用担心父层滚动条被遮住问题》
其他
高度一致最好
高度一致,意味着不用重新计算全部条数据高度,单凭数据length即可计算,性能最高。
拓展:高度不一致、缓存计算
如果高度不一致时,就需要做缓存计算,否则比较耗性能,
参考 与 源码
参考
源码如下
1 | .list-view { |
1 | <script src="//unpkg.com/vue@2.5.15/dist/vue.js"></script> |
1 | const ListView = { |
其他demo
图片预加载
方案设计
通常的做法是,在页面打开后,先添加一个进度条,监听加载进度,设置new Image()用来加载,加载好后,图片哪里需要就在src赋值上即可。
原理
图片通过new Image()加载后,下一次在具体位置再使用src时,就不用等待了,直接就可以用。因此使用new Image() 达到预加载目的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27var images = [{
url: 'https://github.com/CruxF/IMOOC/blob/master/ProImages/ImgPreloading01.jpg?raw=true',
name: '无敌美少女一号'
}]
var $progress = $('.progress');
// 遍历数组,i代表的是数组下标,src代表的是对应数组下标的对象或者属性值
$.each(images, function(i, src) {
//此imgObj不会使用,只用来预加载
var imgObj = new Image();
//当图片有缓存时,不触发load事件,只能使用error来监听兼容此情况
$(imgObj).on('load error', function() {
//通过已加载的图片个数百分比来做进度条
$progress.html(Math.round((count + 1) / len * 100) + '%');
if(count >= len - 1) {
$('.loading').hide();
}
count++;
});
imgObj.src = src.url;
});
//以后使用时,直接赋给src,此时因为之前已经加载过,此时不会再次后台请求,直接秒显示
$('#img').attr({
'src': images[index].url,
'title': images[index].name,
'alt': images[index].name
});
所有图片提前到页面初始时一起加载
参考《原理》
图片加载百分比进度方案
通过已加载的图片个数百分比来做进度条,此方法是普遍做法,见上面代码《原理》;
设置new Image()
参考《原理》
监听load事件
参考《原理》
监听error事件兼容缓存
当图片有缓存时,不触发load事件,只能使用error来监听兼容此情况,参考《原理》
页面要用时再取值
参考《原理》
load与src顺序有讲究
上面的代码中src必须写在on(‘load’)下面,先load,后src赋值,这样可以避免一些隐蔽的问题,比如图片缓存等等。1
2
3 var imgObj = new Image();
$(imgObj).on('load error', function() {});
imgObj.src = src.url;
demo地址
可调大小面板实现
demo与介绍
本demo基于慕课网视频优化而来,demo 地址 demo 效果
方案分析
如下图,要实现左侧,下边,右下侧,三个位置可以拖动,
具体做法是在这三个地方添加一个看不见的拖动用的dom,给这三个dom绑定mouse事件,
在mouseMove中对矩形框持续设置宽高样式,
同时通过css设置三个位置Dom跟随。
具体步骤如下:
设置左、下、左下侧 拖动dom
1 | panelDom = document.getElementById(panelId); |
css设置拖动dom样式跟随矩形框
1 | .ui-Resizable-right{ |
mouseMove中改变矩形框宽高
1 | let newPanelWidth = panelDom.offsetWidth - 2 + moveDistance.x; |
固定侧边栏滚动
demo与介绍
需求分析
要求右侧的侧边栏,正常滚动的时候,正常滚动;
当侧边栏滚到底,但左侧内容还有,需要继续往下滚动时,右侧侧边栏固定显示最后面一段内容。
window.addEventListener(‘scroll’)监听滚动
设置window的滚动事件scroll,当发生滚动时实时监听并设置侧边栏样式。
滚动距离+视口高度 与 侧边栏实际高度 比较
当 滚动距离+视口高度 大于 侧边栏实际高度,启动bottom为0的 position:fixed;
反之,一切正常 position设置为static。1
2
3
4
5
6
7
8
9var sideHeight = domSider.offsetHeight;
var screenHeight =document.documentElement.clientHeight||document.body.clientHeight;
var scrollHeight = document.documentElement.scrollTop||document.body.scrollTop;
//这种思想值得借鉴
if(scrollHeight+screenHeight>sideHeight){
domSider.style.cssText = 'position:fixed;right:0px;bottom: 0px';
}else{
domSider.style.position='static';
}
scrollTop的应用
参考上面《滚动距离+视口高度 与 侧边栏实际高度 比较》
拖动导航条实时显示对应内容
概述
如下,当touchstart 按住左侧导航条,往下拖动时,让左侧显示对应内容。
实现方案
左侧内容区是一个组件,导航条是一个组件。
在导航条上监听三个事件 touchstart 等,三个事件,
通过touchmove计算鼠标当前位置坐标,已知导航条顶部A字母所在位置的坐标,已知每个字母高度,鼠标位置坐标减去导航条顶部坐标,就可计算鼠标当前位于哪个字母上面,
然后通过touchmove实时将对应的字母传给左侧内容组件,
内容组件使用一个scoll插件,此插件可设置滚动到指定的位置,或滚动到指定的元素element上。
因此要实现上面的功能,需要以下元素:
- 获取对应字母的计算方案
- 左侧内容区最好用一个scoll包裹,可设置显示指定位置
touchstart touchmove touchend
touchstart 与touchend的作用就是设置一个touchStatus,标识按住开始拖动时,允许做滚动逻辑处理,松开拖动时,不允许逻辑处理。
剩下的逻辑处理交给touchmove。
网页定位导航特效
demo与介绍

html的锚点做业内跳转
如下,更多参考网上。1
2<a name="add"></a> 或者 <a id="add"></a> (ps:用id兼容性好些)
<a href="#add">跳转到add</a>
window.addEventListener(‘scroll’)监听滚动
监听滚动距离,实时点亮上图右侧的菜单。
CSS Sprite雪碧图应用
demo与介绍
demo
demo效果
雪碧图用多个图标合成一个,可以用来减少http请求,优化性能,主要原理是对background-position的应用。
减少http请求,优化性能
参考上面的讲解。
核心是对background-position的应用
下面是background-position的坐标系:1
2
3
4
5
6.regnow input{
background: url(sp.png) no-repeat;
background-position: 0 -38px;
border: 0;
padding: 0 0 3px 0;
}
