html代码,无法替换,《\n》,字符串,解决方法:test.replace(/\\n/g, “<br/>“)

本文介绍了在HTML代码中遇到换行符( )无法替换的问题,提供了使用JavaScript的replace()函数配合正则表达式(/ /g)将其替换为HTML`<br>`标签的解决方案。
部署运行你感兴趣的模型镜像

html代码,无法替换,《\n》,字符串,解决方法:test.replace(/\\n/g, "<br/>")

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<template> <div class="math-content" ref="container" v-html="processedContent"></div> <!-- <div v-if="fileUrls && fileUrls.length"> <div v-for="(val,index) in fileUrls" :key="index" class="flex-center-warp" @click="openUrl(val)"> <img src="../../../assets/item/ppt.png" alt="" style="width: 20px; height: 20px;margin-right:10px;" />{{getFileName(val)}} </div> </div> --> <div class="flex"> <Popover> <div @click="handleCopy" class="copys" v-if="is_loadin"> <img src="../../../assets/item/copy.png" alt="" style="width: 20px; height: 20px" /> </div> <template #content> <div> 复制 </div> </template> </Popover> <Popover> <div @click="handleDownloadFile()" class="download" v-if="is_loadin"> <img src="../../../assets/item/download.png" alt="" style="width: 20px; height: 20px" />下载Word </div> <template #content> <div> 下载Word</div> </template> </Popover> <Popover> <div @click="DownloadPPT" class="download" v-if="is_loadin"> <img src="../../../assets/item/download.png" alt="" style="width: 20px; height: 20px" />生成PPT </div> <template #content> <div> 生成PPT </div> </template> </Popover> <Modal v-model:visible="visible" title="修改信息" width='1200px'> <iframe :src='getUrlParams()' width="100%" height="800px" v-if="visible" frameborder="0" seamless name="iframe" id="iframe" ></iframe> <!-- <div class="item-radio"> <div>模版场景 : </div> <Radio.Group v-model:value="scene"> <Radio.Button :key="val.id" :value="val.id" v-for="(val) in sceneList" @click="getListTemplayBox">{{val.name}}</Radio.Button> </Radio.Group> </div> <div class="item-radio"> <div>模版风格 : </div> <Radio.Group v-model:value="style"> <Radio.Button :key="val.id" :value="val.id" v-for="(val) in styleList" @click="getListTemplayBox">{{val.name}}</Radio.Button> </Radio.Group> </div> <div class="flex"> <div class="ptt-left flex"> <div class="ptt-item" v-for="(val) in pptList" :key="val.id" @click="handleActive(val)" > <img :src="val.urlList[0]" alt="" :class="['img',{ 'is_active': activeId === val.id }]"> </div> </div> <div class="ptt-right" v-if="urlList.length"> <div class="urlList"> <img :src="urlList[0]" alt="" class="imgs"> </div> <div class="flex" style="justify-content: space-between;"> <div> <img :src="urlList[1]" alt="" class="imgsBox"> </div> <div> <img :src="urlList[2]" alt="" class="imgsBox"> </div> <div> <img :src="urlList[3]" alt="" class="imgsBox"> </div> </div> </div> </div> --> <template #footer> <Button @click="cancel">取消</Button> <!-- <Button type="primary" @click="handleImportJson" :disabled='activeId ? false : true' :loading='loading'>{{ loading ? '生成模板中':'生成模板'}}</Button> --> </template> </Modal> </div> </template> <script setup> import { ref, watch, onMounted, nextTick,defineAsyncComponent } from 'vue'; import DOMPurify from 'dompurify'; import katex from 'katex'; import 'katex/dist/katex.css'; import { copyText } from '@/utils/copyTextToClipboard'; import { downloadFile, pptTemplateScenes, pptTemplateStyes, pptTemplates, getListTemplay } from '../../../api/auth/captcha'; import { Base64 } from 'js-base64'; import { Modal, Switch, Input, Button, Popover, Radio, Form, LayoutSider, Layout, LayoutContent, Menu, MenuItem, SubMenu, Tooltip, Collapse, CollapsePanel, Drawer, Upload, message, // Icon, } from 'ant-design-vue'; // 定义接收的 props const props = defineProps({ content: { type: String, default: '', }, is_loadin: { type: Boolean, default: false, }, modelMessageId:{ type: String, default: '', }, fileUrls: { type: Array, default: [], }, }); const scene = ref(null) const sceneList = ref([]) const style = ref(null) const styleList = ref([]) const pptList = ref([]) const urlList = ref([]) const visible = ref(false) const activeId = ref(null) const loading = ref(false) // const url = ref(`http://ppt.bsyxedu.com?userId=${props.modelMessageId}&test=${props.content.replace(htmlTagRegex, '')}`) const DownloadPPT = () =>{ pptTemplateScenes().then(res=>{ sceneList.value = res.response scene.value = res.response[0].id pptTemplateStyes().then(res=>{ styleList.value = res.response style.value = res.response[0].id getListTemplayBox() }) }) visible.value = true } const getFileName =(url)=> { // 按斜杠分割URL,过滤空字符串(处理可能的多个连续斜杠) const parts = url.split('/').filter(part => part !== ''); // 取最后一个元素(文件名),若数组为空则返回空字符串 return parts.length > 0 ? parts[parts.length - 1] : ''; } const getUrlParams = () => { let htmlTagRegex = /<\/?[a-zA-Z][^>]*>/g; const test = props.content.replace(htmlTagRegex, '') let test1 = test.replace(/"/g, '') console.log(test1,'test'); return `http://ppt.bsyxedu.com?userId=${props.modelMessageId}&test=${test1}` // return `http://localhost:5173/?userId=${props.modelMessageId}&test=${test1}` } const handleImportJson =()=>{ let htmlTagRegex = /<\/?[a-zA-Z][^>]*>/g; const test = props.content.replace(htmlTagRegex, '') let test1 = test.replace(/"/g, '') console.log(test1,'test'); window.open(`http://localhost:5173/?userId=${props.modelMessageId}&test=${test1}`) return let parem = { // sceneId:scene.value, // styleId:style.value modelMessageId:props.modelMessageId, pptId: activeId.value } loading.value = true getListTemplay(parem).then(res=>{ loading.value = false if(res.response && res.response.length){ window.open(res.response) props.fileUrls.push(res.response) }else{ message.error('生成出错请重试'); } }).catch(()=>{ loading.value = false }) } const cancel = ()=>{ visible.value = false activeId.value =null } const handleActive =(item)=>{ console.log(item,'item'); urlList.value = item.urlList activeId.value = item.id } const getListTemplayBox =() =>{ activeId.value = null urlList.value = [] let parem = { sceneId:scene.value, styleId:style.value } pptTemplates(scene.value,style.value).then(res=>{ pptList.value = res.response urlList.value = res.response[0].urlList activeId.value = res.response[0].id console.log(res,'res'); }) } const openUrl = (src)=>{ window.open(`http://edu-ftp-web.eduzhida.com/onlinePreview?url=${Base64.encode(src)}`) } const handleDownloadFile= () =>{ downloadFile(props.modelMessageId).then(res=>{ // props.fileUrls.push(res.response) window.open(res.response) }) } const handleCopy = () => { let htmlTagRegex = /<\/?[a-zA-Z][^>]*>/g; let cleanedText = props.content.replace(htmlTagRegex, ''); cleanedText = cleanedText.replace(/"/g, '"').replace(/&/g, '&'); // 转换其他可能实体 console.log(cleanedText, 'processedContent'); copyText(cleanedText, '复制成功'); }; // 用于存储处理后的内容 const processedContent = ref(''); // 引用 DOM 元素 const container = ref(null); // Katex 配置 const katexConfig = { macros: { '\\text': '#1', // 支持中文 '\\dfrac': '\\frac{#1}{#2}', // 自定义分数显示 }, throwOnError: false, strict: false, }; // 转义正则表达式中的特殊字符 const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // 存储每个公式的 displayMode 信息 const formulaDisplayModes = []; // 将所有定界符转换为 $ 符号,并记录 displayMode const convertToDollar = (str) => { const delimiters = [ { left: '$$', right: '$$', display: false }, { left: '$', right: '$', display: false }, { left: '( ', right: ' )', display: true }, { left: '\\[', right: '\\]', display: true }, { left: '[', right: ']', display: true }, { left: '\\(', right: '\\)', display: false }, { left: '\\begin{align*}', right: '\\end{align*}', display: true }, ]; delimiters.forEach(({ left, right, display }) => { const pattern = new RegExp(`${escapeRegExp(left)}([\\s\\S]*?)${escapeRegExp(right)}`, 'g'); str = str.replace(pattern, (match, formula) => { formulaDisplayModes.push(display); return `$${formula}$`; }); }); return str; }; // 渲染数学公式 const renderMath = async () => { try { // 对内容进行安全过滤 let cleanHtml = DOMPurify.sanitize(props.content, { ALLOWED_TAGS: ['div', 'p', 'span', 'br', 'ol', 'ul', 'li', 'strong', 'em', 'a', 'pre', 'style'], ALLOWED_ATTR: ['class', 'style', 'href', 'target', 'rel', 'border', 'border-radius', 'background', 'position', 'inset', 'padding', 'margin', 'z-index'], ADD_ATTR: ['target', 'rel'], ADD_DATA_URI_TAGS: ['img'] }); // 处理 a 标签,确保安全 cleanHtml = cleanHtml.replace(/<a\s+([^>]*)>/gi, (match, attributes) => { const hrefAttr = (attributes.match(/href\s*=\s*["']([^"']*)["']/i) || [])[1]; if (hrefAttr) { return `<a ${attributes} target="_blank" rel="noopener noreferrer">`; } return match; }); cleanHtml = cleanHtml.replace(/```html([\s\S]*?)```/g, (match, codeContent) => { return `<div class="code-block-wrapper"> <pre class="code-block">${codeContent.trim()}</pre> </div>`; }); // 清空之前的 displayMode 记录 formulaDisplayModes.length = 0; // 将所有定界符转换为 $ 符号,并记录 displayMode cleanHtml = convertToDollar(cleanHtml); // 将清理后的 HTML 设置到容器中 if (container.value) { container.value.innerHTML = cleanHtml; } let formulaIndex = 0; // 只处理 $ 符号定界的公式 const pattern = /\$([\s\S]*?)\$/g; if (container.value) { container.value.innerHTML = container.value.innerHTML.replace(pattern, (_, formula) => { const displayMode = formulaDisplayModes[formulaIndex++] || false; try { return katex.renderToString(formula, { displayMode, throwOnError: true, ...katexConfig, }); } catch (e) { console.error('公式渲染错误:', formula, e); return `<span class="math-error">$${formula}$</span>`; } }); } // 更新处理后的内容 processedContent.value = container.value ? container.value.innerHTML : ''; } catch (error) { console.error('公式渲染失败:', error); } }; // 组件挂载后渲染公式 onMounted(async () => { await nextTick(); renderMath(); }); // 监听 content 属性变化,重新渲染公式 watch(() => props.content, renderMath); </script> <style scoped lang="scss"> /* 修改为深度选择器 */ :deep(pre) { border-radius: 8px; padding: 10px; background: #F9FAFB; margin: 10px 0; white-space: pre-wrap; overflow-x: auto; } .flex-center-warp{ display: flex; margin-right: 20px; align-items: center; cursor: pointer; margin-bottom:10px; color: #343a40; } .flex-center-warp:hover{ color: #000 !important; } .ptt-right{ width: 60%; margin-top: 20px; margin-left: 20px; } .ptt-left{ width: 40%; display: flex; flex-wrap: wrap; max-height: 530px; overflow-y: auto; margin-top: 20px; } .ptt-item{ width: 46%; margin-right: 2%; cursor: pointer; border: 2px solid #fff; margin-bottom: 20px; height: 150px; } .is_active{ border: 2px solid #80318c !important; } .img{ width: 100%; height:150px; border-radius: 10px; } .imgs{ width: 100%; height: 400px; border-radius: 4px; cursor: pointer; } .imgsBox{ height: 150px; width: 200px; border-radius: 4px; margin-top: 10px; cursor: pointer; } .item-radio{ display: flex; align-items: center; margin-top: 20px; } .ant-radio-button-wrapper{ margin-left: 10px; /* border-radius: 10px !important; */ } .math-content { line-height: 1.8; font-size: 16px; } .download { width: 100px; height: 30px; cursor: pointer; padding: 5px; display: flex; align-items: center; justify-content: center; color: #343a40; font-size: 13px; } .download:hover { background: #f1f1f1; border-radius: 10px; } .katex { font-size: 1.1em; margin: 0.5em 0; } .copys { width: 30px; height: 30px; cursor: pointer; padding: 5px; display: flex; align-items: center; justify-content: center; } .copys:hover { background: #f1f1f1; border-radius: 10px; } .math-error { background-color: #fff0f0; color: #cc0000; padding: 2px 4px; border: 1px solid #ffcccc; border-radius: 3px; } a:not([href]) { cursor: text; /* 无链接时禁用指针 */ } /* 自动识别可跳转链接 */ a[data-auto-link] { color: #1677ff; text-decoration: none; position: relative; padding-right: 1.2em; } /* 添加外部链接标识 */ a[data-auto-link]::after { content: '↗'; font-size: 0.8em; margin-left: 4px; opacity: 0.6; position: absolute; right: 0; } /* 悬停效果 */ a[data-auto-link]:hover { text-decoration: underline; color: #0958d9; } /* 天气提示样式 */ .weather-tip { color: #d4380d; border-left: 3px solid #ffa940; padding-left: 8px; margin: 12px 0; } /* 列表样式增强 */ ol { counter-reset: list-counter; padding-left: 1.5em; } ol li { counter-increment: list-counter; margin: 8px 0; } ol li::marker { color: #666; font-weight: 500; } .markdown-content { white-space: pre-line; line-height: 1.6; } </style> 怎么给我优化下 代码块识别还有问题
最新发布
10-28
<!-- src/views/incorruptible/case/caseForm.vue --> <template> <div class="app-container"> <!-- 页面标题 --> <div class="page-title">{{ title }}</div> <el-form ref="form" :model="form" :rules="rules" label-width="80px" class="form-container" > <el-form-item label="案列标题" prop="title"> <el-input v-model="form.title" placeholder="请输入案列标题" /> </el-form-item> <el-form-item label="发布日期" prop="publishDate"> <el-date-picker clearable v-model="form.publishDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择发布日期" popper-append-to-body="false" class="date-picker-zindex" /> </el-form-item> <el-form-item label="案例内容"> <!-- Quill富文本编辑器 --> <div class="quill-editor-container"> <quill-editor ref="quillEditor" v-model="form.content" :options="editorOptions" @ready="onEditorReady" /> </div> </el-form-item> <el-form-item label="状态" prop="status"> <el-radio-group v-model="form.status"> <el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value" >{{dict.label}}</el-radio> </el-radio-group> </el-form-item> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">确 定</el-button> <el-button @click="cancel">取 消</el-button> </div> </el-form> </div> </template> <script> import { getCase, addCase, updateCase } from "@/api/incorruptible/case"; import { quillEditor } from 'vue-quill-editor'; import 'quill/dist/quill.core.css'; import 'quill/dist/quill.snow.css'; import 'quill/dist/quill.bubble.css'; import { getToken } from '@/utils/auth'; import axios from 'axios'; export default { name: "CaseForm", components: { quillEditor }, dicts: ['sys_normal_disable'], data() { return { articleId: null, // 改为在data中存储 title: "", form: { title: null, publishDate: null, content: null, status: null }, // Quill编辑器配置 editorOptions: { placeholder: '请输入内容', theme: 'snow', modules: { toolbar: { container: [ ['bold', 'italic', 'underline', 'strike'], ['blockquote', 'code-block'], [{ 'header': 1 }, { 'header': 2 }], [{ 'list': 'ordered'}, { 'list': 'bullet' }], [{ 'script': 'sub'}, { 'script': 'super' }], [{ 'indent': '-1'}, { 'indent': '+1' }], [{ 'direction': 'rtl' }], [{ 'size': ['small', false, 'large', 'huge'] }], [{ 'header': [1, 2, 3, 4, 5, 6, false] }], [{ 'color': [] }, { 'background': [] }], [{ 'font': [] }], [{ 'align': [] }], ['clean'], ['link', 'image'] ], handlers: { 'image': this.handleImageButtonClick }, // 添加键盘模块处理 Tab 键 keyboard: { bindings: { tab: { key: 'Tab', handler: function(range, context) { // 插入制表符(4个空格) this.quill.insertText(range.index, ' '); // 移动光标到插入位置之后 this.quill.setSelection(range.index + 4); return false; // 阻止默认行为 } } } } }, } }, quillInstance: null, // 表单校验规则 rules: { title: [{ required: true, message: '案列标题不能为空', trigger: 'blur' }], publishDate: [{ required: true, message: '发布日期不能为空', trigger: 'change' }], status: [{ required: true, message: '状态不能为空', trigger: 'change' }] } }; }, created() { // 从路由参数获取articleId this.articleId = this.$route.params.articleId; // 根据是否有ID确定是新增还是修改 this.title = this.articleId ? "修改廉洁标准案例" : "添加廉洁标准案例"; // 如果是修改,加载案例数据 if (this.articleId) { this.loadCaseData(); } }, methods: { // 加载案例数据 async loadCaseData() { try { const response = await getCase(this.articleId); this.form = response.data; // 反转义富文本内容 this.form.content = this.unescapeHtmlFromJson(this.form.content); } catch (error) { console.error('加载案例数据失败:', error); this.$modal.msgError('加载案例数据失败'); } }, // 编辑器准备就绪 onEditorReady(editor) { this.quillInstance = editor; }, // 图片按钮点击事件处理 handleImageButtonClick() { if (!this.quillInstance) return; const input = document.createElement('input'); input.setAttribute('type', 'file'); input.setAttribute('accept', 'image/*'); input.style.display = 'none'; document.body.appendChild(input); input.click(); input.onchange = () => { if (!input.files || !input.files[0]) return; const file = input.files[0]; if (file.size > 5 * 1024 * 1024) { this.$modal.msgError('图片大小不能超过5MB'); return; } this.uploadImage(file) .then(imageUrl => { const range = this.quillInstance.getSelection(); if (range) { this.quillInstance.insertEmbed(range.index, 'image', imageUrl); this.quillInstance.setSelection(range.index + 1); } }) .catch(error => { console.error('图片上传失败:', error); this.$modal.msgError('图片上传失败'); }) .finally(() => { document.body.removeChild(input); }); }; }, // 图片上传方法 uploadImage(file) { return new Promise((resolve, reject) => { const formData = new FormData(); formData.append('file', file); const uploadUrl = process.env.VUE_APP_BASE_API + '/file/upload'; axios.post(uploadUrl, formData, { headers: { 'Authorization': 'Bearer ' + getToken(), 'Content-Type': 'multipart/form-data' } }).then(response => { const res = response.data; let imageUrl = ''; if (res.code === 200 && res.data) { if (typeof res.data === 'string') { imageUrl = res.data; } else if (res.data.url) { imageUrl = res.data.url; } else if (res.data.value) { imageUrl = String(res.data.value); } if (imageUrl) { if (!imageUrl.startsWith('http')) { imageUrl = process.env.VUE_APP_BASE_API + imageUrl; } resolve(imageUrl); } else { reject('无法解析图片URL'); } } else { reject(res.msg || '图片上传失败'); } }).catch(error => { console.error('图片上传失败:', error); reject('上传失败: ' + (error.message || '网络错误')); }); }); }, // 富文本内容JSON转义处理 escapeHtmlForJson(html) { if (!html) return ''; // 1. 处理制表符(Tab) let processedHtml = html.replace(/\t/g, '\\t'); // 2. 处理连续空格(保留连续空格) processedHtml = processedHtml.replace(/ {2,}/g, (match) => { return '\\u00a0'.repeat(match.length); }); // 3. 处理行首空格(缩进) processedHtml = processedHtml.replace(/^[ ]+/gm, (match) => { return '\\u00a0'.repeat(match.length); }); // 4. 转义其他JSON特殊字符 processedHtml = processedHtml .replace(/\\/g, '\\\\') // 转义反斜杠 .replace(/"/g, '\\"') // 转义双引号 .replace(/\//g, '\\/') // 转义斜杠 .replace(/\n/g, '\\n') // 转义换行符 .replace(/\r/g, '\\r') // 转义回车符 .replace(/\f/g, '\\f') // 转义换页符 .replace(/</g, '\\u003c') // 转义小于号 .replace(/>/g, '\\u003e'); // 转义大于号 return processedHtml; }, // JSON转义内容反转义处理 unescapeHtmlFromJson(escapedHtml) { if (!escapedHtml) return ''; // 1. 处理制表符 let result = escapedHtml.replace(/\\t/g, ' '); // 将 \t 转换为 4 个空格 // 2. 处理连续空格 result = result.replace(/\\u00a0/g, ' '); // 3. 处理其他转义字符 result = result .replace(/\\u003c/g, '<') // 转义小于号 .replace(/\\u003e/g, '>') // 转义大于号 .replace(/\\"/g, '"') // 转义双引号 .replace(/\\\//g, '/') // 转义斜杠 .replace(/\\\\/g, '\\') // 转义反斜杠 .replace(/\\n/g, '\n') // 转义换行符 .replace(/\\r/g, '\r') // 转义回车符 .replace(/\\f/g, '\f'); // 转义换页符 return result; }, // 提交表单 submitForm() { this.$refs.form.validate(valid => { if (valid) { // 检查富文本内容 if (!this.form.content || this.form.content === '<p><br></p>') { this.$modal.msgWarning('案例内容不能为空'); return; } // 准备数据 const formData = { ...this.form, content: this.escapeHtmlForJson(this.form.content) }; // 确定是新增还是修改 const action = this.articleId ? updateCase : addCase; action(formData) .then(() => { this.$modal.msgSuccess(this.articleId ? "修改成功" : "新增成功"); this.$router.back(); // 返回上一页 }) .catch(error => { console.error('操作失败:', error); this.$modal.msgError('操作失败'); }); } }); }, // 取消操作 cancel() { this.$router.back(); // 返回上一页 } } }; </script> <style scoped> .app-container { padding: 20px; background-color: #f9f9f9; min-height: 100vh; } .page-title { font-size: 24px; font-weight: bold; margin-bottom: 20px; color: #2c3e50; padding-bottom: 10px; border-bottom: 1px solid #eee; } .form-container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .quill-editor-container { border: 1px solid #DCDFE6; border-radius: 4px; overflow: hidden; background: #fff; margin-bottom: 20px; } .quill-editor-container:hover { border-color: #C0C4CC; } .ql-toolbar { border-bottom: 1px solid #DCDFE6 !important; } .ql-container { min-height: 300px; border: none !important; } .dialog-footer { text-align: center; margin-top: 20px; padding-top: 20px; border-top: 1px solid #eee; } .date-picker-zindex { z-index: 3000 !important; } </style> 转译空格和tab空格还是有问题,我在富文本里1的前面输入两个空格,在2的前面输入1个tab空格,刷新后富文本\ \ 1\ 2,1的前面有两个\,2的签名有1个\.
08-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qaakd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值