资讯专栏INFORMATION COLUMN

用原生 js && jquery 实现知乎收起答案功能

brianway / 1601人阅读

摘要:需求很简单,而且和知乎的显示全部收起功能非常相似,但是了一下没有找到类似的,因此决定自己实现一个看了知乎的网页代码。

Update 2016.12.7

已封装为插件

原生 js 插件$ npm install foldcontent-zhihu@">=3.0.12" --save Usage

jquery 插件 $ npm install foldcontent-zhihu-jquery@">=1.0.1" --save Usage

Update 2016.11.23

此前demo 定义两个按钮,一个固定定位,一个绝对定位,因此滚动至底部时会出现两个按钮同时出现的问题,用户体验不是很好,因此更改为只有一个按钮,判断滚动至底部时添加 classname 更改样式。且精简了代码ヾ(≧∇≦*)ゝ

scroll 事件性能优化问题。

鼠标滚动时 scroll 事件触发的间隔大约为 10~20 ms,相对于其他的鼠标、键盘事件,它被触发的频率很高,间隔很近。因此如果 scroll 事件涉及大量的位置计算、元素重绘等工作,且这些工作无法在下个 scroll 事件触发前完成,就会导致浏览器掉帧

因此需要减少绑定给 scroll 中具体想要执行的业务逻辑的执行次数

并将对象初始化、不变的高度值等缓存在 scroll 事件外部

存在 bug : 当以很快的速度滚动时,有可能执行不到 scroll 绑定的事件(ó﹏ò),有没得更好的优化方案?

示例代码及 github 均已更新 ٩(ˊᗜˋ*)و

Update 2016.11.22

优化代码结构,存在命名不规范、jquery 方法和原生 js 方法混用、代码未封装、设计冗余等问题。。。review 代码被批了。。。

没有需求的话……就自己提一个 ୧(๑•̀⌄•́๑)૭

起初是要做一个公司内部的 mongoDB 日志查询网站,前端用 bootstrap,后端用 nodejs 做了一个简单的页面,不得不说页面还是很粗陋的,因为一条日志的内容很多,如果直接显示的话内容太过冗长,往往滚动几次才能看完一条日志,而且经常查询的就是固定的几个 key,直接展示不利于迅速debug。

问题确定了,要实现的就是显示日志时只显示经常查询的几个键值对,点击展开时显示全部日志,点击收起时变回原状。

需求很简单,而且和知乎的显示全部&&收起功能非常相似,但是 Google 了一下没有找到类似的 demo,因此决定自己实现一个!

Here we go

看了知乎的网页代码。原理是点击显示全部时,如果这条答案超出浏览器视窗,则收起按钮变成固定定位,js 计算出 right 值,bottom固定为12px;当这条答案底部滚动至浏览器视窗内,收起按钮变回绝对定位。ps 发现知乎是不是改版了,之前答案底部出现在浏览器视窗内后这个位置是有收起按钮的?,按钮从固定定位变为绝对定位并更改样式,就像旁边的作者保留权利这样的风格~(图一直传不上来。。暂时放弃了)

现在的做法是直接隐藏掉固定定位的收起按钮。

其实我的实现方法和知乎的不甚相同,因为他的 js 代码我真心……没看懂!谁能告诉我这种情况应该怎么调试(ノ°ο°)ノ

所以想了另一种思路,在答案右下角定义一个按钮 A,判断答案顶部和底部的相对位置 x 和 y ,其中 y = x + 答案的高度(js 获取)。当答案出现在浏览器视窗内,即 x = $(window).height() 时,给 A 添加固定定位,动态定义 right 值;当答案即将滚出浏览器视窗,即 y = $(window).height() 时,A 变为相对定位,right 值始终为 20px。当 A 的文本内容为收起时,点击 A 文本内容变为展开,去掉固定定位。

此处省去连接数据库等无关工作,仅用两段有趣的文字作为 demo ~

首先,文字内容分为 all-content 和 part-content 两部分,分别为折叠前和折叠后要展示的内容,因为还未搞懂知乎折叠答案后显示哪一部分内容的算法,所以简单粗暴地分了折叠前和折叠后的内容。。此处有一个 TODO ?

  • In the winter that seat is close enough to the radiator to remain warm and yet not so close as to cause perspiration. In the summer ...
    展开
