vue可以渐进式增强HTML的前提是vue的模板语法不会使得浏览器报错,这样我们才可以在dom中内嵌vue语法,
所以vue文档在开头就说了一件事情, 就是vue的模板语法是语法合格的HTML
同时在在SFC(也就是后缀为.vue的文件)中, 模板被编译器编译后还会对代码进行优化,像手写vue提供的渲染函数代码没有经过编译阶段,就没有这个编译阶段,所以vue文档在开头说了另一件事情就是手写渲染函数而不采用模板,不会受到和模板同等级的编译优化
总结一下,vue文档开头说了两句话,一件是写了vue的语法的模板放浏览器上跑也没有问题,一件是编译器会对SFC的模板进行优化要比自己手写渲染函数好。
v-html
先看下面一个例子,
html
<body>
<div id="app">
</div>
<!-- App组件 -->
<template id="appTemplate">
<div style="width: 100px;height: 100px;background-color: pink;" v-html="rawHtml">
</div>
</template>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.5.22/vue.global.prod.min.js"></script>
<script>
const App = {
data() {
return {
rawHtml: "this is Compo {{count}}"
}
},
template: "#appTemplate",
};
const app = Vue.createApp(App);
app.mount("#app");
</script>
</body>
可以看到v-html的作用就是插入一个html片段,在这个属性中没有办法使用Vue语法,很适合用来渲染服务器返回的html片段
Attribute绑定
javascript
<div v-bind:id="dynamicId"></div>
<div :id="dynamicId"></div>
在这里div标签的id属性的值会保持和组件的dynamicId属性一致,如果绑定的值是null或者是undefined,那么这个属性会从渲染的元素上移除,下面是这个用法的简写语法,而且当要绑定的参数id和提供值的数据dynamicId名字一样的话,还可以更加简写
javascript
<div v-bind:id></div>
<div :id></div>
注意,这里需要有一个注意点,那就是当你给属性使用一些假值的时候,它是否还会渲染,请看下面一个例子
javascript
<body>
<div id="app">
</div>
<!-- App组件 -->
<template id="appTemplate">
<div :id>这是div</div>
</template>
<script src="./node_modules/vue/dist/vue.global.prod.js"></script>
<script>
const App = {
data() {
return {
id: 0
}
},
template: "#appTemplate"
};
const app = Vue.createApp(App);
app.mount("#app");
</script>
// 上述渲染结果为 id: "0"
//如果id为false
//则渲染id: "false"
//如果id为""
//则渲染id
//如果为null, undefined
//那么就不会渲染这个属性了
可以看到除了null,undefined不会渲染外,其它假值都会作为这个标签属性id的值,vue中除此之外还提到了布尔型Attribute,它不会将你的数据映射到属性的值上,而是判断你的数据真假,如果为真,则会把这个属性渲染到元素上,如果判断为假,则不会渲染这个属性, 会有这种布尔型属性,主要是和html的一些布尔属性有关,disabled, hidden这种,当你把属性写在标签上的时候,不管你给什么值,都会执行这个属性应有的效果, vue在处理的时候当然不能直接把数据映射上去,判断数据的真假然后决定这个属性是否应该存在是比较好的处理了, 请看下面一个例子
javascript
<body>
<div id="app">
</div>
<!-- App组件 -->
<template id="appTemplate">
<div :hidden="id">这是div</div>
</template>
<script src="./node_modules/vue/dist/vue.global.prod.js"></script>
<script>
const App = {
data() {
return {
id: null
}
},
template: "#appTemplate"
};
const app = Vue.createApp(App);
app.mount("#app");
</script>
</body>
//这里没有渲染hidden, 如果id为undefined也是一样
//如果id为 0
//则没有渲染 hidden
//如果id为""
//则渲染出了 hidden
//如果id为 false
//则没有渲染hidden
可以看到,对于布尔型Attribute,vue的判断也和正常的js不一致,vue没有把本该是一个假值的""空字符串也定义为空,但是对于其它常见的假值false, 0, null, undefined,就不会渲染这个属性,我们也可以批量的绑定多个值。
javascript
<body>
<div id="app">
</div>
<!-- App组件 -->
<template id="appTemplate">
<div v-bind="objectAttr">这是div</div>
</template>
<script src="./node_modules/vue/dist/vue.global.prod.js"></script>
<script>
const App = {
data() {
return {
objectAttr: {
id: false,
class: "wrapper"
}
}
},
template: "#appTemplate"
};
const app = Vue.createApp(App);
app.mount("#app");
</script>
</body>
//这里id: false也可以渲染出来,因为id不是一个布尔型属性
指令
指令是带有v-前缀的特殊attribute, 上述描述的v-bind也就是一个指令,可以说v-bind:id.prevent="idValue"中,v-bind用于声明要使用的指令,:id部分是指令的参数部分,而idValue是属性的值部分, 其中prevent是修饰符的部分,请看下面一个例子
html
<a href="https://bilibili.com" @click.prevent="">bilibili
<span>a的子元素span</span>
</a>
动态参数
vue还提供了一种动态参数的用法, 它具体的用法是v-bind:[attributeName]='url', 这里的attributeName是一个组件的数据,属性名称由这个attributeName的值决定,如果这里的attributeName为href,则在模板上就会渲染属性href='....',,但是这种动态用法很容易踩坑,,请先查看下面一个例子,
javascript
<body>
<div id="app"></div>
<template id="appTemplate">
<img :[attributeName]='url'>
</template>
<!-- 使用 Vue 3 CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
const App = {
data() {
return {
attributeName: "src",
url: "https://picsum.photos/200/300" // 测试图片
};
},
template: "#appTemplate"
};
createApp(App).mount("#app");
</script>
</body>
并没有渲染出我们的图片!!!为什么??? 不妨让我看看dom的结构是什么样的

