通过pre标签进行json格式化展示,并实现搜索高亮和通过鼠标进行逐个定位的功能

本文介绍了如何使用Vue.js和Element-Plus构建一个功能,实现在JSON内容中搜索关键词并高亮显示,同时处理输入框监听、编辑提示和确认退出。开发者详细展示了HTML结构、JavaScript方法以及相关组件的运用。
摘要由CSDN通过智能技术生成

功能说明

  1. 实现一个对json进行格式化的功能
  2. 添加搜索框,回车进行关键词搜索,并对关键词高亮显示
  3. 搜索到的多个关键词,回车逐一匹配
  4. 监听json框,如果发生了编辑,需要在退出时提示,在得到用户确认的情况下再退出

效果展示

在这里插入图片描述

说明:如上图中,输入“编程”两个字,每回车一下,就定位到匹配到的第二个位置,并将当前匹配到的文字滚动到顶部。

实现步骤

第一步:编写HTML

分别添加一个输入框、一个用于展示json的pre标签、和一个取消按钮

说明:此处的其它功能有省略

<template>
    <div>
        <el-input class="input" v-model="searchValue" @keyup.enter.native="handleEnter" placeholder="输入关键词回车搜索"></el-input>
        
        <pre class="content" id="json-pre" contenteditable="true" v-html="preJsonHtml"></pre>

        <el-button @click="handleCancle">取消</el-button>
    </div>
</template>

第二步:实现JavaScript方法

2.1 定义必要的变量和进行变量监听

<script lang="ts" setup>
import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessageBox } from 'element-plus';

const route = useRoute()
const router = useRouter()

// 存放获取到的json文件的内容
let jsonData = ref()

// 搜索框内容
let searchValue = ref()

// 用于在pre标签里展示的HTML
let preJsonHtml = ref()

// 表示json是否被修改
let isPreEdit = ref(false)

// 当前搜索匹配到第几个
let matchNum = ref(0)

// 拼接一个获取json文件的地址
const jsonUrl = computed(() => {

    // 这是亚马逊上面部署的一个pdfjs服务,及存放json文件的文件夹拼接地址
    const aws_server = 'http://xxx.s3-website-xxx.amazonaws.com/pdfjs-4.0.379-dist/web/docs/'

    // 从路由中获取到文件名称
    const json_name = route.query.json as string

    // 拼接得到最终的文件地址
    return `${aws_server}${json_name}`
})

// 监听jsonData,修改后需要动态更新文本框里显示的内容
watch(() => jsonData.value, val => {
    preJsonHtml.value = JSON.parse(JSON.stringify(val, null, 4))
})

// 监听搜索框的内容,主要目的是:当搜索框中的内容变化了,需要将matchNum重置为0,开始新输入内容的第一个搜索
watch(() => searchValue.value, val => {
    matchNum.value = 0
})

onMounted(() => {

    // 这里注意,需要使用nexttick,在页面渲染出来以后再做计算
    nextTick(() => {

        // json-pre
        var preTag = document.getElementById('json-pre');
        var originalContent = preTag?.textContent;

        // 添加监听事件
        preTag?.addEventListener('input', function() {

            if (preTag?.textContent !== originalContent) {

                console.log('内容已被修改');

                isPreEdit.value = true // 标记json被修改了
            }
        });
    })

    // 获取json文件,并赋值给jsonData
    fetch(jsonUrl.value).then(res => res.json()).then(r => {
        jsonData.value = JSON.stringify(r, null, 4)
    })
})
</script>

2.2 输入框回车事件

// 输入框回车事件
// 之所以使用这个方法,是因为input输入框在输入一个文字后,需要多次联系重复搜索
const handleEnter = (event) => {

    // 判断下jsonData的类型,需要一个字符串格式
    let result = typeof jsonData.value !== 'string' && JSON.stringify(jsonData.value) || jsonData.value

    // 正则表达式,对输入框中的内容全匹配
    const Reg = new RegExp(searchValue.value, 'g')

    // 获取这种全匹配下,有多少个匹配结果
    // 这一步非常重要,因为需要多次进行搜索和修改样式,所以必须要记录匹配结果
    let matchs = result.match(Reg)

    // 判断:
    // 匹配到结果 且 当前搜索到匹配结果的最后一位时,重新开始搜索第一个
    if((matchs && matchs.length) && matchNum.value + 1 >= matchs.length) {
        matchNum.value = 0
    }
    // 否则,继续向下
    matchNum.value += 1

    // 如果匹配有结果
    if(result) {

        // 定义一个替换方案
        // 将匹配结果替换为一个span标签,id为highLight,颜色为黄色
        let replacement = `<span id="highlight" style="background: yellow;">${searchValue.value}</span>`

        // 调用字符串匹配方法:在后文中有写
        const res = replaceNumMatch(Reg, result, replacement, matchNum.value);

        // preJsonHtml赋值,将它包裹在了一个div中
        preJsonHtml.value = `<div>${JSON.parse(JSON.stringify(res, null, 4))}</div>`

        /**
         * 这里是实现dom结构的滚动
         */
        const div = document.getElementById('json-pre');
        const span = document.getElementById('highlight');

        if (div && span) {
            // 计算滚动位置
            const scrollTo = span.offsetTop - div.offsetTop - 10; // 这里多了一个10px的间距
            
            // 滚动到指定位置

            // 当搜索第一个时,滚动到顶部
            if(matchNum.value === 1) {
                div.scrollTop = 0
                return
            }
            // 其它滚动到指定为止
            div.scrollTop = scrollTo;
        }
    }
}

