移动端字体大小调节器实现

时间:2022-08-24 18:21:03

最近在一个微信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,后来隐约记得有个元素可以充当这个来调节器来用,是它,是它,就是它:inputinput 中有一个属性 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/