Butterfly主题顶栏菜单重写

本文修改主题为Butterfly主题,若使用其他主题,请自行确认修改位置。

原文出处

https://akilar.top/posts/eac2c3d0/

效果预览

查看图片

效果预览

修改步骤

1. 重写顶栏样式

重写[Blogroot]\themes\butterfly\layout\includes\header\nav.pug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#menu-container.menu-container
.menu-item
each value, label in theme.menu
if typeof value !== 'object'
.menu-item-main
a.site-page.faa-parent.animated-hover(href=url_for(trim(value.split('||')[0])))
if value.split('||')[1]
- var icon_value = trim(value.split('||')[1])
- var anima_value = value.split('||')[2] ? trim(value.split('||')[2]) : 'faa-tada'
if icon_value.substring(0,2)=="fa"
i.fa-fw(class=icon_value + ' ' + anima_value)
else if icon_value.substring(0,4)=="icon"
svg.icon(aria-hidden="true" class=anima_value)
use(xlink:href=`#`+ icon_value)
span=' '+label
else
.menu-item-main.has-child
.menu-item-parent
a.site-page.faa-parent.animated-hover(href='javascript:void(0);')
if label.split('||')[1]
- var icon_label = trim(label.split('||')[1])
- var anima_label = label.split('||')[2] ? trim(label.split('||')[2]) : 'faa-tada'
if icon_label.substring(0,2)=="fa"
i.fa-fw(class=icon_label + ' ' + anima_label)
else if icon_label.substring(0,4)=="icon"
svg.icon(aria-hidden="true" class=anima_label)
use(xlink:href=`#`+ icon_label)
span=' '+ trim(label.split('||')[0])
each val,lab in value
.menu-item-child
a.faa-parent.animated-hover.site-page.child(href=url_for(trim(val.split('||') [0])))
if val.split('||')[1]
- var icon_val = trim(val.split('||')[1])
- var anima_val = val.split('||')[2] ? trim(val.split('||')[2]) : 'faa-tada'
if icon_val.substring(0,2)=="fa"
i.fa-fw(class=icon_val + ' ' + anima_val)
else if icon_val.substring(0,4)=="icon"
svg.icon(aria-hidden="true" class=anima_val)
use(xlink:href=`#`+ icon_val)
span=' '+ lab
.top-bar
.message-container
.message-item.message-weather
#tp-weather-widget.message-weather-box
.message-item.message-date(onclick='Navvisible()')
#message-date-box.message-date-box
- var pagedescr = page.description ? page.description : '欢迎光临糖果屋,愿你有愉快的一天 '
- var subtitle = page.subtitle ? page.subtitle : page.title
if is_post()
#message-title-box.message-title-box
a#site-name(title=pagedescr) #[=subtitle]
else if is_page()
#message-title-box.message-title-box
a#site-name(title=pagedescr) #[=subtitle]
else
#message-title-box.message-title-box
a#site-name(title=pagedescr) #[=config.title]
.message-item.message-function
if (theme.algolia_search.enable || theme.local_search.enable)
#search-button
a.site-page.social-icon.search.faa-parent.animated-hover
svg.faa-tada.icon(style="height:25px;width:25px" aria-hidden="true")
use(xlink:href='#icon-search-01')
span=' '+_p('search.title')
a.icon-V.hidden.faa-parent.animated-hover(onclick='switchNightMode()', title=_p ('rightside.night_mode_title'))
svg.faa-tada(width='25', height='25', viewBox='0 0 1024 1024')
use#modeicon(xlink:href='#icon-moon')
#toggle-menu
a.site-page.faa-parent.animated-hover
svg.faa-tada.icon(style="height:25px;width:25px" aria-hidden="true")
use(xlink:href='#icon-multi-window-01')
button.active-button(onclick='Navvisible()')

此处的修改与原文并不相同,差异如下,因为和风天气不再提供服务,改用心知天气,预留标签不同

1
2
3
4
5
6
7
8
  .top-bar
.message-container
- .message-item.message-weather(onclick='btf.scrollToDest(0, 500)')
- #he-plugin-simple.message-weather-box
+ .message-item.message-weather
+ #tp-weather-widget.message-weather-box
.message-item.message-date(onclick='Navvisible()')
#message-date-box.message-date-box

2. 新建样式

