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'
  }
}
目录
相关文章
|
4天前
|
人工智能 文字识别 数据挖掘
MarkItDown:微软开源的多格式转Markdown工具,支持将PDF、Word、图像和音频等文件转换为Markdown格式
MarkItDown 是微软开源的多功能文档转换工具,支持将 PDF、PPT、Word、Excel、图像、音频等多种格式的文件转换为 Markdown 格式,具备 OCR 文字识别、语音转文字和元数据提取等功能。
59 9
MarkItDown:微软开源的多格式转Markdown工具,支持将PDF、Word、图像和音频等文件转换为Markdown格式
|
1月前
|
程序员
【Markdown速成】半小时入门Markdown教程(后缀.md文件详解)
作为程序员我们经常会看到README.md这种说明文件,以.md为后缀的文件就是我们所说的Markdown的文件。
176 4
|
2月前
|
JSON 缓存 JavaScript
vue尚品汇商城项目-day01【1.vue-cli脚手架初始化项目生成文件的介绍】
vue尚品汇商城项目-day01【1.vue-cli脚手架初始化项目生成文件的介绍】
33 0
|
4月前
|
存储 自然语言处理 前端开发
Star 6.9k!开源的全能Markdown格式文件提取器:MinerU
总的来说,MinerU是一款非常实用且强大的数据提取工具。无论你是开发者、互联网从业者,还是有具体需求的新人小白,MinerU都能极大地提升你的工作效率,让你专注于更有价值的工作。 最后,如果你对MinerU感兴趣,不妨亲自尝试一下,相信你会爱上这款全能的Markdown格式文件提取器。
|
4月前
|
Web App开发 Linux Windows
解决Markdown文件上传至CSDN无法显示本地图片问题-白嫖版,分享给别人的md文件图片不显示的解决方案
解决Markdown文件上传至CSDN无法显示本地图片问题-白嫖版,分享给别人的md文件图片不显示的解决方案
119 3
|
4月前
|
JavaScript 容器
Vue学习之--------组件的基本使用(非单文件组件)(代码实现)(2022/7/22)
这篇文章讲解了Vue中组件的基本使用方法,包括组件的定义、注册和使用过程,并通过代码实例演示了非单文件组件的创建和使用,同时指出了一些使用组件时的注意事项。
Vue学习之--------组件的基本使用(非单文件组件)(代码实现)(2022/7/22)
|
5月前
|
JavaScript Java
Java 将Markdown文件转换为Word和PDF文档
【7月更文挑战第5天】Java中使用`Spire.Doc for Java`库可方便地将Markdown转换为Word或PDF。基本步骤包括导入模块,创建`Document`对象,加载Markdown文件,然后保存为目标格式(`.docx`或`.pdf`)。若遇到`Invalid UTF-8 stream`错误,需确保Markdown文件是UTF-8无BOM编码。页面设置可通过`PageSetup`类调整。注意,实际应用会依据具体需求和环境有所调整。
333 6
|
4月前
|
JavaScript
Vue————Vue v2.7.14 入口文件【二】
Vue————Vue v2.7.14 入口文件【二】
66 0
|
5月前
|
JavaScript
vue项目打包后自动压缩成zip文件
vue项目打包后自动压缩成zip文件
421 0
|
6月前
|
JavaScript 前端开发
Vue,如何引入样式文件
Vue,如何引入样式文件