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

Vue3循环渲染时v-html内@click、router-link无法正常渲染如何解决

问题本质

v-html 仅会将传入的字符串作为原生HTML插入DOM,全程不会触发Vue的模板编译流程,因此字符串内的事件指令、自定义组件、响应式绑定都会被当作普通原生内容处理,自然无法生效。这是Vue出于XSS安全防护做的默认设计,不是功能bug。

可行实现方案

根据场景可以二选一:

方案1:运行时编译字符串模板(最贴合现有代码逻辑)

Vue本身提供了运行时编译API,可以直接把字符串模板编译为可渲染的Vue组件,不需要硬编码每个列表项,改动成本最低。

  1. 首先调整构建配置,让项目引入带运行时编译器的Vue版本:
    如果是Vite构建的项目,在vite.config.js中添加别名配置即可:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      vue: 'vue/dist/vue.esm-bundler.js'
    }
  }
})
  1. 改造业务代码,用compile方法把字符串模板编译为渲染函数,通过动态组件渲染:
<template>
  {{ click }}
  <ol>
    <li v-for="(itemComp, idx) in compiledList" :key="idx">
      <component :is="itemComp" />
    </li>
  </ol>
</template>

<script setup>
import { ref, compile } from 'vue'
import { RouterLink } from 'vue-router'

const click = ref(0)
// 把模板中用到的响应式变量、组件统一放到作用域对象中
const renderScope = {
  click,
  RouterLink
}

const rawItems = [
  '<p>text</p><a @click="click+=1">click</a>',
  '<p>text2</p><p><router-link :to="{name: \'home\'}">home</router-link></p>'
]

// 批量将字符串模板编译为可渲染的组件配置
const compiledList = rawItems.map(tplStr => {
  // 包一层根节点避免多根节点编译报错
  const render = compile(`<div>${tplStr}</div>`)
  return {
    render,
    data() {
      return renderScope
    },
    components: { RouterLink }
  }
})
</script>

注意:这个方案存在XSS风险,必须保证传入的字符串模板是可控的可信内容,绝对不能直接将用户提交的未过滤内容传入编译。

方案2:结构化配置渲染(无编译开销、更安全)

如果不想引入运行时编译器(会增加约10-15KB的包体积),可以放弃存纯HTML字符串的思路,改为存结构化的渲染配置,在模板中根据配置动态渲染对应内容,性能和安全性都更好,适合长期维护的项目:

<template>
  {{ click }}
  <ol>
    <li v-for="(item, idx) in items" :key="idx">
      <p>{{ item.text }}</p>
      <a v-if="item.clickAction" @click="item.clickAction">{{ item.clickText }}</a>
      <p v-if="item.route">
        <RouterLink :to="{ name: item.routeName }">{{ item.routeText }}</RouterLink>
      </p>
    </li>
  </ol>
</template>

<script setup>
import { ref } from 'vue'
const click = ref(0)
// 结构化配置,不用写HTML字符串
const items = [
  {
    text: 'text',
    clickAction: () => click.value += 1,
    clickText: 'click'
  },
  {
    text: 'text2',
    routeName: 'home',
    routeText: 'home'
  }
]
</script>

这个方案的缺点是如果模板结构非常灵活多变,需要提前约定好配置结构,灵活度比直接编译字符串稍差。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:27:14