appmountids 必须与 html 中真实存在的唯一 id 严格对齐,并在 template 中动态生成对应容器;v-html 需配合 html 净化防 xss;custom elements 隔离依赖 closed shadow root;vue data 必为函数以确保实例状态独立。

html-webpack-template 的 appMountIds 怎么配才不踩坑
多挂载点配置不是加个数组就完事,appMountIds 必须和实际 DOM 初始化逻辑严格对齐,否则应用会挂载失败或相互覆盖。
-
appMountIds里每个 ID 都必须在最终 HTML 中真实存在,且不能重复 —— 否则document.getElementById()拿不到节点,Vue/React 实例初始化直接报Cannot mount to null - Webpack 构建时,
template文件(如index.ejs)必须包含动态生成容器的模板代码:<div id="<%= item %>"></div>,漏掉这一步,HTML 里根本没对应容器 - 如果多个应用共用同一份
index.ejs,但不同环境(dev/prod)需要不同挂载点,建议把appMountIds提到 webpack 配置变量中,避免硬编码导致构建产物错乱
v-html 在组件通信中为什么容易 XSS?
它不是“通信方案”,而是渲染手段;父组件传来的 htmlContent 若未经净化就直接用 v-html 渲染,等于把执行权交给了字符串内容。
- 只要字符串里含
<script>fetch('/api/token').then(...)</script>这类代码,就会在子组件作用域内执行 —— 和用户输入拼接进 innerHTML 是同等风险 - Vue 不会对
v-html做任何过滤,默认信任传入内容。若数据来自后端富文本接口,必须在服务端或中间层做 HTML sanitizer(如使用 DOMPurify 处理后再传给前端) - 替代方案更安全:用
v-text+ 自定义解析器处理白名单标签(如仅允许<p></p>、<strong></strong>),或改用render函数控制输出结构
Custom Elements + Shadow DOM 真正隔离通信靠什么
不是靠标签名或 <slot></slot>,而是靠 this.attachShadow({ mode: 'closed' }) 创建的边界 —— 外部 JS 无法访问 shadow root 内部节点,CSS 也不会泄漏。
- 必须在
constructor里调用super()和this.attachShadow(),顺序错或漏掉任一环节,shadow root 就不会创建,样式和结构立刻失效 -
connectedCallback是唯一能安全操作this.shadowRoot的生命周期钩子;在constructor里尝试访问this.shadowRoot会得到null - 属性通信走
static get observedAttributes()+attributeChangedCallback,但注意:只监听字符串属性变更,复杂对象需序列化(如JSON.stringify)再传,子组件再反解
template 标签复用时为什么 data 不共享
因为 Vue 组件的 data 必须是函数,每次实例化都会调用一次,返回全新对象 —— 这不是约定,是强制机制。
- 写成
data: { count: 0 }看似省事,但所有组件实例会共享同一个count引用,一个改,全部变 - 用
<template id="xxx"></template>定义模板时,Vue 内部会克隆该模板节点,但不会自动绑定新 data;必须确保组件定义里data()返回独立副本 - 如果通过
props传初始值,也要注意引用类型(如数组/对象)仍可能被多个实例意外修改,建议在data()函数里深拷贝
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











