vue 显示 markdown 文件

简介: vue 显示 markdown 文件

mdvuemarkdownshowdown

vue 页面显示 readme.md 文件, 使用 showdown.js 实现

使用 npm install showdown --save 安装后,在 vue 文件中引入,如下效果:

<template>
  <div>about</div>
</template>
<script>
import showdown from 'showdown'
import readme from '../../README.md'
console.log(readme)
export default {
  data () {
    return {}
  },
  components: {
    showdown
  }
}
</script>
<style scoped="true"></style>

但是会报错,如下

[WDS] Errors while compiling. Reload prevented.

./README.md Module parse failed: Unexpected character '#' (1:0) You may need an appropriate loader to handle this file type.

原因是不识别这中格式,markdown 中的 ‘#’ 号,安装 markdown-loaderhtml-loader

npm i markdown-loader html-loader --save

webpack.base.conf.js 中添加 rules 规则

{ test: /\.md$/, use: [ { loader: 'html-loader' }, { loader: 'markdown-loader', options: {} } ] }

设置完这些后就好用了,这个时候一些转换后的标签没有样式,需要添加对应的样式,这个可以查看一下简书的或者 github 样式,自行添加。

如果代码显示需要语法高亮,需要单独添加 highlight.js 实现。

完整例子:

markdown.vue

<template>
  <div class="main">
    <el-row>
      <el-col :md="3" :lg="6" :xl="8" class="hidden-sm-and-down">&nbsp;</el-col>
      <el-col :sm="24" :md="18" :lg="12" :xl="8">
        <div v-html="html" class="center"></div>
      </el-col>
      <el-col :md="3" :lg="6" :xl="8" class="hidden-sm-and-down">&nbsp;</el-col>
    </el-row>
  </div>
</template>
<script>
import showdown from 'showdown'
import readme from '../../README.md'
export default {
  data () {
    return {
      md: readme,
      html: ''
    }
  },
  components: {
    showdown
  },
  mounted () {
    let converter = new showdown.Converter()
    let text = this.md.toString()
    this.html = converter.makeHtml(text)
  }
}
</script>
<style>
.main {
  padding: 10px 30px;
}
blockquote {
  border-left: #eee solid 5px;
  padding-left: 15px;
  color: #8e8e8e;
  margin-inline-start: 0px;
  margin-inline-end: 0px;
}
ul li {
  line-height: 25px;
}
pre code {
  background: #F6F6F6;
}
p code {
  color: #D34B62;
  background: #F6F6F6;
  margin: 0 2px;
}
@keyframes squeezeBody {
  from {
    width: 100%;
  }
  to {
    width: calc(100% - 300px);
  }
}
@-webkit-keyframes squeezeBody {
  from {
    width: 100%;
  }
  to {
    width: calc(100% - 300px);
  }
}
@keyframes stretchBody {
  from {
    width: calc(100% - 300px);
  }
  to {
    width: 100%;
  }
}
@-webkit-keyframes stretchBody {
  from {
    width: calc(100% - 300px);
  }
  to {
    width: 100%;
  }
}
.squeezed-body {
  animation: squeezeBody 0.5s ease;
  -webkit-animation: squeezeBody 0.5s ease;
  width: calc(100% - 300px);
}
.full-body {
  animation: stretchBody 0.5s ease;
  -webkit-animation: stretchBody 0.5s ease;
  width: 100%;
}
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: 'Old Standard TT', serif;
  font-weight: bold;
}
h1 {
  border-bottom: 1px solid #ddd;
}
.serif {
  font-family: 'Old Standard TT', serif;
}
.top-bar {
  height: 45px;
  min-height: 45px;
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
}
.bars-lnk {
  color: #fff;
}
.bars-lnk i {
  display: inline-block;
  margin-left: 10px;
  margin-top: 7px;
}
.bars-lnk img {
  display: inline-block;
  margin-left: 10px;
  margin-top: -15px;
  margin-right: 15px;
  height: 35px;
}
.lateral-menu {
  background-color: #333;
  color: rgb(144, 144, 144);
  width: 300px;
  font-family: 'Open Sans', 'Myriad Pro', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Geneva, Verdana, sans-serif;
}
.lateral-menu label {
  color: rgb(144, 144, 144);
}
.lateral-menu-content {
  padding-left: 10px;
  height: 100%;
  font-size: 12px;
  font-style: normal;
  font-variant: normal;
  font-weight: bold;
  line-height: 16px;
}
.lateral-menu-content .title {
  padding-top: 15px;
  font-size: 2em;
  height: 45px;
}
.lateral-menu-content-inner {
  overflow-y: auto;
  height: 100%;
  padding-top: 10px;
  padding-bottom: 50px;
  padding-right: 10px;
  font-size: 0.9em;
}
.container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: stretch;
  width: 100%;
  height: 100%;
  padding-top: 65px;
}
.container>* {
  display: block;
  width: 50%;
  margin-left: 10px;
  margin-right: 10px;
  max-height: 100%;
}
.container textarea {
  resize: none;
  font-family: Consolas, "Liberation Mono", Courier, monospace;
  height: 97%;
  max-height: 97%;
  width: 45%;
}
#preview {
  height: 97%;
  max-height: 97%;
  border: 1px solid #eee;
  overflow-y: scroll;
  width: 55%;
  padding: 10px;
}
pre {
  white-space: pre-wrap;
  /* css-3 */
  white-space: -moz-pre-wrap;
  /* Mozilla, since 1999 */
  white-space: -pre-wrap;
  /* Opera 4-6 */
  white-space: -o-pre-wrap;
  /* Opera 7 */
  word-wrap: break-word;
  /* Internet Explorer 5.5+ */
  background-color: #f8f8f8;
  border: 1px solid #dfdfdf;
  margin-top: 1.5em;
  margin-bottom: 1.5em;
  padding: 0.125rem 0.3125rem 0.0625rem;
}
pre {
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  background-color: #f6f8fa;
  border-radius: 3px;
}
.modal-wrapper {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 999;
  background-color: rgba(51, 51, 51, 0.5);
}
.modal-inner {
  margin-top: 200px;
  margin-left: auto;
  margin-right: auto;
  width: 600px;
  height: 225px;
  background-color: #fff;
  opacity: 1;
  z-index: 1000;
}
.modal-close-btn {
  float: right;
  display: inline-block;
  margin-right: 5px;
  color: #ff4336;
}
.modal-close-btn:hover {
  float: right;
  display: inline-block;
  margin-right: 5px;
  color: #8d0002;
}
.modal-topbar {
  clear: both;
  height: 25px;
}
.modal-inner .link-area {
  margin: 10px;
  height: 170px;
}
.modal-inner textarea {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}
.version {
  color: white;
  font-size: 0.8em !important;
}
</style>

