新增了哪些概念
应用实例
每个 Vue 应用都是通过 createApp 函数创建一个新的应用实例。
传入 createApp 的对象实际上是一个组件,每个应用都需要一个根组件,其他组件将作为其子组件。
应用实例并不只限于一个,createApp API 允许在同一个页面中创建多个共存的 Vue 应用。
import { createApp } from 'vue'
// 从一个单文件组件中导入根组件
import App from './App.vue'
const app = createApp(App)
挂载应用
应用实例必须在调用了 .mount()
方法后才会渲染出来。
<div id="app"></div>
该方法接收一个参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串。
它的返回值是根组件实例而非应用实例。
app.mount('#app')
模板语法
Vue 使用一种基于 HTML 的模板语法,在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。
也可以结合可选的 JSX 支持直接手写渲染函数而不采用模板。但是,这将不会享受到和模板同等级别的编译时优化。
文本插值
最基本的数据绑定形式是文本插值。
<span>Message: {{ msg }}</span>
使用JavaScript表达式
在所有的数据绑定中都支持完整的 JavaScript 表达式。
在 Vue 模板内,JavaScript 表达式可以被使用在如下场景上
- 在文本插值中 (双大括号)
- 在任何 Vue 指令 (以 v- 开头的特殊 attribute) attribute 的值中
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>
这些表达式都会被作为 JavaScript ,以当前组件实例为作用域解析执行。
CSS class
可以给 :class(v-bind:class 的缩写)传递一个对象来动态切换 class。
<div
class="static"
:class="{ active: true, 'text-danger': true }"
></div>
<div :class="[activeClass, errorClass]"></div>
<div :class="[{ active: true }, errorClass]"></div>
CSS style
:style 支持绑定 JavaScript 对象值,对应的是 HTML 元素的 style 属性。
<div :style="{ color: 'red', fontSize: '30px' }"></div>
<div :style="[baseStyles, overridingStyles]"></div>
数组变化侦测
Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。
变更原数组 | 返回新数组 |
---|---|
push() | filter() |
pop() | concat() |
shift() | slice() |
unshift() | |
splice() | |
sort() | |
reverse() |
Slots
<slot>
元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。
<script setup>
import FancyButton from './FancyButton.vue'
</script>
<template>
<FancyButton>
Click me <!-- slot content -->
</FancyButton>
</template>
<template>
<button class="fancy-btn">
<slot/> <!-- slot outlet -->
</button>
</template>
具名插槽
带 name 的插槽被称为具名插槽 (named slots)。
要为具名插槽传入内容,需要使用一个含 v-slot 指令的 <template>
元素,并将目标插槽的名字传给该指令。
<BaseLayout>
<template v-slot:header>
<!-- header 插槽的内容放这里 -->
</template>
</BaseLayout>
其中 <template v-slot:header>
可以简写为 <template #header>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
动态插槽名
<BaseLayout>
<template v-slot:[dynamicSlotName]>
...
</template>
<!-- 缩写为 -->
<template #[dynamicSlotName]>
...
</template>
<BaseLayout>
Scoped
使用 scoped 后,父组件的样式将不会渗透到子组件中。
深度选择器
处于 scoped 样式中的选择器如果想要做更深度的选择,即影响到子组件,可以使用 :deep()
这个伪类。
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
上面的代码会被编译成
.a[data-v-f3f3eg9] .b {
/* ... */
}
插槽选择器
使用 :slotted
伪类以明确地将插槽内容作为选择器的目标。
<style scoped>
:slotted(div) {
color: red;
}
</style>
全局选择器
可以让其中一个样式规则应用到全局。
<style scoped>
:global(.red) {
color: red;
}
</style>
混合使用局部与全局样式
可以在同一个组件中同时包含作用域样式和非作用域样式。
<style>
/* 全局样式 */
</style>
<style scoped>
/* 局部样式 */
</style>