I have not updated my article for a long time. Due to work and life, I seem to have lost my previous appearance in college and become lazy. When I just stepped into the society, I still need to keep pushing myself. There are a lot of things to learn. Regular writing will improve me a lot. You’re still thinking as you write, and you want to make it better and show it to others. Unlike writing business, features and requirements are rarely optimized from scratch. Just be also because of a demand that encounters recently, see the data of this respect on the net very little, had this article then.

preface

With the rise of the front end, more and more people joined the family, frames and wheels are everywhere. This brings a lot of benefits: reduced development cost and time, maybe a feature has been built by others, you just need NPM install to use, very fast. But the disadvantages are not small: with the increase of the project, more and more wheels, more difficult to control, the size of the project also changed from 10m > 20m > 100m… “It’s a scary thing. On the other hand, you use a wheel written by someone else too often and don’t think or implement it yourself, and in the long run, your code will naturally deteriorate. Therefore, I often restrict my own words: can not use as far as possible, the development of a wheel utilization rate is extremely low, even only once, that definitely not.

Just one requirement is: Markdow article writing and presentation. The function is similar to the gold nuggets, and today I’m going to show you the first section, how to generate a Markdown directory.

1. Anchor point setting

The title composed of #, ## and ## in makdown will turn into H tags after marked and rendered to the web page, so when you get the article details page, you can extract all the contents tags from it, i.e. H1, H2, h3….

const toc: string[] = data.content.match(/<[hH][1-6]>.*? <\/[hH][1-6]>/g) // By means of a regularCopy the code

Once you have these titles, you can set the anchor points. In H5, there are many ways about anchor points, and we will adopt the following methods for design:


After matching all h tags in the article with the re, the loop adds the ID attribute and wraps the div


tocs.forEach((item: string, index: number) => {
 let _toc = `<div name='toc-title' id='${index}'>${item} </div>`
 data.content = data.content.replace(item, _toc)
})
Copy the code

Second, directory conversion

We see the article catalog is generally in the form of ul > LI > A label, so after getting all the h tags of the article, how to convert to ul or LI labels?


From the console, you can see that the article H headings have been removed. The next step is to convert these H tags to ul> LI. The first is a data structure you should know — the stack. Let’s say you have a basket and you put eggs in the basket, and then one day the bottom of the basket starts to leak, and to protect the eggs you take the eggs out of the basket, and you take the eggs in from the outermost layer of the basket, and this is a typical case of fifin-last out. The same thing happens when we convert the h tag to ul> Li.

export default function toToc(data: string[]) {
  let levelStack: string[] = []
  let result:string = ' '
  const addStartUL = () => { result += '<ul class="catalog-list">'; }
  const addEndUL = () => { result += '</ul>\n'; }
  const addLI = (index: number, itemText: string) => { result += '<li><a name="link" class="toc-link'+'- #'+ index + '" href="#' + index + '" >' + itemText + "</a></li>\n"; }
  data.forEach(function (item: any, index: number) {
    let itemText: string = item.replace(/<[^>]+>/g, ' ') // Matches the text of the h tagletitemLabel: string = item.match(/<\w+? >/)[0] // Match h? Tag < h? >letLevelIndex: number = levelStack.indexof (itemLabel) <h? > label, ul and LI are addedif(levelIndex === -1) {levelStack.unshift(itemLabel) addStartUL() addLI(itemText)} > tag, and put li directly under this ul at the top of the stackelse if(levelIndex === 0) {addLI(index, itemText)} > tag, but not at the top of the stack, requires that all previous <h? < span style = "max-width: 100%; clear: bothelse {
      while(levelIndex--) {levelStack.shift() addEndUL()} addLI(index, itemText)}}) < p style = "max-width: 100%; clear: bothwhile (levelStack.length) {
    levelStack.shift()
    addEndUL()
  }
  return result
}
Copy the code

At this point, all h tags have been converted to the form of UI > Li and added a link anchor point corresponding to the h tag ID in the previous article, the article has realized the directory and click jump.

Third, directory optimization

Here we basically completed half of the goal, as nuggets loyal fans, of course, is the choice to use CSS optimization, CSS paste up always feel like in the home, here is not detailed, roughly like this