可以看到,浏览器对属性进行了归一化处理,大写的字符被转化为小写的了,所以这里最好是把数据也写成小写形式,如下
javascript
attributename: "src",
我们还可以使用动态绑定多个值规避这一点
javascript
<img v-bind='{[attributeName]: url}'>
当然也可以使用计算属性计算出结果对象然后v-bind绑定上, 或者直接把DOM写在template字符串上, 当然在SFC上不会有这个问题,SFC没有把Vue模板给浏览器先解析一遍, 在vue文档中也描述了这个问题,当使用DOM内嵌模版时,我们需要避免在名称中使用大写字母,因为浏览器会强制将其转换为小写 。
动态参数在内嵌模板的dom中的问题
最后我们讨论来着vue文档的这么一句话,动态参数表达式因为某些字符串的缘故有一些语法限制,比如空格和引号,在HTML attribute名称中都是不合法
这是因为HTML属性名被规定必须是由一个或多个非空白的字符组成的,而且一定不能包含, 空格, 双引号, 单引号, =号 , <,>等特殊字符, 请看下面一个例子
xml
<a :[foo + 1]="value"> ... </a>
我们看它在浏览器上是什么样子,

一摸一样!,我们再看看这个标签元素的属性结构,

原本我们想表达的一个完整意思 foo + 1被打断了!!! 为什么会这样呢,其实是浏览器宽松的解析导致的,它不会发生什么报错,它只会按HTML规则解析每一个HTML属性,所以这里浏览器看上去保留了上面写的完整字符串好像是真的作为属性了,但实际上它已经把属性按HTML分词规则拆成了多个属性,vue显然没办法解析这样逻辑被拆分出去的不完整属性, 所以让我们回到vue文档,比如空格和引号,这样的不合法结构无法被解析为正确的HTML属性,但是你可以写成foo+1,是可以被解析的,因为它没有空格和引号了,请看下面一个例子。
xml
<div id="app"></div>
<!-- 使用 Vue 3 CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
const App = {
data() {
return {
src: 1
}
},
template: `<a href="https://bilibili.com" @click.prevent="">bilibili
<span :[src+1]="1">a的子元素span</span>
</a>`
};
createApp(App).mount("#app");
</script>
这段代码结果中a标签渲染出的属性为2="1"。
也可以使用SFC和template规避这个问题,像上面说的,SFC和template都没有让浏览器预先处理标签,自然也就能处理一些浏览器没办法处理的。
显示移除绑定
在文档中还有这么一句话,动态参数中表达式的值应当是一个字符串,或者是null, 特殊值null意为显示移除该绑定,其它非字符串的值会触发警告
请看下面一段代码
xml
<div id="app"></div>
<!-- 使用 Vue 3 CDN -->
<script src="./node_modules/vue/dist/vue.global.prod.js"></script>
<script>
const { createApp } = Vue;
const App = {
data() {
return {
src: 1,
clickon: 'click'
}
},
template: `<a href="https://bilibili.com" @[clickon].prevent="">bilibili
<span :[src+1]="1">a的子元素span</span>
</a>`
};
const rootComponent = createApp(App).mount("#app");
</script>
可以看到我们的a标签的事件监听器确实监听名为click的事件

当我们在控制台设置rootComponent.clickon为null的时候后再次点击a标签,这时页面就发生了跳转,但其实设置成其它非click的字符串也是可以的,null在这里是给了一个在某某个状态下动态参数的值为null的时候,什么也不监听/什么属性也不添加的选项,要不然给一个字符串,肯定会添加上别的事件监听/属性