新建[Blogroot]\themes\butterfly\source\css\_layout\nav.styl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//default color:
:root
--nav-bar-background-color: rgba(249, 249, 249, 0.79)
--nav-font-color: #494748
--nav-font-hover-color: #494748
--nav-button-color: transparent
--nav-active-button-color: rgba(40, 185, 230, 0.65)
--nav-menu-background-color: rgba(160,160,160,0.7)
--nav-menu-item-background-color: rgba(249, 249, 249,0.8)
--nav-menu-item-font-color: #494748
--nav-menu-item-hover-background-color: #eda60c
--nav-menu-item-hover-font-color: #f9f9f9
[data-theme="dark"]
--nav-bar-background-color: rgba(66,66,66,0.8)
--nav-font-color: #f9f9f9
--nav-font-hover-color: #f9f9f9
--nav-button-color: rgba(20, 97, 227, 0.65)
--nav-active-button-color: rgba(249, 246, 14, 0.71)
--nav-menu-background-color: rgb(66,66,66)
--nav-menu-item-background-color: rgba(77, 72, 73,0.8)
--nav-menu-item-font-color: #f9f9f9
--nav-menu-item-hover-background-color: #cdd0ce
--nav-menu-item-hover-font-color: #4d4849
.nav-fixed
#menu-container
top: -110px
transition: all 0.5s
&.nav-visible
#menu-container
top: -60px
transition: all 0.5s
.menu-container
background: transparent
position: fixed
z-index: 90
top: -60px
left: 0
height: auto
width: 100vw
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
&.active-menu-bar
top 0px !important
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
button.active-button
background var(--nav-active-button-color) !important
.menu-item
background: var(--nav-menu-background-color)
height: 60px
width 100%
overflow-x: hidden;
overflow-y: hidden;
white-space: nowrap;
text-align: center;
font-size: 16px
&::-webkit-scrollbar
display: none
.menu-item-main
font-size: 16px !important;
display: inline-flex;
color: var(--nav-menu-item-font-color)
background: var(--nav-menu-item-background-color)
width: auto
min-width: 100px;
height: 50px;
align-items: center;
justify-content: center;
font-size: 14px;
margin: 5px 5px;
clip-path: polygon(3px 0, calc(50% - 5px) 0,50% 0px,calc(50% + 5px) 0 ,calc(100% - 3px) 0, 100% 3px,100% calc(50% - 5px), 100% 50%,100% calc(50% + 5px), 100% calc(100% - 3px), calc(100% - 3px) 100%,calc(50% + 5px) 100%,50% 100%,calc(50% - 5px) 100%,3px 100%, 0 calc (100% - 3px), 0 calc(50% + 5px), 0px 50%,0 calc(50% - 5px),0 3px);
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
a
color: var(--nav-menu-item-font-color)
&:hover
color: var(--nav-menu-item-hover-font-color)
background: var(--nav-menu-item-hover-background-color)
clip-path: polygon(3px 0, calc(50% - 5px) 0,50% 8px,calc(50% + 5px) 0 ,calc(100% - 3px) 0, 100% 3px,100% calc(50% - 5px), calc(100% - 8px) 50%,100% calc(50% + 5px), 100% calc(100% - 3px), calc(100% - 3px) 100%,calc(50% + 5px) 100%,50% calc(100% - 8px),calc (50% - 5px) 100%,3px 100%, 0 calc(100% - 3px), 0 calc(50% + 5px), 8px 50%,0 calc(50% - 5px),0 3px);
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
a
color: var(--nav-menu-item-hover-font-color)
.menu-item-parent
width: 0
opacity 0
color: var(--nav-menu-item-hover-font-color)
background: var(--nav-menu-item-hover-background-color)
pointer-events: none;
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
.menu-item-child
color: var(--nav-menu-item-font-color)
background: var(--nav-menu-item-background-color)
width: 100px;
opacity 1
pointer-events: inherit;
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
&.has-child
&:hover
background: var(--nav-menu-item-background-color) !important
.menu-item-parent
color: var(--nav-menu-item-font-color)
background: var(--nav-menu-item-background-color)
opacity: 1
pointer-events: inherit
display: inline-flex;
align-items: center;
justify-content: center;
width 100px
height: 50px;
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
a
color: var(--nav-menu-item-font-color)
.menu-item-child
color: var(--nav-menu-item-font-color)
background: var(--nav-menu-item-background-color)
opacity: 0
pointer-events: none
display: inline-flex;
align-items: center;
justify-content: center;
width 0
height: 50px;
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
a
color: var(--nav-menu-item-font-color)
&:hover
color: var(--nav-menu-item-font-color)
background: var(--nav-menu-item-hover-background-color)
a
color: var(--nav-menu-item-hover-font-color)



