parent
0880661727
commit
1a8a62f598
@ -0,0 +1,5 @@
|
|||||||
|
export default {
|
||||||
|
copyByClickCode: true, // 点击代码块复制
|
||||||
|
showLanguageName: true, // 是否在代码块右上角显示语言的名称
|
||||||
|
showLineNumber: false // 是否显示行号
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview highlight 插件
|
||||||
|
* Include prismjs (https://prismjs.com)
|
||||||
|
*/
|
||||||
|
import prism from './prism.min'
|
||||||
|
import config from './config'
|
||||||
|
import Parser from '../parser'
|
||||||
|
|
||||||
|
function Highlight (vm) {
|
||||||
|
this.vm = vm
|
||||||
|
}
|
||||||
|
|
||||||
|
Highlight.prototype.onParse = function (node, vm) {
|
||||||
|
if (node.name === 'pre') {
|
||||||
|
if (vm.options.editable) {
|
||||||
|
node.attrs.class = (node.attrs.class || '') + ' hl-pre'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let i
|
||||||
|
for (i = node.children.length; i--;) {
|
||||||
|
if (node.children[i].name === 'code') break
|
||||||
|
}
|
||||||
|
if (i === -1) return
|
||||||
|
const code = node.children[i]
|
||||||
|
let className = code.attrs.class + ' ' + node.attrs.class
|
||||||
|
i = className.indexOf('language-')
|
||||||
|
if (i === -1) {
|
||||||
|
i = className.indexOf('lang-')
|
||||||
|
if (i === -1) {
|
||||||
|
className = 'language-text'
|
||||||
|
i = 9
|
||||||
|
} else {
|
||||||
|
i += 5
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i += 9
|
||||||
|
}
|
||||||
|
let j
|
||||||
|
for (j = i; j < className.length; j++) {
|
||||||
|
if (className[j] === ' ') break
|
||||||
|
}
|
||||||
|
const lang = className.substring(i, j)
|
||||||
|
if (code.children.length) {
|
||||||
|
const text = this.vm.getText(code.children).replace(/&/g, '&')
|
||||||
|
if (!text) return
|
||||||
|
if (node.c) {
|
||||||
|
node.c = undefined
|
||||||
|
}
|
||||||
|
if (prism.languages[lang]) {
|
||||||
|
code.children = (new Parser(this.vm).parse(
|
||||||
|
// 加一层 pre 保留空白符
|
||||||
|
'<pre>' + prism.highlight(text, prism.languages[lang], lang).replace(/token /g, 'hl-') + '</pre>'))[0].children
|
||||||
|
}
|
||||||
|
node.attrs.class = 'hl-pre'
|
||||||
|
code.attrs.class = 'hl-code'
|
||||||
|
code.attrs.style ='display:block;overflow: auto;'
|
||||||
|
if (config.showLanguageName) {
|
||||||
|
node.children.push({
|
||||||
|
name: 'div',
|
||||||
|
attrs: {
|
||||||
|
class: 'hl-language',
|
||||||
|
style: 'user-select:none;position:absolute;top:0;right:2px;font-size:10px;'
|
||||||
|
},
|
||||||
|
children: [{
|
||||||
|
type: 'text',
|
||||||
|
text: lang
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (config.copyByClickCode) {
|
||||||
|
node.attrs.style += (node.attrs.style || '') + ';user-select:none;'
|
||||||
|
node.attrs['data-content'] = text
|
||||||
|
node.children.push({
|
||||||
|
name: 'div',
|
||||||
|
attrs: {
|
||||||
|
class: 'hl-copy',
|
||||||
|
style: 'user-select:none;position:absolute;top:0;right:3px;font-size:10px;'
|
||||||
|
},
|
||||||
|
// children: [{
|
||||||
|
// type: 'text',
|
||||||
|
// text: '复制'
|
||||||
|
// }]
|
||||||
|
})
|
||||||
|
vm.expose()
|
||||||
|
// console.log('vm',node,vm)
|
||||||
|
}
|
||||||
|
if (config.showLineNumber) {
|
||||||
|
const line = text.split('\n').length; const children = []
|
||||||
|
for (let k = line; k--;) {
|
||||||
|
children.push({
|
||||||
|
name: 'span',
|
||||||
|
attrs: {
|
||||||
|
class: 'span'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
node.children.push({
|
||||||
|
name: 'span',
|
||||||
|
attrs: {
|
||||||
|
class: 'line-numbers-rows'
|
||||||
|
},
|
||||||
|
children
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Highlight
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview markdown 插件
|
||||||
|
* Include marked (https://github.com/markedjs/marked)
|
||||||
|
* Include github-markdown-css (https://github.com/sindresorhus/github-markdown-css)
|
||||||
|
*/
|
||||||
|
import marked from './marked.min'
|
||||||
|
let index = 0
|
||||||
|
|
||||||
|
function Markdown (vm) {
|
||||||
|
this.vm = vm
|
||||||
|
vm._ids = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Markdown.prototype.onUpdate = function (content) {
|
||||||
|
if (this.vm.markdown) {
|
||||||
|
return marked(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Markdown.prototype.onParse = function (node, vm) {
|
||||||
|
if (vm.options.markdown) {
|
||||||
|
// 中文 id 需要转换,否则无法跳转
|
||||||
|
if (vm.options.useAnchor && node.attrs && /[\u4e00-\u9fa5]/.test(node.attrs.id)) {
|
||||||
|
const id = 't' + index++
|
||||||
|
this.vm._ids[node.attrs.id] = id
|
||||||
|
node.attrs.id = id
|
||||||
|
}
|
||||||
|
if (node.name === 'p' || node.name === 'table' || node.name === 'tr' || node.name === 'th' || node.name === 'td' || node.name === 'blockquote' || node.name === 'pre' || node.name === 'code') {
|
||||||
|
node.attrs.class = `md-${node.name} ${node.attrs.class || ''}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Markdown
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,175 @@
|
|||||||
|
const blank = {
|
||||||
|
' ': true,
|
||||||
|
'\n': true,
|
||||||
|
'\t': true,
|
||||||
|
'\r': true,
|
||||||
|
'\f': true
|
||||||
|
}
|
||||||
|
|
||||||
|
function Parser () {
|
||||||
|
this.styles = []
|
||||||
|
this.selectors = []
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 解析 css 字符串
|
||||||
|
* @param {string} content css 内容
|
||||||
|
*/
|
||||||
|
Parser.prototype.parse = function (content) {
|
||||||
|
new Lexer(this).parse(content)
|
||||||
|
return this.styles
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 解析到一个选择器
|
||||||
|
* @param {string} name 名称
|
||||||
|
*/
|
||||||
|
Parser.prototype.onSelector = function (name) {
|
||||||
|
// 不支持的选择器
|
||||||
|
if (name.includes('[') || name.includes('*') || name.includes('@')) return
|
||||||
|
const selector = {}
|
||||||
|
// 伪类
|
||||||
|
if (name.includes(':')) {
|
||||||
|
const info = name.split(':')
|
||||||
|
const pseudo = info.pop()
|
||||||
|
if (pseudo === 'before' || pseudo === 'after') {
|
||||||
|
selector.pseudo = pseudo
|
||||||
|
name = info[0]
|
||||||
|
} else return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分割交集选择器
|
||||||
|
function splitItem (str) {
|
||||||
|
const arr = []
|
||||||
|
let i, start
|
||||||
|
for (i = 1, start = 0; i < str.length; i++) {
|
||||||
|
if (str[i] === '.' || str[i] === '#') {
|
||||||
|
arr.push(str.substring(start, i))
|
||||||
|
start = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!arr.length) {
|
||||||
|
return str
|
||||||
|
} else {
|
||||||
|
arr.push(str.substring(start, i))
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后代选择器
|
||||||
|
if (name.includes(' ')) {
|
||||||
|
selector.list = []
|
||||||
|
const list = name.split(' ')
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
if (list[i].length) {
|
||||||
|
// 拆分子选择器
|
||||||
|
const arr = list[i].split('>')
|
||||||
|
for (let j = 0; j < arr.length; j++) {
|
||||||
|
selector.list.push(splitItem(arr[j]))
|
||||||
|
if (j < arr.length - 1) {
|
||||||
|
selector.list.push('>')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selector.key = splitItem(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectors.push(selector)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 解析到选择器内容
|
||||||
|
* @param {string} content 内容
|
||||||
|
*/
|
||||||
|
Parser.prototype.onContent = function (content) {
|
||||||
|
// 并集选择器
|
||||||
|
for (let i = 0; i < this.selectors.length; i++) {
|
||||||
|
this.selectors[i].style = content
|
||||||
|
}
|
||||||
|
this.styles = this.styles.concat(this.selectors)
|
||||||
|
this.selectors = []
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description css 词法分析器
|
||||||
|
* @param {object} handler 高层处理器
|
||||||
|
*/
|
||||||
|
function Lexer (handler) {
|
||||||
|
this.selector = ''
|
||||||
|
this.style = ''
|
||||||
|
this.handler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
Lexer.prototype.parse = function (content) {
|
||||||
|
this.i = 0
|
||||||
|
this.content = content
|
||||||
|
this.state = this.blank
|
||||||
|
for (let len = content.length; this.i < len; this.i++) {
|
||||||
|
this.state(content[this.i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lexer.prototype.comment = function () {
|
||||||
|
this.i = this.content.indexOf('*/', this.i) + 1
|
||||||
|
if (!this.i) {
|
||||||
|
this.i = this.content.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lexer.prototype.blank = function (c) {
|
||||||
|
if (!blank[c]) {
|
||||||
|
if (c === '/' && this.content[this.i + 1] === '*') {
|
||||||
|
this.comment()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.selector += c
|
||||||
|
this.state = this.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lexer.prototype.name = function (c) {
|
||||||
|
if (c === '/' && this.content[this.i + 1] === '*') {
|
||||||
|
this.comment()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (c === '{' || c === ',' || c === ';') {
|
||||||
|
this.handler.onSelector(this.selector.trimEnd())
|
||||||
|
this.selector = ''
|
||||||
|
if (c !== '{') {
|
||||||
|
while (blank[this.content[++this.i]]);
|
||||||
|
}
|
||||||
|
if (this.content[this.i] === '{') {
|
||||||
|
this.floor = 1
|
||||||
|
this.state = this.val
|
||||||
|
} else {
|
||||||
|
this.selector += this.content[this.i]
|
||||||
|
}
|
||||||
|
} else if (blank[c]) {
|
||||||
|
this.selector += ' '
|
||||||
|
} else {
|
||||||
|
this.selector += c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lexer.prototype.val = function (c) {
|
||||||
|
if (c === '/' && this.content[this.i + 1] === '*') {
|
||||||
|
this.comment()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (c === '{') {
|
||||||
|
this.floor++
|
||||||
|
} else if (c === '}') {
|
||||||
|
this.floor--
|
||||||
|
if (!this.floor) {
|
||||||
|
this.handler.onContent(this.style)
|
||||||
|
this.style = ''
|
||||||
|
this.state = this.blank
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.style += c
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Parser
|
@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<view class="zero-markdown-view">
|
||||||
|
<mp-html :key="mpkey" :selectable="selectable" :scroll-table='scrollTable' :tag-style="tagStyle"
|
||||||
|
:markdown="true" :content="html">
|
||||||
|
</mp-html>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mpHtml from '../mp-html/mp-html';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'zero-markdown-view',
|
||||||
|
components: {
|
||||||
|
mpHtml
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
markdown: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
selectable: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
scrollTable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
themeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#007AFF'
|
||||||
|
},
|
||||||
|
codeBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2d2d2d'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
html: '',
|
||||||
|
tagStyle: '',
|
||||||
|
mpkey: 'zero'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
markdown: function(val) {
|
||||||
|
this.html = this.markdown
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initTagStyle();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
this.html = this.markdown
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
initTagStyle() {
|
||||||
|
const themeColor = this.themeColor
|
||||||
|
const codeBgColor = this.codeBgColor
|
||||||
|
let zeroStyle = {
|
||||||
|
p: `
|
||||||
|
margin:5px 5px;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height:1.75;
|
||||||
|
letter-spacing:0.2em;
|
||||||
|
word-spacing:0.1em;
|
||||||
|
`,
|
||||||
|
// 一级标题
|
||||||
|
h1: `
|
||||||
|
margin:25px 0;
|
||||||
|
font-size: 24px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
color: ${themeColor};
|
||||||
|
padding:3px 10px 1px;
|
||||||
|
border-bottom: 2px solid ${themeColor};
|
||||||
|
border-top-right-radius:3px;
|
||||||
|
border-top-left-radius:3px;
|
||||||
|
`,
|
||||||
|
// 二级标题
|
||||||
|
h2: `
|
||||||
|
margin:40px 0 20px 0;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align:center;
|
||||||
|
color:${themeColor};
|
||||||
|
font-weight:bolder;
|
||||||
|
padding-left:10px;
|
||||||
|
// border:1px solid ${themeColor};
|
||||||
|
`,
|
||||||
|
// 三级标题
|
||||||
|
h3: `
|
||||||
|
margin:30px 0 10px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
color: ${themeColor};
|
||||||
|
padding-left:10px;
|
||||||
|
border-left:3px solid ${themeColor};
|
||||||
|
`,
|
||||||
|
// 引用
|
||||||
|
blockquote: `
|
||||||
|
margin:15px 0;
|
||||||
|
font-size:15px;
|
||||||
|
color: #777777;
|
||||||
|
border-left: 4px solid #dddddd;
|
||||||
|
padding: 0 10px;
|
||||||
|
`,
|
||||||
|
// 列表
|
||||||
|
ul: `
|
||||||
|
margin: 10px 0;
|
||||||
|
color: #555;
|
||||||
|
`,
|
||||||
|
li: `
|
||||||
|
margin: 5px 0;
|
||||||
|
color: #555;
|
||||||
|
`,
|
||||||
|
// 链接
|
||||||
|
a: `
|
||||||
|
// color: ${themeColor};
|
||||||
|
`,
|
||||||
|
// 加粗
|
||||||
|
strong: `
|
||||||
|
font-weight: border;
|
||||||
|
color: ${themeColor};
|
||||||
|
`,
|
||||||
|
// 斜体
|
||||||
|
em: `
|
||||||
|
color: ${themeColor};
|
||||||
|
letter-spacing:0.3em;
|
||||||
|
`,
|
||||||
|
// 分割线
|
||||||
|
hr: `
|
||||||
|
height:1px;
|
||||||
|
padding:0;
|
||||||
|
border:none;
|
||||||
|
// border-top:medium solid #333;
|
||||||
|
text-align:center;
|
||||||
|
background-image:linear-gradient(to right,rgba(248,57,41,0),${themeColor},rgba(248,57,41,0));
|
||||||
|
`,
|
||||||
|
// 表格
|
||||||
|
table: `
|
||||||
|
border-spacing:0;
|
||||||
|
overflow:auto;
|
||||||
|
min-width:100%;
|
||||||
|
margin:10px 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
`,
|
||||||
|
th: `
|
||||||
|
border: 1px solid #202121;
|
||||||
|
color: #555;
|
||||||
|
`,
|
||||||
|
td: `
|
||||||
|
color:#555;
|
||||||
|
border: 1px solid #555555;
|
||||||
|
`,
|
||||||
|
pre: `
|
||||||
|
border-radius: 5px;
|
||||||
|
white-space: pre;
|
||||||
|
background: ${codeBgColor};
|
||||||
|
font-size:12px;
|
||||||
|
position: relative;
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
this.tagStyle = zeroStyle
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.zero-markdown-view {
|
||||||
|
padding: 15rpx;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"id": "zero-markdown-view",
|
||||||
|
"displayName": "zero-markdown-view(markdown解析)",
|
||||||
|
"version": "2.0.5",
|
||||||
|
"description": "一行代码即可实现markdown解析,支持自定义主题色,支持vue2,vue3.",
|
||||||
|
"keywords": [
|
||||||
|
"markdown",
|
||||||
|
"markdown解析",
|
||||||
|
"代码块",
|
||||||
|
"代码高亮",
|
||||||
|
"mp-html"
|
||||||
|
],
|
||||||
|
"repository": "",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": "^3.1.0"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"type": "component-vue",
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "插件不采集任何数据",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": ""
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "n"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
},
|
||||||
|
"App": {
|
||||||
|
"app-vue": "u",
|
||||||
|
"app-nvue": "u"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "u",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "u",
|
||||||
|
"百度": "u",
|
||||||
|
"字节跳动": "u",
|
||||||
|
"QQ": "u",
|
||||||
|
"钉钉": "u",
|
||||||
|
"快手": "u",
|
||||||
|
"飞书": "u",
|
||||||
|
"京东": "u"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue