|
@@ -0,0 +1,186 @@
|
|
|
+<template>
|
|
|
+ <el-container>
|
|
|
+ <el-main>
|
|
|
+ <el-row :gutter="5">
|
|
|
+ <el-col :span="2">
|
|
|
+ <div style="height: 30px"></div>
|
|
|
+ <div style="padding: 4px">
|
|
|
+ <el-checkbox v-model="clearWhenChangeType">
|
|
|
+ <div>更换类型时</div>
|
|
|
+ <div>清空文本</div>
|
|
|
+ </el-checkbox>
|
|
|
+ </div>
|
|
|
+ <div style="height: 10px"></div>
|
|
|
+ <div style="padding: 4px"><el-radio v-model="type" label="JSON" @change="onTypeChange">JSON</el-radio></div>
|
|
|
+ <div style="padding: 4px"><el-radio v-model="type" label="XML" @change="onTypeChange">XML</el-radio></div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <pre :style="preStyle" class="formatted-body">
|
|
|
+ <el-input v-model="originContent" type="textarea" rows="30" :placeholder="placeholder" @input="executeFormat"></el-input>
|
|
|
+ </pre>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="14">
|
|
|
+ <pre :style="[preStyle, resultBackGround]" class="formatted-result">{{ formattedResult }}</pre>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-main>
|
|
|
+ </el-container>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { computed, ref } from 'vue'
|
|
|
+import { useStore } from 'vuex'
|
|
|
+
|
|
|
+export default {
|
|
|
+ setup() {
|
|
|
+ const store = useStore()
|
|
|
+ const windowSize = store.state.app.windowSize
|
|
|
+
|
|
|
+ const clearWhenChangeType = ref(false)
|
|
|
+ const type = ref('JSON')
|
|
|
+
|
|
|
+ const placeholder = computed(() => {
|
|
|
+ return `把要格式化的${type.value}字符串放在这里...`
|
|
|
+ })
|
|
|
+
|
|
|
+ const preStyle = {
|
|
|
+ width: '92%',
|
|
|
+ height: windowSize.h - 50 + 'px',
|
|
|
+ overflowY: 'auto',
|
|
|
+ }
|
|
|
+
|
|
|
+ const onTypeChange = () => {
|
|
|
+ if (clearWhenChangeType.value) {
|
|
|
+ originContent.value = null
|
|
|
+ formattedResult.value = null
|
|
|
+ } else {
|
|
|
+ executeFormat()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const originContent = ref(null)
|
|
|
+ const formattedResult = ref(null)
|
|
|
+ const trueJson = ref(true)
|
|
|
+ const resultBackGround = computed(() => {
|
|
|
+ return {
|
|
|
+ background: trueJson.value ? '#90da6b7a' : '#f3818186',
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ const formatXml = () => {
|
|
|
+ let text = originContent.value
|
|
|
+ text =
|
|
|
+ '\n' +
|
|
|
+ text
|
|
|
+ .replace(/(<\w+)(\s.*?>)/g, function ($0, name, props) {
|
|
|
+ return name + ' ' + props.replace(/\s+(\w+=)/g, ' $1')
|
|
|
+ })
|
|
|
+ .replace(/>\s*?</g, '>\n<')
|
|
|
+ text = text
|
|
|
+ .replace(/\n/g, '\r')
|
|
|
+ .replace(/<!--(.+?)-->/g, function ($0, text) {
|
|
|
+ var ret = '<!--' + escape(text) + '-->'
|
|
|
+ return ret
|
|
|
+ })
|
|
|
+ .replace(/\r/g, '\n')
|
|
|
+ var rgx = /\n(<(([^\?]).+?)(?:\s|\s*?>|\s*?(\/)>)(?:.*?(?:(?:(\/)>)|(?:<(\/)\2>)))?)/gm
|
|
|
+ var nodeStack = []
|
|
|
+ var output = text.replace(rgx, function ($0, all, name, isBegin, isCloseFull1, isCloseFull2, isFull1, isFull2) {
|
|
|
+ var isClosed = isCloseFull1 == '/' || isCloseFull2 == '/' || isFull1 == '/' || isFull2 == '/'
|
|
|
+ var prefix = ''
|
|
|
+ if (isBegin == '!') {
|
|
|
+ //!开头
|
|
|
+ prefix = setPrefix(nodeStack.length)
|
|
|
+ } else {
|
|
|
+ if (isBegin != '/') {
|
|
|
+ ///开头
|
|
|
+ prefix = setPrefix(nodeStack.length)
|
|
|
+ if (!isClosed) {
|
|
|
+ //非关闭标签
|
|
|
+ nodeStack.push(name)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ nodeStack.pop() //弹栈
|
|
|
+ prefix = setPrefix(nodeStack.length)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var ret = '\n' + prefix + all
|
|
|
+ return ret
|
|
|
+ })
|
|
|
+ var outputText = output.substring(1)
|
|
|
+ //还原注释内容
|
|
|
+ outputText = outputText.replace(/\n/g, '\r').replace(/(\s*)<!--(.+?)-->/g, function ($0, prefix, text) {
|
|
|
+ if (prefix.charAt(0) == '\r') prefix = prefix.substring(1)
|
|
|
+ text = unescape(text).replace(/\r/g, '\n')
|
|
|
+ var ret = '\n' + prefix + '<!--' + text.replace(/^\s*/gm, prefix) + '-->'
|
|
|
+ return ret
|
|
|
+ })
|
|
|
+ outputText = outputText.replace(/\s+$/g, '').replace(/\r/g, '\r\n')
|
|
|
+ return outputText
|
|
|
+ }
|
|
|
+
|
|
|
+ //计算头函数 用来缩进
|
|
|
+ const setPrefix = (prefixIndex) => {
|
|
|
+ var result = ''
|
|
|
+ var span = ' ' //缩进长度
|
|
|
+ var output = []
|
|
|
+ for (var i = 0; i < prefixIndex; ++i) {
|
|
|
+ output.push(span)
|
|
|
+ }
|
|
|
+ result = output.join('')
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ const executeFormat = () => {
|
|
|
+ if (!originContent.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (type.value === 'JSON') {
|
|
|
+ formattedResult.value = JSON.stringify(JSON.parse(originContent.value), null, 2)
|
|
|
+ trueJson.value = true
|
|
|
+ } else {
|
|
|
+ if (originContent.value.indexOf('<') === -1 || originContent.value.indexOf('</') === -1 || originContent.value.indexOf('>') === -1) {
|
|
|
+ formattedResult.value = '不正确的XML文本'
|
|
|
+ trueJson.value = false
|
|
|
+ } else {
|
|
|
+ formattedResult.value = formatXml()
|
|
|
+ trueJson.value = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ formattedResult.value = error
|
|
|
+ trueJson.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ type,
|
|
|
+ preStyle,
|
|
|
+ placeholder,
|
|
|
+ clearWhenChangeType,
|
|
|
+ originContent,
|
|
|
+ formattedResult,
|
|
|
+ resultBackGround,
|
|
|
+ onTypeChange,
|
|
|
+ executeFormat,
|
|
|
+ }
|
|
|
+ },
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+pre {
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-wrap: break-word;
|
|
|
+}
|
|
|
+.formatted-body {
|
|
|
+ background: #60a6ec8a;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+.formatted-result {
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+</style>
|