插值表达式-内置制定
在通常情况下,我们认为的模版语法仅仅是包含在 template 里面的内容,实际上它还包含了 Vue 的特性,如表达式、指令和属性等。Vue 的模版基于 HTML,这意味着模板中直接编写的 HTML 代码能够被浏览器的 HTML 解析器正确解析。然而,模版中的指令和表达式需要 Vue 提供的模板编译系统来处理。
开发者在编写 template 内容时,Vue 会将其解析为 HTML 字符串,然后转换成抽象语法树(AST)。通过遍历 AST,Vue 将表达式、属性和指令转换为虚拟 DOM 树,最终生成真实的 DOM 并渲染到页面上。
// 简单函数
function square(n) {
return n * n;
}
// 转换后的AST
{
type: "FunctionDeclaration",
id: {
type: "Identifier",
name: "square"
},
params: [
{
type: "Identifier",
name: "n"
}
],
// 其他属性省略
}
为什么要有虚拟 DOM?
虚拟 DOM 的引入主要是为了优化性能。当直接操作真实 DOM 时,每一次的修改都可能导致浏览器的重绘和重排,影响性能。通过引入虚拟 DOM,Vue 可以在内存中高效地对比新旧虚拟 DOM 树的差异,仅将必要的部分更新到真实 DOM,从而减少不必要的渲染操作。
<span>123</span>;
span.innerText = 123;
// span.innerText 的直接修改会影响 DOM 节点的变化
// 而使用虚拟 DOM 后,Vue 可以避免不必要的更新
实际上,网页中大多数的变化本质上都是数据的变化。Vue 的核心思想是“数据驱动”,即通过数据的变化来驱动视图的更新。这种设计理念使得 Vue 能够高效地管理和更新界面。
插值表达式
插值表达式允许我们在模板中动态地显示数据。Vue 使用双花括号 {{ }} 来绑定数据。
const App = {
data() {
return {
title: 'This is my title',
};
},
template: `
<div>
<h1 class="title">
{{ title }}
</h1>
</div>
`,
};
Vue.createApp(App).mount('#app');
在上述示例中,{{ title }} 会被替换为 data 中定义的 title 的值。当 title 的值发生变化时,视图会自动更新以反映新的值。
Mustache(八字胡)
插值表达式的由来可以追溯到 Mustache 模板引擎。Mustache 使用 \{{ \}} 来表示模板中的变量,这种语法被 Vue 采纳并加以扩展。
GitHub - janl/mustache.js: Minimal templating with \{{mustaches\}} in JavaScript
数据绑定的绑定的是什么?
数据绑定是 Vue 的核心特性之一,它负责将数据模型与视图层连接起来。
绑定的内容主要包括:
-
App.data中的数据:这是组件内部的数据,直接绑定到模板中的插值表达式或属性上。 -
父组件传递进来的属性值:通过
props,父组件可以向子组件传递数据。这种方式使得组件之间能够高效地共享和传递数据。使用组件的流程:
-
定义父组件:父组件中包含子组件,并通过属性向子组件传递数据。
-
定义子组件:子组件通过
props接收来自父组件的数据。 -
在父组件中声明子组件:在父组件的模板中使用子组件,并绑定相应的属性。
-
directive 指令
Vue 提供了大量的内置指令,开发者可以通过 v- 前缀来使用这些指令。此外,开发者也可以扩展自定义指令,但需要遵循 v- 命名规范。
v-once
v-once 指令用于一次性渲染元素或组件。使用 v-once 的元素及其所有子节点只会渲染一次,之后即使数据发生变化,也不会重新渲染。这对于静态内容的渲染可以提升性能。
- 使用
v-once时,会影响其内部的子元素,使内部的指令仅执行一次。 - 视图中,
Vue指定的插值表达式的数据变量必须在实例上声明。
v-html
v-html 指令用于将原始的 HTML 字符串插入到 DOM 中。需要注意的是,v-html 不会解析插值表达式中的 HTML,而是将其作为原始 HTML 插入。
const App = {
data() {
return {
title: 'This is my TITLE',
};
},
template: `
<div>
{{ '<h1>' + title + '</h1>' }}
</div>
`,
};
Vue.createApp(App).mount('#app');
结果

-
插值表达式
{{ '<h1>' + title + '</h1>' }}会解析为HTML,因为插值表达式是未经加工的rawHTML,没有对DOM进行操作。 -
类似于相机的
RAW文件,这些rawHTML是未经处理的HTML内容。 -
不要尝试使用
v-html来渲染子模板,因为Vue的编译系统需要处理模板内容。const App = {
data() {
return {
title: '<h1>This is my TITLE</h1>',
};
},
template: `
<div v-html="title"></div>
`,
};
// 不要使用这种方式去做子模板
Vue.createApp(App).mount('#app'); -
Vue底层有自己的一套编译系统,模板内容必须经过Vue的编译系统才能正确渲染为真实的DOM。- 字符串 →
AST树 → 虚拟DOM→ 真实DOM→ 渲染到#app
- 字符串 →
-
应遵循
Vue的规则,将子模板放入子组件中,以实现模板的复用和组合的强大功能。
v-html 会引发的问题
使用 v-html 需要谨慎,特别是当插入的内容来自用户输入时,因为这可能导致 XSS 攻击。
什么是 XSS 攻击?
XSS(跨站脚本攻击)通常指攻击者利用网页开发中的漏洞,通过注入恶意脚本代码到网页中,使用户在浏览器中执行这些恶意脚本。这些脚本通常是 JavaScript,但也可以是 Java、VBScript、ActiveX、Flash,甚至是普通的 HTML。攻击成功后,攻击者可能窃取用户的敏感信息,如会话 cookie,或者执行一些未授权的操作。
被利用的 innerHTML
-
v-html动态渲染HTML的实现机制:v-html基本上是通过设置元素的innerHTML来实现的。 -
innerHTML容易导致XSS攻击。例如:// 插入到 DIV 中,虽然 HTML5 对某些标签有严格限制
var text = '<script>alert(123)</script>';
document.getElementById('app').innerHTML = text;
// 但 img 标签可以执行 onerror 事件
var text = '<img src="invalid.jpg" onerror="alert(123)">';
document.getElementById('app').innerHTML = text; -
潜在风险:攻击者可以利用一些标签和事件来注入和执行恶意脚本,因此在使用
v-html时必须格外小心。 -
安全建议:
- 不要将用户提供的内容直接作为
v-html的插值。 - 对用户输入的内容进行严格的过滤和消毒,防止恶意代码的注入。
- 尽量避免在处理用户输入时使用
v-html,以确保网站的安全性。
- 不要将用户提供的内容直接作为