3

猹的魔改日记-文章页抛弃卡片、丢弃小菜单以及布局重构

 1 year ago
source link: https://noionion.top/64594.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

猹的魔改日记-文章页抛弃卡片、丢弃小菜单以及布局重构

发表于2022-12-24|更新于2022-12-24|魔改日记本
字数总计:4.3k|阅读时长:18分钟|阅读量:28

温馨提示:本日记本只提供魔改参考,并不做通用处理,很多源码修改都需要根据自己博客做小小微调

另外在修改源码时注意做好备份处理。本帖只提供思路与方法,如果哪里炸了,请检查语法与缩进等,猹概不负责啦!

继白嫖店长冰老师小康小N等大佬的魔改之后,猹终于不满于白嫖,开始想动手实操,把自己的博客调教成想要的样子,也以此来使猹学前端有实操的机会。

:这部分前言内容会在魔改日记本的每一篇都出现;另外这是一篇日记而非教程,文风可能不是那么友好(逃

本篇特别提示:这次的魔改修改了bf的主要结构,并对一些大的布局样式进行了flex弹性盒子的全面替换,不建议进行跟随魔改(我自己都不记得我改的一些细节)


事情要从小菜单的魔改说起。猹将文章页的目录模块藏在了小菜单里头,结果经过大量的反馈发现,“猹你博客没有目录吗”

az,好吧本来是为了保留作者卡片而设计的小菜单,既然目录没人看到,那小菜单显然也是没人点开看。本来的目的也就没有达到,想想还是把小菜单砍了,重构吧……

主要结构重构-左右双栏与菜单按钮

设计来源、灵感

重构的最主要目的还是原本容易被人忽略的目录模块。找到一个好的目录布局设计可不容易,bf原先的设计也的确不适合我。在zhheo的推荐下,选用了少数派的目录设计。

sspai1.jpg

sspai2.jpg

少数派的设计逻辑说实在很戳我的心,然后我脑子一抽决定给他加个当前标题居中显示。。。再然后折腾了几天就是现在这样了。

设计思路

但是折腾这个目录的关键在于,如何保证其自适应良好。采取与小菜单相同的浮动窗口肯定是不好用的,一不小心可能就会变成这个样子(拿同学在做的博客系统举个栗子(反正目录是我的设计))

badtoc.png

如果要保证文章板块与目录间天然的自适应,最好的方式还是在左右侧各开辟一个 div 盒子,这样更可靠一点。原本 butterfly 主题的源码部分,是这样的:

<div id="mainbody">
<main class="layout hide-aside" id="content-inner">
<div id="post">...</div>
</main>
</div>

并且对main部分限定了最大宽度1000px,在双栏布局下双栏也被严格限制在这个大小里,属实是对魔改的发挥起到了一定的限制。故而更改其结构是十分必要的事。于是目标结构如下:

  <div id="mainbody">
+ <div id="content_leftside">...</div>
<main class="layout hide-aside" id="content-inner">
<div id="post">...</div>
</main>
+ <div id="content_rightside">...</div>
</div>

此后,显然就可以直接在新开辟的content_rightside加点料。如果只是建立起类似样式的目录倒是小事,实现当前标题的恒定居中才是复杂的东西。

最后是一些功能按键。回到顶部这个功能显然还是放在类似小彩单的位置合适,样式直接参考fluit主题的按钮即可。而原本的作者卡片我决定提取社交按钮以及一些功能按键,在左侧也形成一个居中对称的设计来进行视觉上的平衡,魔改思路就此完成。

布局调整-开辟左右双栏

将开辟双栏的思路翻译到 pug 源码文件[BlogSource]/themes/butterfly/layout/includes/layout.pug

        #mainbody
+ block content_leftside
main#content-inner.layout(class=hideAside)
if body
div!= body
else
block content
if theme.aside.enable && page.aside !== false
include widget/index.pug
+ block content_rightside

有了左右双栏,目录等的添加就好做了。

目录1-原生目录js再就业

content_rightside pug源码

block content_rightside
- let tocNumber = page.toc_number !== undefined ? page.toc_number : theme.toc.number
#content_rightside
#rightside-toc
.toc-box
if (page.encrypt == true)
.toc-content.toc-div-class(style="display:none")!=toc(page.origin, {list_number: tocNumber})
else
.toc-content!=toc(page.content, {list_number: tocNumber})
#rightside-button
button#rightside-go-up(type="button" title=_p("rightside.back_to_top"))
i.fas.fa-arrow-up

为了方便自适应,按键也一并写在content_rightside

目录板块在小菜单的魔改中就已经写过了,问题在于active状态添加的js失效了。咱本来就不太懂js,自然不愿去再写一份js来对当前标题进行标记。最有可能的方式,自然是对原本的js进行改造再就业。

    const tocFn = function () {
- const $cardTocLayout = document.getElementById('card-toc')
+ const $cardTocLayout = document.getElementById('rightside-toc')
const $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0]
const $tocLink = $cardToc.querySelectorAll('.toc-link')
const $article = document.getElementById('article-container')

但修改完对应类等发现,还是没办法令其生效。于是将目光转向了一些配置项中,最终发现是侧栏的关闭导致了js无法生效。修改文件[BlogSource]/themes/butterfly/layout/includes/head/config_site.pug

-   var showToc = is_post() && theme.aside.enable && pageToc && (toc(page.content) !== '' || page.encrypt == true )
+ var showToc = is_post() && pageToc && (toc(page.content) !== '' || page.encrypt == true )

active能够正常标记到目录标题中,就可以编写对应的样式。少数派中的胶囊颗粒采用的是在标题前使用div,所有标题也使用div盒子。胶囊与盒子本身不是绝对关联的情况下才有可能做到所有不处于active状态的标题隐藏而胶囊不隐藏的效果。

butterfly的设计下目录则采用有序表格的方式呈现。这也意味着在不改目录生成源码的情况下,我如果想单纯实现胶囊就只能使用before伪类,也没有办法做到一模一样的显隐逻辑,于是只能自己设计效果了。

这里不得不吐槽下不同长度胶囊颗粒的css实现(这写的好淦啊)

.toc-item
transition: all 0.5s ease-in-out
opacity: 0.5
// 目录缩进结构
&.toc-level-1
&:before
content: " "
margin: 0.65rem 0.4rem 0.65rem 0
width: 1rem
height: 0.2rem
border-radius: 0.1rem
background: #000
&.toc-level-2
&:before
content: " "
margin: 0.65rem 0.7rem 0.65rem 0
width: 1rem
height: 0.2rem
border-radius: 0.1rem
background: #000
&.toc-level-3
&:before
content: " "
margin: 0.65rem 1.2rem 0.65rem 0
width: 0.8rem
height: 0.2rem
border-radius: 0.1rem
background: #000
&.toc-level-4
&.toc-level-5
&.toc-level-6
&:before
content: " "
margin: 0.65rem 1.7rem 0.65rem 0
width: 0.6rem
height: 0.2rem
border-radius: 0.1rem
background: #000

目录2-当前标题居中轮转

居中的轮盘设计就类似于一些卡牌决斗盘抽卡,一些动效就很养眼。本来想使用swiper来实现,但我不知道怎么去控制其随着文章进度转换,于是作罢。

最终选用了十分暴力的 translate 大法,复用目录的标记js部分进行相应的 translate 计算即可动态偏移:

var offset = -currentIndex * 1.5 + 4.25
$cardToc.style.translate = "0 " + offset + "rem"

然后css对对应的标题高度进行限制(例如与上面对应的就是一行1.5rem),保证偏移后还是居中就行。

translate 大法也就有个反人类设计吧,没办法使用滚轮查看目录。

子菜单-回到顶部

回到顶部的按钮还是要做一点点调整的,现在的整体设计是向中间集中的,不适合在边角放小彩单。而放到偏靠中间的部分还是需要考虑位置自适应问题。

fluit主题的回到顶部按钮位置本身是靠js进行控制的。而我这里做了一点点的尝试,直接在content_rightside进行样式测试。

意外的是,fixed布局似乎不会被flex干扰,默认会靠在边上而不会串成串儿。于是直接采用绝对定位将其钉在了content_rightside的左下角。

相关的js逻辑直接复用小彩单,在此不提。

左侧功能区-文章阅读进度与糖果屋二维码

content_leftside pug源码

block content_leftside
#content_leftside
#left_menu
//- 联系方式
if(theme.social)
.leftside-social
!=fragment_cache('social', function(){return partial('includes/header/social')})
//- 阅读进度
.leftside-contents
span#read-percent 0
//- 跳转评论
.leftside-comment
a(href="#post-comment" title="要去留言吗?")
i.fa-lg.fas.fa-comment
.leftside-qq(title="来糖果屋聊天噻!")
i.fa-lg.fas.fa-qrcode
.leftside-rmb
a(title="柿还在施工的捐赠页!不给看!")
i.fa-lg.fas.fa-money-check-dollar
#left_display
.candy_qrcode
img(src="./img/candy-qr.png")

在原先的bf的目录中,有一串数字表示阅读进度(它采用的不是全网页百分比,在我看来逻辑上更合理一点),恰好可以进行复用。在左侧的功能区一群图标中,插入一个数字恰好可以看起来对称些。

然后是一些功能,分享按钮与跳转评论本身只是链接,赞助二维码还没画好(涩涩嘿嘿涩涩)

balabalasesesese.png

所以只有一个糖果屋群聊二维码需要加上。我去使用工具绘制了一下一个相对好看且对称的二维码:

candy-qr.png

然后以类似的方法添加上去。但是这玩意肯定不能常态显示,不然我倒数第二个图标就是摆设了啊。想想我决定动手写一个js。

本身我是没有js编写经验的(以前反正或抄或改,反正就是没有自己写过),好在写了类似hover的逻辑还算简单:

document.addEventListener('DOMContentLoaded', function () {
const leftSideMenu = {
qrcodeHover: () => {
// 按钮获取
const left_menu = document.getElementById('left_menu')
if(left_menu){
const leftside_qq = left_menu.getElementsByClassName('leftside-qq')[0]
// 显示区域获取
const left_display = document.getElementById('left_display')
const candy_qrcode = left_display.getElementsByClassName('candy_qrcode')[0]

leftside_qq.addEventListener('mouseover', function () {
candy_qrcode.style.opacity = "1"
})
leftside_qq.addEventListener('mouseout', function () {
candy_qrcode.style.opacity = "0"
})
}
}
}

leftSideMenu.qrcodeHover();
})

整体显隐逻辑

左右栏还是需要相应的显示逻辑的。文章处于最顶部时不应该显示左右栏和回到最顶按钮,阅读结束后不应显示左右栏。于是这里选择复用原小菜单显隐逻辑代码,做进一步修改:

window.scrollCollect = () => {
return btf.throttle(function (e) {
const currentTop = window.scrollY || document.documentElement.scrollTop
const isDown = scrollDirection(currentTop)

//滚动条高度+视窗高度 = 可见区域底部高度
const currentBottom = currentTop + document.documentElement.clientHeight;

if (currentTop > 56) {
if (isDown) {
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
if (isChatBtnShow && isChatShow === true) {
chatBtnHide()
isChatShow = false
}
} else {
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
if (isChatBtnHide && isChatShow === false) {
chatBtnShow()
isChatShow = true
}
}
$header.classList.add('nav-fixed')
// 获取位置监测容器,此处采用文章主体
var eventlistner = document.getElementById('post');
if(eventlistner){
var centerY = eventlistner.offsetTop+eventlistner.offsetHeight;
if(centerY > currentBottom && currentTop > eventlistner.offsetTop+document.getElementById('post-info').offsetHeight){
if($rightside_toc) $rightside_toc.style.cssText = 'opacity: 1; pointer-events: all'
if($leftside_menu) $leftside_menu.style.cssText = 'opacity: 1; pointer-events: all'
} else {
if($rightside_toc) $rightside_toc.style.cssText = 'opacity: 0; pointer-events: none'
if($leftside_menu) $leftside_menu.style.cssText = 'opacity: 0; pointer-events: none'
}
}
if($rightside_button) $rightside_button.style.cssText = 'bottom: 1rem'
} else {
if (currentTop === 0) {
$header.classList.remove('nav-fixed', 'nav-visible')
}
if($rightside_toc) $rightside_toc.style.cssText = 'opacity: 0; pointer-events: none'
if($leftside_menu) $leftside_menu.style.cssText = 'opacity: 0; pointer-events: none'
if($rightside_button) $rightside_button.style.cssText = 'bottom: -3rem'
}

if (document.body.scrollHeight <= innerHeight) {
if($rightside_toc) $rightside_toc.style.cssText = 'opacity: 0; pointer-events: none'
if($leftside_menu) $leftside_menu.style.cssText = 'opacity: 0; pointer-events: none'
if($rightside_button) $rightside_button.style.cssText = 'bottom: -3rem'
}
}, 200)()
}

显示范围这里选择直接检测文章主体。

css完整代码和gh提交记录

样式代码

#mainbody
display: flex
#post
background: none
box-shadow: none
&:hover
box-shadow: none
#content_leftside
flex: 1
width: fill-available
width: -webkit-fill-available
display: flex
flex-direction: row-reverse
#left_menu
top: -1rem
opacity: 0
pointer-events: none
transition: all 0.3s ease-in-out
position: fixed
display: flex
height: 100%
width: 1.5rem
padding: 0.5rem
margin: 0 auto
flex-direction: column
justify-content: center
align-items: center
translate: -0.7rem 0
i
color: #000
.leftside-social
text-align: center
opacity: 0.7
width: 1.5rem
margin: 0.4rem
transition: all 0.5s
.fa-fw
margin: 0.5rem 0
transition: all 0.3s
transform: scale(1.3)
&:hover
opacity: 1
.leftside-contents
.leftside-comment
.leftside-qq
.leftside-rmb
text-align: center
margin-bottom: 0.25rem
opacity: 0.7
width: 1.5rem
height: 1.5rem
font-weight: bold
transition: all 0.5s
a
font-weight: bolder
.fas
margin: 0.5rem 0
width: 1.25em
.fas::hover
transform: scale(1.3)
&:hover
opacity: 1
.leftside-contents
border-radius: 1rem
box-shadow: 0 0 5px #000
margin-bottom: 0.5rem
#left_display
// box-shadow: 0 0 5px #000
width: inherit
height: 100%
margin-right: 3rem
display: flex
align-items: center
position: fixed
top: -0.62rem
flex-direction: row-reverse
.candy_qrcode
transition: all 0.3s ease-in-out
opacity: 0
pointer-events: none
max-width: 9rem
width: 100%


#content_rightside
flex: 1
width: fill-available
width: -webkit-fill-available
display: flex
flex-direction: row
#rightside-toc
top: -1rem
opacity: 0
pointer-events: none
transition: all 0.3s ease-in-out
position: fixed
display: flex
height: 100%
width: inherit
padding: 0.5rem
flex-direction: row
align-items: center

.item-headline
font-size: 1rem
font-weight: bold
display: flex
flex-direction: column
span
margin-left: 0.5rem
span.toc-text
color: #000
.toc-box
height: 10rem
width: 100%
// box-shadow: 0 0 5px #000
overflow: hidden
.toc-content
translate: 0 4.25rem
transition: all 0.5s
// height: 100%
ol
padding: 0
margin: 0
list-style-type: none
li::marker
content: none
li::before
float: left
// counter-increment: section
// content: counters(section,".") " "
.toc
font-weight: bold
width: 100%
height: inherit
overflow-y: scroll
overflow-x: hidden
// height: 10rem
margin-top: 0.1rem
// padding-left: 0
list-style-type: none
.toc-child
// padding: 0
list-style-type: none
.toc::-webkit-scrollbar
width: 0 !important
.toc-link
line-height: 1.5rem
max-height: 1.5rem
white-space: nowrap
display: block
// border-left: 0.1rem solid transparent
color: var(--btn-bg)
transition: all 0.5s
padding-left: 0.5rem
span.toc-text
text-overflow: ellipsis
color: #000
&:hover span.toc-text
color: #000
&.active
transform: scale(1.3)
transform-origin: 2.5rem 0.75rem
font-weight: bolder
.toc-item
transition: all 0.5s ease-in-out
opacity: 0.5
// 目录缩进结构
&.toc-level-1
&:before
content: " "
margin: 0.65rem 0.4rem 0.65rem 0
width: 1rem
height: 0.2rem
border-radius: 0.1rem
background: #000
&.toc-level-2
&:before
content: " "
margin: 0.65rem 0.7rem 0.65rem 0
width: 1rem
height: 0.2rem
border-radius: 0.1rem
background: #000
&.toc-level-3
&:before
content: " "
margin: 0.65rem 1.2rem 0.65rem 0
width: 0.8rem
height: 0.2rem
border-radius: 0.1rem
background: #000
&.toc-level-4
&.toc-level-5
&.toc-level-6
&:before
content: " "
margin: 0.65rem 1.7rem 0.65rem 0
width: 0.6rem
height: 0.2rem
border-radius: 0.1rem
background: #000


&.active
transition: all 0.5s ease-in-out
opacity: 1
.toc-child
display: block
&:hover
opacity: 1
#rightside-button
position: fixed
z-index: 101
display: flex
bottom: -3rem
align-items: center
justify-content: center
flex-direction: column
transition: all .5s

button
background: var(--card-bg)
height: 2rem
width: 2rem
border-radius: 1rem
font-size: 0.8rem
box-shadow: 0 0 5px #000
margin: 0.25rem 0

[data-theme="dark"]
#mainbody
#content_leftside
a
&:hover
color: #a153ff
#left_menu
.leftside-contents
box-shadow: 0 0 5px #fff
i
color: #fff
.leftside-contents span
color: #fff
#left_display
.candy_qrcode
filter: invert(1)
#content_rightside
#rightside-toc
span.toc-text
color: #fff
.toc-link
color: var(--btn-bg)
span.toc-text
color: #fff
&:hover span.toc-text
color: #fff
.toc-item
// 目录缩进结构
&.toc-level-1
&:before
background: #fff
&.toc-level-2
&:before
background: #fff
&.toc-level-3
&:before
background: #fff
&.toc-level-4
&.toc-level-5
&.toc-level-6
&:before
background: #fff

#rightside-button
button
background: var(--card-bg)
box-shadow: 0 0 5px #fff
i
color: #fff

.start
.end
font-family: 'Noto Serif SC', -apple-system, BlinkMacSystemFont, Roboto, Segoe UI, Helvetica, Arial, serif
font-size: large
font-weight: bolder
opacity: 0.5

@media screen and (max-width: 1200px)
#content_leftside
#left_menu
display: none !important
#content_rightside
#rightside-toc
display: none !important

@media screen and (max-width: 1100px)
#mainbody
display: block
#content_leftside
display: none !important
#content_rightside
display: none !important

github提交记录

微调-抛弃卡片结构和若干功能区

这部分包含了我很长时间的微调和想法,主要只针对整个文章块。

一是开头的标题部分:

lenovo20221224220458.png

我添加了彩色标签,并把一些数据做了重新排版。(西瓜做分割线真好用)

二是地下文章结束的部分:

lenovo20221224220827.png

我去除了版权卡片(以后大概还会想个设计补上)、上下篇和推荐(我觉得这玩意属实没什么用处,尽管我做了美化但也觉得很违和)

三是去除了文章板块的框框,整个与背景项贴合。整体看起来相对简单整洁一点。

整个文章页魔改应该会告一段落。还剩下的一点坑是移动端的目录和回到顶部,这部分想还是用最传统的浮动小菜单来实现,就不瞎整了。

这部分的魔改太难以像前面的捋思路方式给源码修改参考,涉及的调整部分过多也不利于做教程。所以有能力的还是建议自己翻我博客源码来做更改,没能力的就爱莫能助了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK