所以,这就是我想出的。我认为这很丑陋,但它确实有效。
<template>
<template v-for="(item, index) in lines" :key="index">
<router-link :to="item.Route" v-if="item.Type === 'route'">{{ item.Value }}</router-link>
<br v-else-if="item.Type === 'break'">
<template v-else>{{ item.Value }}</template>
</template>
</template>
<script>
import { defineComponent, h } from 'vue';
export default defineComponent({
name: 'TokenizedText',
props: {
text: {
type: String,
required: true,
},
symbols: {
type: Array,
default: () => []
},
handles: {
type: Array,
default: () => []
},
topics: {
type: Array,
default: () => []
},
},
computed: {
lines() {
return new Token("str", this.text).Tokenize(this.symbols || [], this.handles || [], this.topics || []).Build()
}
},
})
function Token(type, value) {
this.Type = type
this.Value = value
this.Route = {}
this.Children = []
}
Token.prototype.Build = function() {
let out = []
if (this.Value.length > 0 ||this.Type === 'break') {
out.push(this)
}
for (let i in this.Children) {
out.push.apply(out, this.Children[i].Build())
}
return out
}
Token.prototype.Tokenize = function(symbols, handles, topics) {
if (this.Type === "str") {
let breakLines = this.Value.split("\n")
if (breakLines.length > 1) {
this.Value = ""
for (let key in breakLines) {
this.Children.push(new Token("str", breakLines[key]).Tokenize(symbols, handles, topics))
if (key < breakLines.length - 1) {
this.Children.push(new Token("break", ""))
}
}
return this
}
}
handles.sort((a, b) => a.length - b.length)
for (let h in handles) {
if (this.Value.toLowerCase() === "@"+handles[h].toLowerCase()) {
this.Type = "route"
this.Route = {name: "user.view", params: {handle: handles[h]}}
return this
}
let handleLines = this.Value.split(new RegExp(`@\\b${handles[h]}\\b`, 'gmi'))
let handleOriginals = this.Value.match(new RegExp(`@\\b${handles[h]}\\b`, 'gmi')) || []
if (handleLines.length > 1) {
this.Value = ""
for (let l in handleLines) {
if (handleLines[l].length > 0) {
this.Children.push(new Token("str", handleLines[l]).Tokenize(symbols, handles, topics))
}
if (l < handleLines.length-1) {
let line = handleOriginals[l] || "@"+handles[h]
console.log(line)
this.Children.push(new Token("route", line).Tokenize(symbols, handles, topics))
}
}
return this
}
}
topics.sort((a, b) => a.length - b.length)
for (let h in topics) {
if (this.Value.toLowerCase() === "#"+topics[h].toLowerCase()) {
this.Type = "route"
this.Route= {name: "topic.view", params: {tag: topics[h]}}
return this
}
let topicLines = this.Value.split(new RegExp(`#\\b${topics[h]}\\b`, 'gmi'))
let topicOriginals = this.Value.match(new RegExp(`#\\b${topics[h]}\\b`, 'gmi')) || []
if (topicLines.length > 1) {
this.Value = ""
for (let l in topicLines) {
if (topicLines[l].length > 0) {
this.Children.push(new Token("str", topicLines[l]).Tokenize(symbols, handles, topics))
}
if (l < topicLines.length-1) {
let line = topicOriginals[l] || "#"+topics[h]
this.Children.push(new Token("route", line).Tokenize(symbols, handles, topics))
}
}
return this
}
}
symbols.sort((a, b) => a.length - b.length)
for (let h in symbols) {
if (this.Value.toLowerCase() === "$"+symbols[h].toLowerCase()) {
this.Type = "route"
this.Route= {name: "symbol.view", params: {symbol: symbols[h]}}
return this
}
let symbolLines = this.Value.split(new RegExp(`\\$\\b${symbols[h]}\\b`, 'gmi'))
let symbolOriginals = this.Value.match(new RegExp(`\\$\\b${symbols[h]}\\b`, 'gmi')) || []
if (symbolLines.length > 1) {
this.Value = ""
for (let l in symbolLines) {
if (symbolLines[l].length > 0) {
this.Children.push(new Token("str", symbolLines[l]).Tokenize(symbols, handles, topics))
}
if (l < symbolLines.length-1) {
let line = symbolOriginals[l] || "$"+symbols[h]
this.Children.push(new Token("route", line).Tokenize(symbols, handles, topics))
}
}
return this
}
}
return this
}
</script>