preface

This NuxT-Blog project is built based on NUxT server rendering (SSR)

rendering

See sdjblog.cn for the full effect

Functional description

Implemented functions

  • Log in
  • The article lists
  • link
  • Comments like this article
  • The article archive
  • A list of items
  • The message list
  • Kanban girl background

Technology library dependency

  • Nuxtjs /axios (API request)
  • @nuxtjs/style-resources (SCSS public file introduction)
  • Element-ui (Component Library)
  • Highlight.js (code highlighting)
  • Moment (Time format processing)
  • Nprogress (Progress bar)
  • Nuxt (Vue framework)

The project structure

- Assets resource file (image, CSS and font icon) - Components - RaindropCanvas Rain Effects - BackTop Back to top - EmptyShow empty state - HeaderNav head navigation - MyForm SideBar - TagBox - Layouts - Pages - Article - Page - _num Article list - archive - Project Articledetail-_id - article list header and sidebar - index Default home page route - Message list - Plugins package - static Kanban.com, background resources, etc Store Vuex state management - utils Form verification, title directory navigation, time formatting and other common methods encapsulation - nuxt.config Personalized configurationCopy the code

The sidebar

  • Get the corresponding inspirational statement display by week

  • Related contact information, such as Github, code cloud, background login page and nuggets, etc

  • Filter the list of articles by article tag and article sorting

  • Link display

The article archive

Article list formatting, merge the same month data content in the list data into a new array, and regenerate the month list data

async asyncData({ $axios }) {
  const res = await $axios.get('/blogPage/statistics/articleArchive')
  let total = res.data.length
  let data = res.data
  let arr = []
  let articleList = []
  if(data.length > 0){
    data.forEach(item= >{
      let outerObj = { month: item._id.month, articleArr: []}let inObj = { articleId: item._id.id, title: item._id.title, createTime: item._id.createTime}
      outerObj.articleArr.push(inObj);
      arr.push(outerObj);
    })
    let newData = []; // Target array
    let newObj = {};
    arr.forEach((item, index) = > {
      if(! newObj[item.month]) { newData.push(item); newObj[item.month] =true;
      } else {
        newData.forEach(data= > {
          if (data.month === item.month) {
            data.articleArr = [...data.articleArr, ...item.articleArr]
          }
        })
      }
    })
    articleList = newData
  }
  return { articleList, total }
}
Copy the code

The article details

Add class to the content H title tag and extract the title generation directory

// Add class to the title
export function catalogList(content) {
  // remove marked parsing generates the ID in the h header tag
  // content = content.replace(/(\sid\s*=[\s\'\"].*? [\s\'\"])/g,"")
  const toc = content.match(/<[hH][1-6]>.*? <\/[hH][1-6]>/g)
  let tocList = null
  if (toc && toc.length > 0) {
    toc.forEach((item, index) = > {
      let _toc = `<div class='rich-title' id='content-title${index}'>${item} </div>`
      content = content.replace(item, _toc)
    })
    tocList = toToc(toc)
  }else{
    tocList = '
      
directory (none)
\n'
} let obj = { tocList, content } return obj } // The article content h tag generates the title directory function toToc(data) { let levelStack = [] let result = '
directory
\n'
const addStartList = () = > { result += `<div class="catalog-list">\n`; } const addEndList = () = > { result += '</div>\n'; } const addLInk = (index, itemText) = > { result += `<div class='catalog-link' title='${itemText}' id='title${index}'>${itemText}</div>\n`; } data.forEach(function (item, index) { let itemText = item.replace(/<[^>]+>/g.' ') // Matches the text in the h tag let itemLabel = item.match(/<\w+? >/) [0] / / match h? Tag < h? > let levelIndex = levelStack.indexOf(itemLabel) // Check whether ?> label, ul and LI are added ?> if (levelIndex === -1) { levelStack.unshift(itemLabel) addStartList() addLInk(index, itemText) } tag, and put li directly under this ul at the top of the stack ?> else if (levelIndex === 0) { addLInk(index, itemText) } tag, but not at the top of the stack, requires that all previous ?> else { while (levelIndex--) { levelStack.shift() addEndList() } addLInk(index, itemText) } }) // If there is while (levelStack.length) { levelStack.shift() addEndList() } return result } Copy the code

Click the TAB directory to jump to the corresponding location and scroll to the listening location to highlight the title

//rich-title Specifies the class to be added to the content title
this.$nextTick(() = >{
  let linkArr = document.querySelectorAll(".rich-title")
  let linkTopArr = []
  if(linkArr.length > 0){
    linkArr.forEach(item= >{
      linkTopArr.push(item.offsetTop - 130)
    })
    linkTopArr.push(2 * linkTopArr[linkTopArr.length-1])
    this.linkTopArr = linkTopArr
  }
  window.addEventListener('scroll'.this.handleScroll, true)})// Scroll listener
handleScroll(){
  let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
  let {linkTopArr} = this
  const linkArr = document.querySelectorAll(".catalog-link")
  if(linkArr.length > 0) {for(let i = 0; i < linkTopArr.length; i++){
      let start = linkTopArr[i]
      let top = linkTopArr[i + 1]
      if (scrollTop >= start && scrollTop <= top) {
          // Get the target element to scroll the article to the directory
        linkArr.forEach((item) = > {
          item.classList.remove('link-active')})if(linkArr[i]){
          linkArr[i].classList.add('link-active')}break; }}}}Copy the code

The message list

Mouse drag message movement, when the drag move to the top, rain effect

// Bind mouse press events<div class="box-item" v-for='item in messageList' :key='item._id' :style="item.style" @mousedown.prevent="mousedown" v-show='initData'></div>
Copy the code
// Drag the message down and hold down the left mouse button
mousedown (e) {
  this.isDrag = true
  this.dragObj = e.currentTarget
  this.dragMouseOffset = this.getCurrentOffset(e)
  this.maxDragOffset = this.getMaxDragOffset(e)
  this.LiftingZIndex()
  document.addEventListener('mousemove'.this.mousemove)
  document.addEventListener('mouseup'.this.mouseup)
},
// Mouse distance element position
getCurrentOffset (e) {
  let target = e.target
  let offset = {
      x: 0.y: 0
  }
  while (target.className.indexOf('box-item') < 0) {
      offset = {
          x: offset.x + target.offsetLeft + target.clientLeft,
          y: offset.y + target.offsetTop + target.clientTop
      }
      target = target.offsetParent
  }
  offset = {
      x: e.offsetX + offset.x,
      y: e.offsetY + offset.y + 60,}return offset
},
/ / to get
getMaxDragOffset (e) {
    const target = e.currentTarget
    let w = target.offsetWidth,
        h = target.offsetHeight
    return {
        w: this.screen.width - w,
        h: this.screen.height - h - 60}},// The current element is upgraded
LiftingZIndex () {
    this.noteIndex += 1
    this.dragObj.style.zIndex = this.noteIndex
},
mousemove (e) {
    if (!this.isDrag) return
    let {x, y} = this.getCurrentEleCoords(e)
    let {w, h} = this.maxDragOffset
    if (x < 0) x = 0
    if (x > w) x = w
    if (y < 0) y = 0
    if (y > h) y = h
    this.dragObj.style.left = `${x}px`
    this.dragObj.style.top = `${y}px`
    if(y <= 0) {this.showRaindropCanvas = true}},// The current mouse distance
getCurrentEleCoords(e){ 
    return {
        x: e.clientX - this.dragMouseOffset.x,
        y: e.clientY - this.dragMouseOffset.y
    }
},
mouseup () {
  this.isDrag = false
}
Copy the code

Kanban girl background

By importing resources in nuxt.config.js

Head: {title: 'personal blog ', meta: [{charset:' utF-8 '}, {name: 'viewport', content: 'width=device-width, initial-scale=1'}, {hid: 'keywords', name: 'keywords', content: 'front-end, blog, vue, node'}, {hid: 'description', name: 'description', Content: 'Personal technical blog, vue, node'}], link: [{rel: 'icon', type: 'image/x-icon', href: '/ favicon. Ico'}], script: [{SRC: '/ live2dw/lib/L2Dwidget. Min. Js' / / kanban musume}, {SRC:'/navigator. Js / / device type judgment}, {SRC :'/ bgshow.js ', // body: true}]},Copy the code
// Initialize render in Layout
created() {
  if (process.browser) {
    setTimeout(() = > {
      window.L2Dwidget.init({
        pluginRootPath: "/live2dw/".pluginJsPath: "lib/".pluginModelPath: `live2d-widget-model-shizuku/assets/`.tagMode: false.debug: false.model: {
          jsonPath: `/live2dw/live2d-widget-model-shizuku/assets/shizuku.model.json`
        },
        display: {
          position: "right".width: 220.height: 400.hOffset: 30.vOffset: -45
        },
        react: { opacity: 0.7 },
        mobile: { show: true },
        log: false
      });
    }, 400); }}Copy the code

instructions

Nuxt, static, nuxt.config.js, and package.json files on the server. Run NPM install to install dependencies. Pm2 start NPM –name “nuxtBlog” — run start to start service, package.json config config port

Building installation

# install dependencies
$ npm install

# Development environment
$ npm run dev

# Package production environment
$ npm run build
$ npm run start

Static packaging
$ npm run generate
Copy the code

Project Address:

Front Desk Presentation: https://gitee.com/sdj_work/blog-page (Vue/Nuxt/ UNI-app)

Management background: https://gitee.com/sdj_work/blog-admin (Vue/React)

Back-end Node: https://gitee.com/sdj_work/blog-node (Express/Koa)

Blog: https://sdjBlog.cn/

Project series:

Vue+Nuxt blog display

Vue+ UniAPP blog display

Vue+ElementUI backstage blog management

Node + KOA + mongodb blog interface development

Node + Express + mongodb blog interface development