.top-bar
background: var(--nav-bar-background-color);
height: 50px;
width: 100%;
display: flex;
align-items: center;
flex-direction: column;
border-radius 0 0 10px 10px
.message-container
display: flex;
flex-wrap: nowrap;
height: 50px;
width: 100%;
align-items: center;
flex-direction: row;
.message-item
display: inline-flex
justify-content: center
height: 50px
align-items: center;
.message-weather
width 25%
.s-sticker-tmp.module
color: var(--nav-font-color) !important;
font-family: 'ZhuZiAYuanJWD' !important;
.s-sticker-city.module
color: var(--nav-font-color) !important;
font-family: 'ZhuZiAYuanJWD' !important;
.message-date
width 50%
.message-date-box
display: flex;
align-items: center;
justify-content: center;
width 50%
height: 50px
position absolute
background transparent
transform rotateX(0deg)
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17);
opacity 1
font-family: 'UnidreamLED','ZhuZiAYuanJWD';
font-size: 20px;
.message-title-box
display: flex;
align-items: center;
justify-content: center;
width 50%
height: 50px
position absolute
background transparent
transform rotateX(-180deg)
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17);
opacity 0
font-family: 'ZhuZiAYuanJWD';
font-size: 20px;
a
color: var(--nav-font-color)
&:hover
color: var(--nav-font-hover-color)
&:hover
.message-date-box
transform rotateX(180deg)
opacity 0
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17);
.message-title-box
transform rotateX(0deg)
opacity 1
transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17);
.message-function
justify-content: center;
width 25%
a
display: flex;
align-items: center;
#toggle-menu
display none
button.active-button
background: var(--nav-button-color);
width: 70px;
height: 10px;
border-radius: 1px;
margin: 0px auto;
border-bottom: 3px solid var(--nav-bar-background-color);
border-top: 3px solid var(--nav-bar-background-color);
border-left: 10px solid var(--nav-bar-background-color);
border-right: 10px solid var(--nav-bar-background-color);
transform: perspective(0.5em) rotateX(-5deg);
left: calc(50% - 35px);
position: absolute;
&:hover
background var(--nav-active-button-color) !important
@media screen and (max-width: 768px)
.menu-container
.top-bar
.message-container
.message-weather
.s-sticker-tmp.module
display none !important
.s-sticker-city.module
display none !important;
if hexo-config('mobile_menu')
@media screen and (max-width: 768px)
.menu-container
.top-bar
.message-container
.message-function
#toggle-menu
display block !important

3. 移除原生顶栏的内容

移除main.js中关于原生顶栏的内容

移除了原文中的 overflow-x 使其更加美观

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  .
.
.

let blogNameWidth, menusWidth, searchWidth, $nav
let mobileSidebarOpen = false

- const adjustMenu = (init) => {
- if (init) {
- blogNameWidth = document.getElementById('site-name').offsetWidth
- const $menusEle = document.querySelectorAll('#menus .menus_item')
- menusWidth = 0
- $menusEle.length && $menusEle.forEach(i => { menusWidth += i.offsetWidth })
- const $searchEle = document.querySelector('#search-button')
- searchWidth = $searchEle ? $searchEle.offsetWidth : 0
- $nav = document.getElementById('nav')
- }
-
- let hideMenuIndex = ''
- if (window.innerWidth < 768) hideMenuIndex = true
- else hideMenuIndex = blogNameWidth + menusWidth + searchWidth > $nav.offsetWidth - 120
-
- if (hideMenuIndex) {
- $nav.classList.add('hide-menu')
- } else {
- $nav.classList.remove('hide-menu')
- }
- }
-
- // 初始化header
- const initAdjust = () => {
- adjustMenu(true)
- $nav.classList.add('show')
- }