.catalog-list {
  font-weight: 600;
  padding-left: 10px;
  position: relative;
  font-size: 15px;
  &:first-child::before {
      content: "";
      position: absolute;
      top: 10px;
      left: 12px;
      bottom: 0;
      width: 2px;
      background-color: #ebedef;
      opacity: .8;
    }
  }
  & > li > a {
    position: relative;
    padding-left: 16px;
    line-height: 20px;
    @include catalogRound(0, 6px);
  }
  ul, li {
    padding: 0;
    margin: 0;
    list-style: none;
  }
  ul > li > a {
    font-size: 14px;
    color: # 333333;
    padding-left: 36px;
    font-weight: 500;
    position: relative;
    @include catalogRound(20px, 5px);
  }
  ul > ul > li > a {
    line-height: 20px;
    font-size: 14px;
    color: # 333333;
    padding-left: 50px;
    font-weight: normal;
    @include catalogRound;
  }
  a {
    color: # 000;
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 4px 0 4px 12px;
    &:hover {
      background-color: #ebedef;}}}Copy the code

After the modification of the directory effect as follows, seems to have a bit similar. At least not too ugly. The following part mainly introduces how to realize the linkage from article to directory and from directory to article. This is an essential feature

Dynamic correlation

1. Contents to articles

How can directories control the location of articles? Consider 🤔 : Anchor is done by a label but a lot of a label the click event is unable to capture, especially we are through the conversion of a label, but observation found that anchor hash value can increase the anchor position on the url, so think of a solution can be captured by monitoring the change of the url click a tag is which. So we listen for route

@Watch('$route')
  private routechange(val: any) {
    const data = document.getElementsByClassName(`toc-link-${val.hash}`)[0] as Element
    this.linkLists.forEach((list:Element) => {
      data == list ? list.classList.add('active') : list.classList.remove('active')})}Copy the code

To jump to the post response, click on the table of contents. Here’s a hint. Since the page may have nav navigation positioning, the article we jump to will often be covered by the navigation bar, so it needs to be improved, through the CSS property set margin-top = nav height, padding-top = -nav height.

2, the article to the catalog

Directory to the article has talked about, scrolling article how to achieve automatic directory jump? Consider also clarifying your thoughts:

  • 1. Monitor the scrolling distance of the browser
  • 2. Calculate the height of each header from the top of the browser
  • 3. Match the scrolling distance between two headings to realize automatic directory jump

Specific implementation steps:

Mounted () monitors mouse scrolling during the mounted() lifecycle

window.addEventListener(‘scroll’, this.handleScroll, true)

Get all article titles and table of contents

this.$nextTick(async () => {await this.gettitleheight () await this.getcatalogList ()}) // Get the height from top of each article title private asyncgetTitleHeight() {
    let titlelist = Array.prototype.slice.call((this.$refs.article as Element).getElementsByClassName('toc-title')) titlelist.foreach ((item,index) => {this.listheight. Push (item.offsetTop)}) This.listheight. Push (2 * (titlelist[titlelist.length-1].offsettop))} // Fetch all ul, A tags of the directory private AsyncgetCataloglist() {
    let catalogList = (this.$refs.catalog as Element).getElementsByClassName('catalog-list')
    this.linkLists = document.getElementsByName('link')
    this.target = Array.prototype.slice.call(catalogList)
  }
Copy the code

Listen for article scrolling in the handleScroll function

private handleScroll() {
    const scrollY = window.pageYOffset
    this.fixed = scrollY > 230 ? true : false
    for (let i = 0; i < this.listHeight.length-1; i++) {
      let h1: number = this.listHeight[i]
      let h2: number = this.listHeight[i + 1]
      if (scrollY >= h1 && scrollY <= h2) {
        const data: Element = document.getElementsByClassName(`toc-link-#${I} ')[0] as Element
        this.linkLists.forEach((list: Element) => {
          let top: number = 0 
          top = i > 7 ? -28 * (i-7) : 0  
          this.target[0].style.marginTop = `${top}px`
          data == list ? list.classList.add('active') : list.classList.remove('active') // Other remove active})}}}Copy the code

Code explanation:

this.fixed = scrollY > 230 ? true : false

The directory does not scroll with the page, so you need to add a fixed property to the right of the article. 230 is the height of the box in front of the directory. When you scroll 230px the directory is fixed and the effect is in place.

let top: number = 0 
top = i > 7 ? -28 * (i-7) : 0  
this.target[0].style.marginTop = `${top}px`
Copy the code

Although the directory does not scroll with the page, it may not be displayed if the directory is too long, so it needs to dynamically set the margin-top property of the directory.

top = i > 7 ? -28 * (i-7) : 0

“Said

The function is realized, but there are still a lot of places can be optimized, also hope to point out and give advice. If you don’t like this directory, or if your actual needs are different, it’s just CSS. Function implementation often determines the effect, you can rewrite ul > LI CSS according to your own needs. This is just part of what I took away from my actual project. It’s a lot harder than that. But that’s enough. Next time, we’ll learn how to create a gold-digging Style article editor.