最近在一个微信H5项目中需要用到字体大小调节器,就看了一下QQ中的功能,就做了一个相似的,方法也不止一种,而且都不难。
方法1
html
<div class="wrap">
<div class="line"></div>
<ul class="font-adjust">
<li data-size="14px" class="selected"></li>
<li data-size="16px"></li>
<li data-size="18px"></li>
<li data-size="20px"></li>
<li data-size="22px"></li>
</ul>
</div>
<article style="font-size: 14px">
圣诞已过<br>再加上看过各个大牌出的辣眼睛狗年限定以后<br>我以为未来的几个月应该是没有什么东西<br>能骗到我的钱了<br>直到...看到了ysl的春季限定...<br>我知道<br>钱包又要完。蛋 。了。
</article>
style
<style type="text/css">
* {
margin: 0;
padding: 0;
border: none;
box-sizing: border-box;
}
.wrap {
position: relative;
padding: 0 50px;
border: 1px solid #000;
}
.line {
width: calc(100% - 100px);
height: 1px;
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: #ccc;
}
.font-adjust {
display: flex;
justify-content: space-between;
align-items: center;
height: 50px;
}
.font-adjust li {
position: relative;
list-style: none;
width: 1px;
height: 10px;
background-color: #ccc;
}
.font-adjust li::after {
content: ‘‘;
display: block;
position: absolute;
width: 20px;
height: 20px;
top: 50%;
left: 50%;
border-radius: 50%;
transform: translate(-50%, -50%);
background-color: transparent;
}
.font-adjust li.selected::after {
background-color: #fff;
border: 1px solid #eee;
box-shadow: 0 1px 1px 0 #999;
}
article {
text-align: center;
}
</style>
我们得到这样的页面:
javascript
最简单的单击目标点可以设置对应字体大小:
$(‘.font-adjust li‘).on(‘click‘, function(e) {
$(‘article‘).attr(‘style‘, `font-size: ${$(this).attr(‘data-size‘)}`); // 设置字体大小
$(‘.font-adjust li‘).removeClass(‘selected‘);
$(this).addClass(‘selected‘);
})
在QQ的字体设置中,只要点击起始点在调节区域,之后在整个窗口左右滑动也可以达到调节字体的目的,我这里用的是 touchmove 事件,利用它返回的位置信息,判断当前距离哪个点的水平位置最近,就使用哪个字体大小,代码如下:
var fontModel = [‘14px‘, ‘16px‘, ‘18px‘, ‘20px‘, ‘22px‘]; // 可供选择的字体序列
var current = 0; // 当前使用的字体在序列中的位置下标
var fontModelsPos = $(‘.font-adjust li‘).map(function (index) { // 获得每个标记点的位置 x
return $(‘.font-adjust li‘).eq(index)[0].offsetLeft;
})
$(‘.font-adjust‘).on(‘touchmove‘, function (e) {
e.preventDefault();
var min = {
i: 0,
dis: Math.abs(fontModelsPos[0] - e.changedTouches[0].clientX)
};
for(var i = 1; i < 5; i++){ // 获得最近标记点
var dis = Math.abs(fontModelsPos[i] - e.changedTouches[0].clientX); // 计算触控点和各标记点的距离
if (dis < min.dis) { // 找出最近的那个
min = { i: i, dis: dis }
}
}
if (min.i != current) { // 字体大小改变
current = min.i;
$(‘.font-adjust li‘).removeClass(‘selected‘);
$(‘.font-adjust li‘).eq(min.i).addClass(‘selected‘);
$(‘article‘).attr(‘style‘, `font-size: ${fontModel[min.i]}`)
}
})
效果:
方法2
emmmmm,后来隐约记得有个元素可以充当这个来调节器来用,是它,是它,就是它:input 。input 中有一个属性 type="range" ,使用它可以更方便的完成上述功能。
html
<div class="wrap">
<input type="range" min="0" max="4" step="1" value="0" id="adjust_font">
<!-- 以下模拟横线和定位点 -->
<div class="line"></div>
<ul class="range-simulate">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
这里还是保留了上面的部分代码(5个定位点和1条横线),因为 input 是没有这些点的,横线可以通过更改默认滑轨的样式成为一条细线,但是当滑块在两端时,横线的顶点并不在滑块中央,不介意的话问题也不大。
如下的透视图展示的就是顶点在滑块正中央:
style
<style type="text/css">
* {
margin: 0;
padding: 0;
border: none;
box-sizing: border-box;
}
.wrap {
position: relative;
padding: 10px 50px;
border: 1px solid #000;
}
input[type=range] {
-webkit-appearance: none;
width: 100%;
background-color: transparent;
}
input[type=range]::-webkit-slider-runnable-track { // 滑轨
height: 20px;
}
input[type=range]::-webkit-slider-thumb { // 滑块
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #fff;
border: 1px solid #eee;
box-shadow: 0 1px 1px 0 #999;
}
input[type=range]:focus {
outline: none;
}
.line {
width: calc(100% - 120px);
margin: 0 10px;
height: 1px;
position: absolute;
z-index: -1;
top: 50%;
transform: translateY(-50%);
background-color: #ccc;
}
.range-simulate {
width: calc(100% - 120px);
margin: 0 10px;
display: flex;
justify-content: space-between;
align-items: center;
position: absolute;
z-index: -1;
top: 50%;
transform: translateY(-50%);
}
.range-simulate li {
position: relative;
list-style: none;
width: 1px;
height: 10px;
background-color: #ccc;
}
article {
text-align: center;
}
</style>
javascript
这里的 js 部分就很简单了,简直是送分题:
var fontModel = [‘14px‘, ‘16px‘, ‘18px‘, ‘20px‘, ‘22px‘];
var article = document.getElementById(‘article‘);
document.getElementById(‘adjust_font‘).addEventListener(‘input‘, function (e) {
article.setAttribute(‘style‘, `font-size: ${fontModel[e.target.value]}`);
}, false);
总结
两种方法实现起来看起来都挺简单,但是综合考虑还是第二种方法优先,我考虑的方面主要有三点:
- 当各字体的5个标记点不是一条竖线,而是一个圆或者其他形状的时候,我们需要计算圆的中心点,而众所周知移动端我们可能会用 rem 或者其他单位,这时候计算起来比较棘手了;
- 在 touchmove 事件中处理了很多计算问题,比较消耗资源,有可能会造成用户体验不佳;
- touchmove 事件的兼容性,Safari 暂不支持,有可能会造成困扰。
第三点在我目前的项目中,在微信浏览器是不需要考虑的。
该文章首发于https://blog.bingqichen.me/。