2.3 正则表达式进行字符串匹配和替换方法

/**
 * 使用正则表达式进行字符串替换的方法
 */
function replaceNumMatch(regexp, str, replacement, i) {

    let count = 0;

    return str.replace(regexp, function(matched) {
        count++;
        if (count === i) {
            return replacement; // 替换第i个匹配字符为指定的字符串
        } else {
            return matched; // 保持其他匹配字符不变
        }
    });
}

2.4 json对话框编辑取消方法

/**
 * 取消方法:
 * 这里的要求是,当json被修改后退出需要提醒
 * 所以这里增加了一个isPreEdit的变量,标记json是否被修改
 */
const handleCancle = () => {

    if(isPreEdit.value) {
        // 如果被修改增加提醒
        ElMessageBox.confirm('内容有修改,是否进行保存?', '提示',
            {
                confirmButtonText: '是',
                cancelButtonText: '否',
                type: 'warning',
                closeOnClickModal: false,
                showClose: false
            }).then(() => {

                // do something 

                // 如可以保存数据等

            }).catch(() => {
                // 否则 跳转到指定路由
                router.push({ path: '/xxx' })
            })
        return
    }

    // 如果没有被修改,则跳转到指定路由
    router.push({ path: '/xxx' })
}

第三步:样式

pre在文字过长时,不换行。此处的目的是为了让长段的pre换行

<style lang="scss" scoped>

// 让pre里的文字自动换行
pre {
    white-space: pre-wrap;
    white-space: -moz-pre-wrap;
    white-space: -pre-wrap;
    white-space: -o-pre-wrap;
    word-wrap: break-word;
}
</style>
为了提取PDF和OFD格式的发票内容,我们可以使用第三方库PyMuPDF和ofdreader。在此之前,需要安装这些库。可以使用以下命令进行安装: ``` pip install PyMuPDF ofdreader ``` 以下是提取PDF和OFD格式发票内容并JSON格式化输出的代码: ```python import fitz from ofdreader import OFD def extract_pdf_invoice(pdf_file): doc = fitz.open(pdf_file) page = doc.loadPage(0) text = page.getText() invoice_data = {} for line in text.split('\n'): if '发票代码' in line: invoice_data['invoice_code'] = line.split(':')[1].strip() elif '发票号码' in line: invoice_data['invoice_number'] = line.split(':')[1].strip() elif '开票日期' in line: invoice_data['invoice_date'] = line.split(':')[1].strip() elif '购买方名称' in line: invoice_data['buyer_name'] = line.split(':')[1].strip() elif '税前金额' in line: invoice_data['pre_tax_amount'] = line.split(':')[1].strip() elif '税额' in line: invoice_data['tax_amount'] = line.split(':')[1].strip() elif '价税合计' in line: invoice_data['total_amount'] = line.split(':')[1].strip() return invoice_data def extract_ofd_invoice(ofd_file): ofd = OFD(ofd_file) invoice_data = {} for page in ofd.pages: text = page.extract_text().replace('\n', '') if '发票代码' in text: invoice_data['invoice_code'] = text.split('发票代码')[1].split('发票号码')[0].strip() if '发票号码' in text: invoice_data['invoice_number'] = text.split('发票号码')[1].split('开票日期')[0].strip() if '开票日期' in text: invoice_data['invoice_date'] = text.split('开票日期')[1].split('购买方名称')[0].strip() if '购买方名称' in text: invoice_data['buyer_name'] = text.split('购买方名称')[1].split('价税合计')[0].strip() if '税前金额' in text: invoice_data['pre_tax_amount'] = text.split('税前金额')[1].split('税额')[0].strip() if '税额' in text: invoice_data['tax_amount'] = text.split('税额')[1].split('价税合计')[0].strip() if '价税合计' in text: invoice_data['total_amount'] = text.split('价税合计')[1].strip() return invoice_data pdf_invoice = extract_pdf_invoice('invoice.pdf') ofd_invoice = extract_ofd_invoice('invoice.ofd') print(json.dumps(pdf_invoice, indent=4)) print(json.dumps(ofd_invoice, indent=4)) ``` 在上面的代码中,我们定义了两个函数`extract_pdf_invoice()`和`extract_ofd_invoice()`,分别用于提取PDF和OFD格式的发票内容。这些函数将返回一个包含发票信息的字典对象。最后,我们使用`json.dumps()`函数将这些字典对象转换为JSON格式,并使用`print()`函数打印输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值