Vue使用一种基于HTML的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的DOM上。所有的Vue模板都是语法层面合法的HTML,可以被符合规范的浏览器和HTML解析器解析。
template内部的HTML字符串,内部有一些Vue的特性,例如插值表达式、自定义属性和指令。Vue提供一套模版编译系统来编译Vue的模版语法,解析流程如下:
:::info
开发者写的template
➡️ 分析HTML字符串
➡️ 生成AST树
➡️ 解析表达式、自定义属性、指令
➡️ 生成虚拟DOM
➡️ 解析为真实的DOM
➡️ render渲染到页面上
:::
为什么需要虚拟DOM呢?
假设我页面上现在有一个span元素
<span>Vue2</span>
const oDom = document.getElementsByTagname("span")[0];oDom.onclick = function(){oDom.innerText = "Vue2";}
综上,我们点击span标签的时候把内容更改为Vue2,但是我们页面上本来就是Vue2,所以不需要对内容进行更改。如果使用真实DOM进行对比会比较麻烦,如果使用了虚拟DOM对象的数据进去对比就方便了很多,所以虚拟DOM能将新的DOM和旧的DOM进行对比来判断数据是否发生了变化,来决定是否要更新视图。
除了使用template,Vue还支持render+h函数:
import { createApp, h } from "vue";const App = {render() {return h("div", {},[h("h1", { class: "title" }, this.title),h("p", {}, "This is content")]);},data() {return {title: "this is my title",};},};createApp(App).mount("#app");
插值表达式
插值表达式内只能书写JS表达式,不能书写语句、函数、声明等!
const App = {template: `<h1 class="title">{{ title }}</h1><p>{{ var a = 1 }}</p> 这是一个语句,而非表达式<p>{{ if (ok) { return message } }}</p> 条件控制也不支持`,data() {return {title: "this is my title",};},};
插值表达式的想法来源于Mustache八字胡。
GitHub - janl/mustache.js: Minimal templating with {{mustaches}} in JavaScript
我们可以利用这个库实现一个简单的案例:
import mustache from "mustache";let data = {title: "This is My Title",};let html = mustache.render(`<h1>{{ title }}</h1>`, data);console.log(html); // <h1>This is My Title</h1>
以上案例我们利用Mustache就将{{}}内的数据进行了替换,但是**Vue**并没有使用**Mustache**库,只是灵感来源于它。Mustache并不支持HTML书写的插值,Vue的底层有一套自己的模版编译系统,所以能支持Vue内置的属性。
Vue 的内置指令
在Vue开发中,所有书写在Vue模版中v-*都是指令。为什么叫做指令呢?指令可以告诉模版应该按照什么样的逻辑进行渲染或绑定行为。Vue提供了大量的内置指令,如v-if、v-show、v-for、v-html…同时Vue还支持我们给Vue拓展指令(也就是自定义指令)。
这里我们挑几个指令讲述一下使用时的注意点:
v-html,在插值中是不会解析HTML字符串的,因为插值是JS表达式,没有对DOM的操作。 ```vue{{ ‘‘+ 内容 +’
‘ }}
不要试图将`v-html`作为子模版的显示,因为`Vue`本身有一套底层的模版编译系统,而不是直接使用字符串进行渲染,这会导致语法无法被解析,你应该把子模版放到子组件中,让模版的重用和组合更加强大。```vue<template><!-- 不要这样做 --><div v-html="child"></div></template><script>export default{data(){return{child: `<button @click="handleClickBtn">点击按钮</button>`}}}</script>
另外需要注意,v-html是动态渲染的HTML,使用的基本都是innerHTML属性进行赋值,innerHTML很容易导致XSS的攻击!!!
let text = "<img src="123" onerror="alert(123)" />" // 图片加载失败将会执行 alertdocument.body.innerHTML = text;
v-once用于让template一次插值后,再也不更新,这个指令同时会影响到子组件!!! ```vue{{ title }}
- `v-bind`用于动态绑定属性,布尔型的属性依据`true/false`值来决定`attribute`是否应该存在于该元素上。`disabled`就是最常见的例子之一。当`isButtonDisabled `为真值或一个空字符串 (即`<button disabled="">`) 时,元素会包含这个`disabled attribute`。而当其为其他假值时`attribute`将被忽略。```vue<button :disabled="isButtonDisabled">Button</button>
如果你有像这样的一个包含多个attribute的JavaScript对象,通过不带参数的v-bind,你可以将它们绑定到单个元素上:
<template><div v-bind="objectOfAttrs"></div><!-- 和下面的等效的 --><div v-bind:id="objectOfAttrs.id" v-bind:class="objectOfAttrs.class"></div></template><script>export default{data(){return{objectOfAttrs:{id: 'container',class: 'wrapper'}}}}</script>
