Vue 单文件组件 (SFC) 规范
.vue
文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每个 .vue
文件包含三种类型的顶级语言块 <template>
、<script>
和 <style>
,还允许添加可选的自定义块。
vue-loader
会解析文件,提取每个语言块,如有必要会通过其它 loader 处理,最后将他们组装成一个 ES Module,它的默认导出是一个 Vue.js 组件选项的对象。
vue-loader
支持使用非默认语言,比如 CSS 预处理器,预编译的 HTML 模版语言,通过设置语言块的 lang
属性。例如,你可以像下面这样使用 Sass 语法编写样式:
<style lang="sass">
/* write Sass! */
</style>
Vue Loader 是一个 webpack 的 loader。
使用 Vue CLI 直接创建一个项目的脚手架,已经安装好了 vue-loader,也不需要手动配置 webpack 了。
资源 URL 转换会遵循如下规则:
- 如果路径是绝对路径 (例如
/images/foo.png
),会原样保留。 - 如果路径以
.
开头,将会被看作相对的模块依赖,并按照你的本地文件系统上的目录结构进行解析。 - 如果路径以
~
开头,其后的部分将会被看作模块依赖。这意味着你可以用该特性来引用一个 Node 依赖中的资源:<img src="~some-npm-package/foo.png">
- 如果路径以
@
开头,也会被看作模块依赖。如果你的 webpack 配置中给@
配置了 alias,这就很有用了。所有vue-cli
创建的项目都默认配置了将@
指向/src
。
Scoped CSS
当 <style>
标签有 scoped
属性时,它的 CSS 只作用于当前组件中的元素。
使用 scoped
后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
如果你希望 scoped
样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>>
操作符:
<style scoped>
.a >>> .b { /* ... */ }
</style>
上述代码将会编译成:
.a[data-v-f3f3eg9] .b { /* ... */ }
有些像 Sass 之类的预处理器无法正确解析 >>>
。这种情况下你可以使用 /deep/
或 ::v-deep
操作符取而代之——两者都是 >>>
的别名,同样可以正常工作。
通过 v-html
创建的 DOM 内容不受 scoped 样式影响。
CSS Modules
用于模块化和组合 CSS 的系统。
CSS Modules 必须通过向 css-loader
传入 modules: true
来开启:
// webpack.config.js
{
module: {
rules: [
// ... 其它规则省略
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// 开启 CSS Modules
modules: true,
// 自定义生成的类名
localIdentName: '[local]_[hash:base64:8]'
}
}
]
}
]
}
}
然后在你的 <style>
上添加 module
特性:
<style module>
.bold {
font-weight: bold;
}
</style>
这个 module
特性指引 Vue Loader 作为名为 $style
的计算属性,向组件注入 CSS Modules 局部对象。然后你就可以在模板中通过一个动态类绑定来使用它了:
<template>
<p :class="$style.red">
This should be red
</p>
<p :class="{ [$style.red]: isRed }">
Am I red?
</p>
<p :class="[$style.red, $style.bold]">
Red and bold
</p>
</template>
热重载
当使用脚手架工具 vue-cli
时,热重载是开箱即用的。
- 当编辑一个组件的
<template>
时,这个组件实例将就地重新渲染,并保留当前所有的私有状态。能够做到这一点是因为模板被编译成了新的无副作用的渲染函数。 - 当编辑一个组件的
<script>
时,这个组件实例将就地销毁并重新创建。(应用中其它组件的状态将会被保留) 是因为<script>
可能包含带有副作用的生命周期钩子,所以将重新渲染替换为重新加载是必须的,这样做可以确保组件行为的一致性。这也意味着,如果你的组件带有全局副作用,则整个页面将会被重新加载。 <style>
会通过vue-style-loader
自行热重载,所以它不会影响应用的状态。