You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue中实现带特殊样式文本循环展示,是否有优于v-html的方案?

更优实现方案:替代v-html处理带样式的文本展示

你当前用v-html的方式虽然能实现需求,但存在两个明显问题:一是HTML字符串硬编码维护性差,二是有XSS注入风险(如果数据来自用户输入或第三方)。这里给你几个更优的实现方案:

方案1:用结构化数据替代HTML字符串(最推荐)

把需要高亮的内容从HTML字符串拆成结构化数据,比如每个条目包含原始文本和需要高亮的关键词,既安全又便于维护,还能直接配合Vue的响应式特性。

<script setup>
import { ref } from "vue";

// 结构化数据:存储原始文本+需要高亮的关键词
const data3 = [
  {
    text: "An approachable, performant and versatile framework for building web user interfaces.",
    highlight: ["performant"]
  },
  {
    text: "The library for web and native user interfaces",
    highlight: ["native"]
  }
];

// 拆分文本为普通/高亮片段的工具函数
const splitText = (text, highlights) => {
  if (!highlights.length) return [{ text, highlight: false }];
  const regex = new RegExp(`(${highlights.join('|')})`, 'gi');
  return text.split(regex)
    .map(part => ({
      text: part,
      highlight: highlights.some(word => part.toLowerCase() === word.toLowerCase())
    }))
    .filter(part => part.text); // 过滤拆分产生的空字符串
};
</script>

<template>
  <div class="data3">
    <p v-for="(item, index) in data3" :key="index">
      <template v-for="(segment, idx) in splitText(item.text, item.highlight)" :key="idx">
        <span v-if="segment.highlight" class="highlight">{{ segment.text }}</span>
        <span v-else>{{ segment.text }}</span>
      </template>
    </p>
  </div>
</template>

<style scoped>
.highlight {
  font-weight: 700;
}
</style>

方案2:安全处理HTML字符串(适配已有HTML数据场景)

如果数据确实是HTML格式(比如来自后端接口),不要直接用v-html,先通过DOMPurify过滤掉危险标签和属性,彻底规避XSS风险。

  1. 先安装依赖:
npm install dompurify
  1. 组件中使用:
<script setup>
import { ref, computed } from "vue";
import DOMPurify from 'dompurify';

const data2 = [
  "An approachable, <b>performant</b> and versatile framework for building web user interfaces.",
  "The library for web and <b>native</b> user interfaces",
];

// 计算属性返回过滤后的安全HTML
const safeData2 = computed(() => data2.map(item => DOMPurify.sanitize(item)));
</script>

<template>
  <div class="data2">
    <p v-for="(item, index) in safeData2" :key="index" v-html="item"></p>
  </div>
</template>

<style scoped>
:deep(.data2 > b) {
  font-weight: 700;
}
</style>

方案3:封装高亮组件(适配多场景复用)

如果多个页面需要类似的高亮文本展示,可以封装独立组件,提高代码复用性:

<!-- HighlightText.vue -->
<script setup>
import { computed } from "vue";

const props = defineProps({
  text: String,
  highlights: {
    type: Array,
    default: () => []
  }
});

const segments = computed(() => {
  if (!props.highlights.length) return [{ text: props.text, highlight: false }];
  const regex = new RegExp(`(${props.highlights.join('|')})`, 'gi');
  return props.text.split(regex)
    .map(part => ({
      text: part,
      highlight: props.highlights.some(word => part.toLowerCase() === word.toLowerCase())
    }))
    .filter(part => part.text);
});
</script>

<template>
  <span>
    <template v-for="(seg, idx) in segments" :key="idx">
      <span v-if="seg.highlight" class="highlight">{{ seg.text }}</span>
      <span v-else>{{ seg.text }}</span>
    </template>
  </span>
</template>

<style scoped>
.highlight {
  font-weight: 700;
}
</style>

父组件中调用:

<script setup>
import { ref } from "vue";
import HighlightText from './HighlightText.vue';

const data3 = [
  {
    text: "An approachable, performant and versatile framework for building web user interfaces.",
    highlight: ["performant"]
  },
  {
    text: "The library for web and native user interfaces",
    highlight: ["native"]
  }
];
</script>

<template>
  <div class="data3">
    <p v-for="(item, index) in data3" :key="index">
      <HighlightText :text="item.text" :highlights="item.highlight" />
    </p>
  </div>
</template>

方案对比

方案类型优点适用场景
结构化数据方案无XSS风险、易维护、样式无需穿透scoped新开发项目,可控数据结构
安全HTML方案适配已有HTML数据、降低XSS风险数据来自后端且为HTML格式
组件化方案高复用性、代码整洁多页面需要同类高亮展示场景
原v-html方案实现简单静态本地数据、无安全风险场景

内容的提问来源于stack exchange,提问作者JackFan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:43:08