这是我参与「第四届青训营」笔记创作活动的的第38天
效果展示
源代码
问题描述
动态的响应式布局
当缩放界面时,动态地展示导航栏、侧边栏、文章主体与右侧目录。
markdown 文档解析与代码高亮
安装 markdown-loader,之后在 vue.config.js 文件内添加配置并重新启动项目,进行文章解析;
npm i html-loader markdown-loader --save-dev
安装 highlight.js,并新建工具文件 highlight.js,进行代码高亮处理。
npm install --save highlight.js
侧边栏、文章与目录的吸顶效果
监听滚动条,滚动到顶部导航栏消失时,侧边栏和右侧目录就会定位。 position: fixed
目录生成、点击跳转与滚动高亮效果
分析文章,将 h1 ~ h6 标题的内容提取存放到数组中,通过列表循环展示。监听页面的滚动,当滚动到对应标题所在位置时,高亮对应的目录内容。
功能实现
动态的响应式布局
纯 CSS 实现的简单布局。参考:CSS 网站布局
/* 创建三个不相等的彼此并排的浮动列 */
/* 左列 */
.leftcolumn {
float: left;
width: 15%;
}
/* 其余同理 */
/* 清除列之后的浮动 */
.row:after {
content: "";
display: table;
clear: both;
}
/* 响应式布局 - 当屏幕的宽度小于 1400 像素时,使三列堆叠而不是并排 */
@media screen and (max-width: 1400px) {
.maincolumn {
width: 75%;
padding: 0;
}
.rightcolumn {
width: 20%;
padding-left: 20px;
}
.leftcolumn,
.menu-item,
.img {
display: none;
}
.menu {
width: 100%;
}
}
/* 其余同理,分别在屏幕宽度小于 1400、1100、600 像素时响应 */
markdown 文档解析与代码高亮
尝试了很多 markdown 文档解析与代码高亮的插件,但都没有成功。最终使用的是以下这个:一站式解决vue解析markdown,代码高亮,目录获取。
侧边栏、文章与目录的吸顶效果
// JS
mounted () { //渲染成html后调用
window.addEventListener('scroll', this.initHeight) //监听窗口的滚动
this.$nextTick(() => {
//左侧边栏距离它的 offsetParent 元素的顶部的距离
this.offsetTop = document.querySelector('#left').offsetTop
})
}
initHeight () {
//获取当前页面滚动条纵坐标的位置
const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
//滚动到侧边栏位置时将这三列固定
this.isFixed = scrollTop > this.offsetTop
}
// HTML
<div class="leftcolumn" id="left" :class="{'is_fixed' : isFixed}">···</div>
// CSS
.is_fixed {
position: fixed;
float: left;
width: 15%;
}
文章与目录的效果同理。
目录生成、点击跳转与滚动高亮效果
目录:
<ul>
<li
v-for="(nav, index) in contents"
:key="index"
@click="handleMenuList(nav)">
<a :class="{ 'itemHight': menuIndex === index }">{{nav}}</a>
</li>
</ul>
目录生成:
搜索获得的文章,将其中的 h1 ~ h6 标题的内容存入数组 contents[]
中,然后使用循环列表显示。
···
if (this.content[i].localName === 'h1') {
···
this.contents.push(this.content[i].innerHTML)
···
}
//其余标题同理
点击跳转
handleMenuList (nav) { //传入当前点击的目录内容
// 目录内容在目录数组中的索引位置,会高亮对应位置的目录
this.menuIndex = this.contents.findIndex((item) => item === nav)
// 获取目录内容在文章中的索引位置
this.clickMenuIndex = this.article.findIndex((item) => item === nav)
const navPage = this.content[this.clickMenuIndex]
// 滚动到对应位置
scrollTo(0, navPage.offsetTop)
}
滚动高亮
同样监听页面滚动,通过比较 标题到顶部的距离 和 滚动距离 + 导航栏距离 来确定哪条目录应该高亮。
initHeight () {
for (let i = this.menuIndex; i < this.content.length; ++i) { //从当前所在位置开始
if (this.content[i].offsetTop < scrollTop + 40) {
// 当标题快要滚动到顶部时
if (this.content[i].localName === 'h1' || this.content[i].localName === 'h2' || this.content[i].localName === 'h3' || this.content[i].localName === 'h4' || this.content[i].localName === 'h5' || this.content[i].localName === 'h6') {
// 获得当前滚动到的标题在目录数组中的位置
this.menuIndex = this.contents.findIndex((item) => item === this.content[i].innerHTML)
}
}
}
}
后续
虽然和组内的另一个小伙伴按时完成了项目,但因为没来得及填写项目报告并将项目部署到服务器(第一次部署服务器不太了解遇到了很多问题),导致没有参加最后的项目答辩,有点遗憾。但总的来说这次活动也让我这个前端小白了解到了很多东西,还是受益匪浅的,非常感谢各位老师们♪(・ω・)ノ。
ps:因为时间紧迫所以没来得及优化代码,源代码中有些冗余的代码也没来得及删除,部分注释有误,查阅时请自行注意区分啦~