var doc = $(document);
var win = $(window);
// 多次使用, 缓存起来
doc.on("click", ".unfold", function () {
    var unfold = $(this);
    if (unfold.text() !== "收起") {
        unfold.text("收起").siblings(".part-content").hide().siblings(".all-content").show();
        var panel = unfold.parent();
        var panelScroll = panel.offset().top + panel.height();
        var scrollHeight = doc.scrollTop() + win.height();
        var right = win.width() / 2 - 350 + 20 > 20 ? win.width() / 2 - 350 + 20 : 20;
        // 点击展开按钮时即判断是否出现收起按钮
        if (scrollHeight - panelScroll < 50) {
            unfold.addClass("fold-fix").css("right", right);
        }
        // 绑定在 scroll 事件上
        var cb = {
            onscroll: function() {
                var panelScroll = panel.offset().top + panel.height();
                var scrollHeight = doc.scrollTop() + win.height();
                var right = win.width() / 2 - 350 + 20 > 0 ? win.width() / 2 - 350 + 20 : 20;
                if (scrollHeight - panelScroll < 50 &&
                    panel.offset().top - scrollHeight < -90 && unfold.text() !== "展开") {
                    unfold.addClass("fold-fix").css("right", right);
                } else {
                    changeStyle(unfold);
                }
                win.off("scroll", cb.onscroll);
                setTimeout(function() {
                    win.on("scroll", cb.onscroll);
                }, 50);
            }
        };
        win.on("scroll", cb.onscroll);
    } else {
        var fold = $(this);
        changeStyle(fold);
        fold.text("展开").siblings(".part-content").show()
            .siblings(".all-content").hide();
    }
});

function changeStyle(i) {
    i.removeClass("fold-fix").css("right", "20px");
}

此处涉及一个知识点:网页元素的绝对位置 && 相对位置

网页元素的绝对位置,指该元素的左上角相对于整张网页左上角的坐标。jquery 中 offset() 方法返回元素相对于文档的偏移。该方法返回的对象包含两个整型属性:top 和 left。x.offset().top 即为 x 元素的绝对高度;

网页元素的相对位置,指该元素左上角相对于浏览器窗口左上角的坐标。绝对位置减去页面的滚动条滚动的距离就是相对位置。x.offset().top - $(document).scrollTop() 即为 x 元素的相对高度。

本例需要浏览器视窗刚刚滚动至答案a的绝对定位按钮出现的效果,因此此节点为答案底部的相对高度减去浏览器视窗高度正好等于负的按钮 A 的高度。即 a.offset().top + a.height() - $(document).scrollTop() - $(window).height() = - 按钮高度

阮一峰老师的用Javascript获取页面元素的位置这篇文章讲解得十分清晰,如果要深入了解这个知识点建议看一下这篇文章,说不定就有茅塞顿开的感觉哦 ٩(ˊᗜˋ*)و

如何动态设置固定定位的折叠按钮 的 right 值呢?

答案的固定宽度是 700px,因此浏览器视窗宽度减去 700px 再除以 2 便始终是答案的 right 值,因为按钮为绝对定位时 right: 20px; 因此 right: $(window).width()/2 - 350 + 20 就保证了固定定位和绝对定位时按钮都在一条垂直线上,过渡衔接很自然。

当浏览器窗口不断缩小时,上面计算出的固定定位时按钮的 right 值可能为负,这显然不符合需求,因此要设置当计算出的 right 值为负时设置 right 值为 20px。

catch the code

源代码已上传至 my github (ㆆᴗㆆ) ?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80916.html

相关文章

  • 原生 js &amp;&amp; jquery 实现知乎收起答案功能

    摘要:需求很简单,而且和知乎的显示全部收起功能非常相似,但是了一下没有找到类似的,因此决定自己实现一个看了知乎的网页代码。 showImg(https://segmentfault.com/img/remote/1460000008488966);showImg(https://segmentfault.com/img/remote/1460000008488967); Update 20...

    Seay 评论0 收藏0
  • 教你实现React文字展开收起组件

      今天我们讲讲项目中实战就是文字展开收起组件的实现过程,讲解这个就是为了让多给大家一个思路,想法。  简单来说文字展开收起组件产生的需求背景,就是为省略显示,然后有展开收起的按钮可以操作。我们看显示效果上图:  上图是文字收起的图示,超过一定的字数那就收起省略显示,并出现查看全部按钮。  上图显示的就是操作了查看全部按钮之后,文字需要全部显示出来并有收起按钮。还是来看一张gif图的显示最后该组件...

    3403771864 评论0 收藏0
  • 前端资源系列(4)-前端学习资源分享&amp;前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • 库&amp;插件&amp;框架&amp;工具

    摘要:一些有用的一些有用的,包括转换小箭头三角形媒体查询等中文指南是当下最热门的前端资源模块化管理和打包工具。 nodejs 入门 nodejs 入门教程,大家可以在 github 上提交错误 2016 年最好用的表单验证库 SMValidator.js 前端表单验证工具分享 浅谈前端线上部署与运维 说到前端部署,可能大多数前端工程师在工作中都是使用的公司现成的部署系统,与SRE对接、一起完...

    Codeing_ls 评论0 收藏0
  • 库&amp;插件&amp;框架&amp;工具

    摘要:一些有用的一些有用的,包括转换小箭头三角形媒体查询等中文指南是当下最热门的前端资源模块化管理和打包工具。 nodejs 入门 nodejs 入门教程,大家可以在 github 上提交错误 2016 年最好用的表单验证库 SMValidator.js 前端表单验证工具分享 浅谈前端线上部署与运维 说到前端部署,可能大多数前端工程师在工作中都是使用的公司现成的部署系统,与SRE对接、一起完...

    xiaowugui666 评论0 收藏0

发表评论

0条评论

brianway

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<