// sidebar menus
const sidebarFn = {
open: () => {

.
.
.

const unRefreshFn = function () {
window.addEventListener('resize', () => {
- adjustMenu(false)
btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close()
})

.
.
.

window.refreshFn = function () {
- initAdjust()

if (GLOBAL_CONFIG_SITE.isPost) {
GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice()
GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time'))

4. 新建顶栏JS文件

新建[Blogroot]\themes\butterfly\source\js\custom\nav.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//鼠标控制横向滚动
if (document.getElementsByClassName("menu-item")[0]){
var xscroll = document.getElementsByClassName("menu-item")[0];
xscroll.addEventListener("mousewheel", function (e) {
//计算鼠标滚轮滚动的距离
var v = -e.wheelDelta / 2;
xscroll.scrollLeft += v;
//阻止浏览器默认方法
e.preventDefault();
}, false);
}

// 获取当前时间

var box = document.getElementById('message-date-box')

//不足十位补零
var addZero = val => val < 10 ? '0' + val : val
//把阿拉伯数字的星期转化为中国汉字的星期 // 星期映射表
var trans = val => {
var obj = {
0: '日',
1: '一',
2: '二',
3: '三',
4: '四',
5: '五',
6: '六'
}
return obj[val]
}
setTime ()
//获取时间的方法
function setTime() {
var time = new Date();
// var year = time.getFullYear(); // 获取年
// var month = time.getMonth() + 1; // 获取月(是从0到11,所以我们要给他加1)
// var date = time.getDate(); // 获取日
var hour = time.getHours(); // 获取小时
var min = time.getMinutes(); // 获取分钟
var sec = time.getSeconds(); // 获取秒
var day = time.getDay(); // 获取星期几(0是星期日)


var value = addZero(hour) +
':' + addZero(min) + ":" + addZero(sec) + ' 星期'+ trans(day)
// 把所有的时间拼接到一起
box.innerText = value
// console.log(value)
// 把拼接好的时间插入到页面

}
// 让定时器每间隔一秒就执行一次setTime这个方法(这是实现时钟的核心)
setInterval(setTime, 1000)


function Navvisible(){
var navbar = document.getElementById('menu-container')
if (navbar) {
// 首先判断是否存在active类
if (navbar.className.indexOf('active-menu-bar') > -1){
// 存在则移除
navbar.classList.remove('active-menu-bar');
}
else{
// 不存在则先添加
navbar.classList.add('active-menu-bar');
}
}
}

5. 引入样式文件

[Blogroot]\_config.butterfly.ymlinject配置项中引入

注意:nav.js 每页都需要加载 ,故插入 js 时应当加入 data-pjax 标签排除 pjax

1
2
  bottom:
+ - <script async data-pjax src="/js/custom/nav.js"></script>

6. 新增配置项

[Blogroot]\_config.butterfly.yml中新增配置项mobile_menu以控制手机端是否需要启用侧栏展开的菜单

1
2
3
4
5
6
7
8
menu:
首页: / || fas fa-home || faa-tada
目录|| fas fa-compass || faa-tada:
归档: /archives/ || fas fa-archive || faa-tada
标签: /tags/ || fas fas fa-tags || faa-tada
分类: /categories/ || fas fa-folder-open || faa-tada

mobile_menu: false

7. 添加天气显示

如果要添加天气显示,需要先去心知天气创建应用,在用下方网址创建js,写入文件并引入

插件类型随意选择,需要吸附顶栏则选择固定极简,其余根据需要选择

点击生成后会得到一段HTML,将其script部分复制到自定义位置的weather.js并在[Blogroot]\_config.butterfly.yml中引入即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="tp-weather-widget"></div>
<script>
(function(a,h,g,f,e,d,c,b){b=function(){d=h.createElement(g);c=h.getElementsByTagName(g)[0];d.src=e;d.charset="utf-8";d.async=1;c.parentNode.insertBefore(d,c)};a["SeniverseWeatherWidgetObject"]=f;a[f]||(a[f]=function(){(a[f].q=a[f].q||[]).push(arguments)});a[f].l=+new Date();if(a.attachEvent){a.attachEvent("onload",b)}else{a.addEventListener("load",b,false)}}(window,document,"script","SeniverseWeatherWidget","//cdn.sencdn.com/widget2/static/js/bundle.js?t="+parseInt((new Date().getTime() / 100000000).toString(),10)));
window.SeniverseWeatherWidget('show', {
flavor: "slim",
location: "XXXXXXXXXXXX",
geolocation: true,
language: "auto",
unit: "c",
theme: "auto",
token: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
hover: "enabled",
container: "tp-weather-widget"
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
(function(a,h,g,f,e,d,c,b){b=function(){d=h.createElement(g);c=h.getElementsByTagName(g)[0];d.src=e;d.charset="utf-8";d.async=1;c.parentNode.insertBefore(d,c)};a["SeniverseWeatherWidgetObject"]=f;a[f]||(a[f]=function(){(a[f].q=a[f].q||[]).push(arguments)});a[f].l=+new Date();if(a.attachEvent){a.attachEvent("onload",b)}else{a.addEventListener("load",b,false)}}(window,document,"script","SeniverseWeatherWidget","//cdn.sencdn.com/widget2/static/js/bundle.js?t="+parseInt((new Date().getTime() / 100000000).toString(),10)));
window.SeniverseWeatherWidget('show', {
flavor: "slim",
location: "XXXXXXXXXXXX",
geolocation: true,
language: "auto",
unit: "c",
theme: "auto",
token: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
hover: "enabled",
container: "tp-weather-widget"
})

注意:weather.js 每页都需要加载 ,故也要加入 data-pjax 标签

1
2
      bottom:
+ - <script async data-pjax src="/js/weather.js"></script>