效果:
- 弧形菜单,文字按规则变形以及变换透明度
- 简单的 javascript,上手难度:简单
- 欢迎来我的博客看此文章:https://clatterrr.com/archive…
源码:
- 演示地址:https://clatterrr.github.io/m…
- 源码:https://github.com/clatterrr/…
学习笔记:
text-decoration:
最主要的功能就是给文字加上附着在文字底部,上方,或者中间的线(删除线 )。参考:https://www.w3school.com.cn/c…
none
默认。定义标准的文本。
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;}
然后是邻近顶部和底部的线性渐变,这样看来菜单项似乎和背景融为一体了
.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>
第二步:
当按下按钮时,执行 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 没有关系,看看前面的定义即可。
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()。更多 Callback 函数的知识请看 https://blog.csdn.net/UnderIc…,我在这儿就不多说了。
但到底执行的函数是什么样子?单独放出来一看,注意按向上的按钮时,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();}