webpack.base.conf.js

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
  return path.join(__dirname, '..', dir)
}
const createLintingRule = () => ({
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  enforce: 'pre',
  include: [resolve('src'), resolve('test')],
  options: {
    formatter: require('eslint-friendly-formatter'),
    emitWarning: !config.dev.showEslintErrorsInOverlay
  }
})
module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.md$/,
        use: [
          {
            loader: 'html-loader'
          },
          {
            loader: 'markdown-loader',
            options: {}
          }
        ]
      }
    ]
  },
  node: {
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native).
    setImmediate: false,
    // prevent webpack from injecting mocks to Node native modules
    // that does not make sense for the client
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}
相关文章
|
2月前
|
JavaScript
详解Vue文件结构+实现一个简单案例
详解Vue文件结构+实现一个简单案例
|
3月前
|
自然语言处理 Shell API
如何翻译 Markdown 文件?-1- 难点及解决方案
如何翻译 Markdown 文件?-1- 难点及解决方案
|
22天前
|
JavaScript 前端开发
vue 实现在线预览PDFpdf文件
vue 实现在线预览PDFpdf文件
31 0
|
1月前
|
JavaScript
vue element 导出blob后台文件流xlsx文件自动下载(且规避乱码)
vue element 导出blob后台文件流xlsx文件自动下载(且规避乱码)
|
2月前
|
JavaScript 前端开发
HTM文件中使用vue
HTM文件中使用vue
11 0
|
3月前
|
JavaScript 前端开发 API
如何翻译 Markdown 文件?-2- 几种商业及开源解决方案介绍
如何翻译 Markdown 文件?-2- 几种商业及开源解决方案介绍
|
3月前
|
druid JavaScript Java
SpringBoot+Vue.js实现大文件分片上传、断点续传与极速秒传
SpringBoot+Vue.js实现大文件分片上传、断点续传与极速秒传
127 0
|
3月前
|
前端开发 JavaScript API
极简运行Vue打包文件:让你的网页快速启动,高效展现!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
4月前
|
JavaScript 小程序 Java
基于Java+SpringBoot+Vue的大学生考勤系统的设计与实现(亮点:多角色、打卡签到、请假审批、上传成绩单文件、统计图展示)
基于Java+SpringBoot+Vue的大学生考勤系统的设计与实现(亮点:多角色、打卡签到、请假审批、上传成绩单文件、统计图展示)
122 0
基于Java+SpringBoot+Vue的大学生考勤系统的设计与实现(亮点:多角色、打卡签到、请假审批、上传成绩单文件、统计图展示)
|
5月前
|
JavaScript 应用服务中间件 nginx
docker安装的nginx放在html文件下的vue项目404解决
docker安装的nginx放在html文件下的vue项目404解决