效果:
弧形菜单, 文字按规则变形以及变换透明度
简单的 JavaScript, 上手难度: 简单
学习笔记:
text-decoration:
最主要的功能就是给文字加上附着在文字底部, 上方, 或者中间的线(删除线).
默认. 定义标准的文本.
underline
定义文本下的一条线.
overline
定义文本上的一条线.
line-through
定义穿过文本下的一条线.
inherit
规定应该从父元素继承 text-decoration 属性的值.
隐藏超出边界的子元素:
该例子中有 13 个菜单项, 但只显示出 12 个, 因为第 1 个和第 13 个超出了父元素的边界, 被隐藏了.
overflow: hidden;
渐入隐藏效果:
第 2,3,11,12 个虽然没有被隐藏, 但看起来很朦胧. 这样的效果首先是设置透明度, 嗯, nth-child 的用法
- .item:nth-child(2), .item:nth-child(3), .item:nth-child(11), .item:nth-child(12) {
- opacity: 0.2;
- }
然后是邻近顶部和底部的线性渐变, 这样看来菜单项似乎和背景融为一体了
web 前端开发学习 Q-q-u-n: 731771211, 分享学习的方法和需要注意的小细节, 不停更新最新的教程和学习方法(详细的前端项目实战教学视频, PDF)
- .top {
- top: 0;
- background: linear-gradient(to bottom, steelblue 0%, rgba(70, 130, 180, 0) 100%);
- }
- .bottom {
- bottom: 0;
- background: linear-gradient(to bottom, rgba(70, 130, 180, 0) 0%, steelblue 100%);
- }
按钮触摸渐变:
下面这行代码的效果时, 当鼠标放上按钮时, 按钮花 3 秒从白色渐变成黑色, 离开时立马从黑色变为白色.
- .btn {
- color: white;
- }
- .btn:hover {
- color: black;
- transition: color 3s;
- }
如果我们想鼠标离开时也是黑色逐渐变为白色怎么办? 同样加个 transition:
- .btn {
- color: white;
- transition: color 3s;
- }
- .btn:hover {
- color: black;
- transition: color 3s;
- }
吐槽一下, 这儿的上下按钮是两个特殊符号, 见 html.win10 输入法自带许多特殊符号, 够弄出很多好玩的东西了
- <div class="btn prev" onClick="animation({}, 1);">
- ˄
- </div>
- <div class="btn next" onClick="animation({}, 0);">
- ˅
- </div>
由于符号本身很小, 于是用 scale 放大, 为了防止用户复制内容时不小心选中它, 以及为了防止被用户看出来是个符号, 加上一个 user-select:none, 这样用户就选不中了.
- .btn {
- transform: scale(3, 1);
- user-select: none;
- }
JavaScript 详细解释:
第一步:
初始话一波, 把除按钮之外的东西都定义好, 就形成了一开始看到的界面
- const srart_pos = 90.75;
- const item_count = 13;
- const s = 0.52 * Math.PI / 180; // 计算位移角度
- var pos = [];
- var elem = document.getElementsByClassName('item');
- function allocationItems() {
- // 首先设置第 7 个元素处于中间最大的位置
- var i;
- var pp = elem[6].getElementsByTagName('a')[0].getAttribute('data-img');
- document.getElementById("pic").style.backgroundImage = "url('" + pp + "')";
- document.getElementById("pic").className = "img-box";
- // 计算其它菜单项的位置
- pos[0] = srart_pos;
- for (i = 1; i <item_count; i++) {
- pos[i] = pos[i - 1] - 0.2;
- last_pos = pos[i];
- }
- for (i = 0; i < item_count + 1; i++) {
- elem[i].style.left = 240 + 250 * Math.sin(pos[i]) + 'px';
- elem[i].style.top = 240 + 250 * Math.cos(pos[i]) + 'px';
- }
- }
- allocationItems();
注意下面这句, getAtrribute 的名字要和 HTML 设定的属性值一样, 看到 data-img 了吗? 不过这个名字随便取就行了, 叫 "photo" 之类的也可以, 只要保证 JS 和 HTML 一样就行
- var pp = elem[6].getElementsByTagName('a')[0].getAttribute('data-img');
- <a href=""data-img="img/6.jpg"target="_blank"rel="noopener">
- Can I use... Support tables for HTML5, CSS3, etc
- </a>
Web 前端开发学习 Q-q-u-n: 731771211, 分享学习的方法和需要注意的小细节, 不停更新最新的教程和学习方法(详细的前端项目实战教学视频, PDF)
第二步:
当按下按钮时, 执行 animation(), 传个参数, 1 为向上, 0 为向上. 现在看看 animtaion 函数里面有什么. 首先是定义一些东西
- var $ = {
- radius: 250, // 圆周半径
- speed: 10 // 速度单位
- }
- var e = elem;
- document.getElementById("pic").className = "hide";
- console.log(3);
然后执行函数 animate(). 不过这个执行函数把别的函数当成参数传进去了, 注意看. 先不管当成参数传的函数是什么, 暂时用不上.
- animate(function () {
- console.log(1);
- var i;
- for (i = 0; i <item_count; i++) {
- e[i].style.left = 240 + $.radius * Math.sin(pos[i]) + 'px';
- e[i].style.top = 240 + $.radius * Math.cos(pos[i]) + 'px';
- if (flag) {
- pos[i] += s;
- } else {
- pos[i] -= s;
- }
- } /* callback function */
- }, 400, function changeItems() {
- console.log(2);
- var list = document.getElementById('list');
- var ch = flag ? list.firstElementChild : list.lastElementChild
- ch.remove();
- if (flag) {
- list.appendChild(ch);
- } else {
- list.insertBefore(ch, list.firstChild);
- }
- allocationItems();
- });
然后看看 animate()函数的定义:
- function animate(draw, duration, callback) {
- console.log(4);
- var start = performance.now();
- requestAnimationFrame(function run(time) {
- console.log(5);
- // 自启动来 (按下按钮) 的时差
- var timePassed = time - start;
- console.log(time, start)
- // 不能超过最大持续时间
- if (timePassed> duration)
- timePassed = duration;
- // 重新绘制菜单项的位置
- draw();
- console.log(6);
- if (timePassed < duration) {
- console.log(7);
- requestAnimationFrame(run);
- } else
- {
- console.log(8);
- callback();
- console.log(9);
- }
- });
- }
先用 performance.now()确定按下按钮的时间, 储存在 start 中. 然后用 requestAnimationFrame 执行 run 函数. 至于 run 函数是什么, 已经在 requestAnimationFrame 函数中定义好了.
注意 requestAnimationFrame 调用时会给其中的函数传入 DOMHighResTimeStamp 参数, 该参数与 performance.now()的返回值相同, 它表示 requestAnimationFrame() 开始去执行其中函数的时刻. 这就是为什么 run 函数的定义中会有个 time 参数了, 其实就是目前的时刻.
每次执行 run 函数, 都要执行一遍 draw 函数. draw 我单独放了出来, 便于理解. 仔细一看, 这不就是更新菜单项的位置吗? 菜单项位置并不是一下就从原位置到了指定位置, 而是慢慢地移过去的, 所以看起来很流畅. 注意这儿的 $ 和 jQuery 没有关系, 看看前面的定义即可.
Web 前端开发学习 Q-q-u-n: 731771211, 分享学习的方法和需要注意的小细节, 不停更新最新的教程和学习方法(详细的前端项目实战教学视频, PDF)
- function draw() {
- console.log(1);
- var i;
- for (i = 0; i < item_count; i++) {
- e[i].style.left = 240 + $.radius * Math.sin(pos[i]) + 'px';
- e[i].style.top = 240 + $.radius * Math.cos(pos[i]) + 'px';
- if (flag) {
- pos[i] += s;
- } else {
- pos[i] -= s;
- }
- }
- }
返回 run 函数, 如果现在播放时间还没到规定的时间的话, 再执行一遍 run 函数. 如此反复下去. 如果到了规定时间的话, 就执行 callback().
但到底执行的函数是什么样子? 单独放出来一看, 注意按向上的按钮时, flag = 1, 否则 flag = 0. 假如按了向上的按钮, 所有菜单项逆时针向上转, 这时第一个菜单项需要接着第十三个菜单项后面, 否则后面就空了. 于是就把第一个菜单项取下来 remove(), 掉, 于是原来的第二到第十三菜单项序号都变小一个, 第八个变成了第七个, 变成了最大的那个. 然后再把取下的第一个当成第十三个接在最后面, 又成了新的菜单排列.
按向下的按钮也是一样.
- function changeItems() {
- console.log(2);
- var list = document.getElementById('list');
- var ch = flag ? list.firstElementChild : list.lastElementChild
- ch.remove();
- if (flag) {
- list.appendChild(ch);
- } else {
- list.insertBefore(ch, list.firstChild);
- }
- allocationItems();
- }
来源: http://www.jianshu.com/p/72bfc46eec49