Vue3.0 单文件组件 - SFC语法定义
Posted 爱怪笑的小杰杰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3.0 单文件组件 - SFC语法定义相关的知识,希望对你有一定的参考价值。
1、总览
一个 Vue 单文件组件 (SFC) Single File Components,通常使用 *.vue
作为文件扩展名,它是一种使用了类似 html 语法的自定义文件格式,用于定义 Vue 组件。一个 Vue 单文件组件在语法上是兼容 HTML 的。
每一个 *.vue
文件都由三种顶层语言块构成:<template>
、<script>
和 <style>
,以及一些其他的自定义块:
<template>
<div class="example"> msg </div>
</template>
<script>
export default
data()
return
msg: 'Hello world!'
</script>
<style>
.example
color: red;
</style>
<custom1>
This could be e.g. documentation for the component.
</custom1>
2、相应语言块
<template>
-
每个
*.vue
文件最多可以包含一个顶层<template>
块。 -
语块包裹的内容将会被提取、传递给
@vue/compiler-dom
,预编译为 JavaScript 渲染函数,并附在导出的组件上作为其render
选项。
<script>
-
每个
*.vue
文件最多可以包含一个<script>
块。(使用 <script setup> 的情况除外) -
这个脚本代码块将作为 ES 模块执行。
-
默认导出应该是 Vue 的组件选项对象,可以是一个对象字面量或是 defineComponent 函数的返回值。
<script setup>
-
每个
*.vue
文件最多可以包含一个<script setup>
。(不包括一般的<script>
) -
这个脚本块将被预处理为组件的
setup()
函数,这意味着它将为每一个组件实例都执行。<script setup>
中的顶层绑定都将自动暴露给模板。要了解更多细节,请看 <script setup> 的专门文档。
<style>
-
每个
*.vue
文件可以包含多个<style>
标签。 -
一个
<style>
标签可以使用scoped
或module
attribute (查看 SFC 样式功能了解更多细节) 来帮助封装当前组件的样式。使用了不同封装模式的多个<style>
标签可以被混合入同一个组件。
自定义块
请参见相关工具链指南获取更多细节。
3、自动名称推导
SFC 在以下场景中会根据文件名自动推导其组件名:
- 开发警告信息中需要格式化组件名时;
- DevTools 中观察组件时;
- 递归组件自引用时。例如一个名为
FooBar.vue
的组件可以在模板中通过<FooBar/>
引用自己。(同名情况下) 这比明确注册/导入的组件优先级低。
4、预处理器
代码块可以使用 lang
这个 attribute 来声明预处理器语言,最常见的用例就在 <script>
中使用 TypeScript:
<script lang="ts">
// use TypeScript
</script>
lang
在任意块上都能使用,比如我们可以在 <style>
标签中使用 SASS 是 <template>
中使用 Pug:
<template lang="pug">
p msg
</template>
<style lang="scss">
$primary-color: #333;
body
color: $primary-color;
</style>
注意对不同预处理器的集成会根据你所使用的工具链而有所不同,具体细节请查看相应的工具链文档来确认:
5、Src 导入
如果你更喜欢将 *.vue
组件分散到多个文件中,可以为一个语块使用 src
这个 attribute 来导入一个外部文件:
<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>
请注意 src
导入和 JS 模块导入遵循相同的路径解析规则,这意味着:
- 相对路径需要以
./
开头 - 你也可以从 npm 依赖中导入资源
<!-- 从所安装的 "todomvc-app-css" npm 包中导入一个文件 -->
<style src="todomvc-app-css/index.css" />
src
导入对自定义语块也同样适用:
<unit-test src="./unit-test.js">
</unit-test>
6、注释
在每一个语块中你都可以按照相应语言 (HTML、CSS、javascript 和 Pug 等等) 的语法书写注释。对于顶层注释,请使用 HTML 的注释语法 <!-- comment contents here -->
vue3中<script setup> 和 setup函数的区别
目录
官网:<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。相比于普通的 <script> 语法,具有以下特点:
- 更少的样板内容,更简洁的代码。
- 能够使用纯 TypeScript 声明 props 和自定义事件。
- 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
- 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。
简单来说<script setup> 就是 setup函数的一个语法糖,我们来看这个糖甜不甜~
一、基本语法
要启用该语法,需要在 <script>
代码块上添加 setup
属性即可
<script setup>
console.log('hello script setup')
</script>
里面的代码会被编译成组件 setup()
函数的内容。这意味着与普通的 <script>
只在组件被首次引入的时候执行一次不同,<script setup>
中的代码会在每次组件实例被创建的时候执行。
二、定义变量
使用setup函数
<script>
import ref from 'vue'
export default
name: 'Home',
setup ()
const num = ref(1)
return num
</script>
使用<script setup>
<script setup>
import ref from 'vue'
const num = ref(1)
</script>
so ~ 你是喜欢两行定义一个变量还是写成好多好多行,注意 当使用 <script setup>
的时候,任何在 <script setup>
声明的顶层的绑定 (包括变量,函数声明,以及 import 导入的内容) 都能在模板中直接使用
三、使用外部文件方法
使用setup函数
<template>
<div class="home">
<h1>使用了setup函数</h1>
<h2> lowercase1(name)</h2>
</div>
</template>
<script>
import ref from 'vue'
import lowercase from '@/utils/lowercase.js'
export default
setup ()
const name = ref('MYNAME')
const lowercase1 = lowercase
return name, lowercase1
</script>
使用<script setup>
<template>
<div class="about">
<h1>使用了script setup</h1>
<h2>1.使用变量 lowercase(name)</h2>
</div>
</template>
<script setup>
import lowercase from '@/utils/lowercase.js'
import ref from 'vue'
const name = ref('MYNAME')
</script>
不需要在定义成一个方法啦 直接使用
四、注册组件
使用setup函数
<script>
import Hello from '@/components/HelloWorld'
export default
components:
Hello
</script>
使用<script setup>
<script setup>
import Hello from '@/components/HelloWorld'
</script>
不需要在component 在注册了
五、使用自定义指令
不使用<script setup>
<template>
<h1 v-onceClick>使用了setup函数</h1>
</template>
<script>
export default
directives:
onceClick:
mounted (el, binding, vnode)
console.log(el)
,
</script>
使用<script setup>
<template>
<h1 v-my-Directive>使用了script setup</h1>
</template>
<script setup>
const vMyDirective =
beforeMount: (el) =>
console.log(el)
// 在元素上做些操作
</script>
全局注册的自定义指令将正常工作。本地的自定义指令在 <script setup>
中不需要显式注册,但他们必须遵循 vNameOfDirective
这样的命名规范
六、父传子
<Com :num="100"></Com>
使用setup函数
<script>
export default
props:
num:
type: Number,
default: 1
,
setup (props)
console.log(props)
</script>
使用<script setup>
<script setup>
import defineProps from 'vue'
// eslint-disable-next-line no-unused-vars
const props = defineProps(
num:
type: Number,
default: 1
)
</script>
七、子传父
使用setup函数
<script>
export default
setup (props, context)
const sendNum = () =>
context.emit('sendNum', 1200)
return sendNum
</script>
使用<script setup>
<script setup>
import defineProps, defineEmits from 'vue'
const emit = defineEmits(['submit'])
const sendNum = () =>
emit('submit', 1000)
</script>
-
defineProps
和defineEmits
都是只能在<script setup>
中使用的编译器宏。他们不需要导入,且会随着<script setup>
的处理过程一同被编译掉。 -
defineProps
接收与props
选项相同的值,defineEmits
接收与emits
选项相同的值。 -
defineProps
和defineEmits
在选项传入后,会提供恰当的类型推导。 -
传入到
defineProps
和defineEmits
的选项会从 setup 中提升到模块的作用域。因此,传入的选项不能引用在 setup 作用域中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块作用域内。
八、defineExpose
使用 <script setup>
的组件是默认关闭的——即通过模板引用或者 $parent
链获取到的组件的公开实例,不会暴露任何在 <script setup>
中声明的绑定。
可以通过 defineExpose
编译器宏来显式指定在 <script setup>
组件中要暴露出去的属性,若不使用defineExpose 则获取不到当前引用的组件实例变量、方法
<script setup>
import ref,defineExpose from 'vue'
const a = 1
const b = ref(2)
defineExpose(
a,
b
)
</script>
下面通过父组件获取子组件实例时 加definedExpose和不加 definedExpose的区别
九、useSlots()
和 useAttrs()
useSlots 顾名思义 使用插槽的意思 那必然和插槽脱离不了关系
子组件 定义出一个插槽
<template>
<div>
<slot name="header"> </slot>
</div>
</template>
<script setup>
import onMounted, useSlots from 'vue'
onMounted(() =>
const slot = useSlots()
const slotHeader = slot.header()
console.log(slot, slotHeader)
)
</script>
父组件
<ComSlot>
<template v-slot:header>我是父组件使用了header</template>
</ComSlot>
来看打印出来的slot和slotHeader
useSlots是一个函数可以打印出组件中所有的插槽 而打印出来的插槽同样是函数 调用后可以看到插槽的基础信息
useAttrs
父组件
<ComSlot class="box">
<template v-slot:header><p>我是父组件使用了header</p></template>
</ComSlot>
子组件
<script setup>
import useAttrs from 'vue'
onMounted(() =>
const artts = useAttrs()
console.log(artts)
)
</script>
useAttrs 可以拿到父组件传递过来的所有属性
十、与普通的<script>
一起使用
<script setup>
可以和普通的 <script>
一起使用。普通的 <script>
在有这些需要的情况下或许会被使用到:
- 声明无法在
<script setup>
中声明的选项,例如inheritAttrs
或插件的自定义选项。 - 声明模块的具名导出 (named exports)。
- 运行只需要在模块作用域执行一次的副作用,或是创建单例对象。
<script>
// 普通 <script>, 在模块作用域下执行 (仅一次)
runSideEffectOnce()
// 声明额外的选项
export default
name:'header',
inheritAttrs: false,
customOptions:
</script>
<script setup>
// 在 setup() 作用域中执行 (对每个实例皆如此)
</script>
十一、顶层 await
<script setup>
中可以使用顶层 await
。结果代码会被编译成 async setup()
:
<script setup>
const post = await fetch('https://api.uomg.com/api/rand.qinghua').then((r) => r.json())
</script>
另外,await 的表达式会自动编译成在 await
之后保留当前组件实例上下文的格式。
注意:async setup()
必须与 Suspense 内置组件组合使用,Suspense
目前还是处于实验阶段的特性,会在将来的版本中稳定。
使用await demo
父组件
<template>
<div>
<Suspense>
<template v-slot:default> <ComAwait></ComAwait> </template>
<template v-slot:fallback> <div>加载中</div> </template>
</Suspense>
</div>
</template>
<script setup>
import defineAsyncComponent from 'vue' // 使用defineAsyncComponent异步引入组件
const ComAwait = defineAsyncComponent(() =>
import('@/components/ComAwait.vue')
)
</script>
子组件
<template>
<div>post.content</div>
</template>
<script setup>
const post = await fetch('https://api.uomg.com/api/rand.qinghua').then((r) => r.json())
</script>
十二、限制<script setup> 使用src属性
由于模块执行语义的差异,<script setup>
中的代码依赖单文件组件的上下文。当将其移动到外部的 .js
或者 .ts
文件中的时候,对于开发者和工具来说都会感到混乱。因此,<script setup>
不能和 src
attribute 一起使用。
以上是关于Vue3.0 单文件组件 - SFC语法定义的主要内容,如果未能解决你的问题,请参考以下文章
vue3中<script setup> 和 setup函数的区别
vue3中<script setup> 和 setup函数的区别