setup语法糖和style常用特性

setup语法糖

基本语法

要使用这个语法,需要将 setup attribute 添加到 <script> 代码块上:

<script setup>
console.log('hello script setup')
</script>

使用语法糖后就不需要再将属性和方法return出来,但是也存在一个问题,无论模板里会不会用到,属性和方法都会被return出来

顶层的绑定会被暴露给模板

当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用,同样import 导入的内容也会以同样的方式暴露。

<script setup>
// 变量
const msg = 'Hello!'

// 函数
function log() {
    
    
  console.log(msg)
}
</script>

<template>
  <div @click="log">{
    
    {
    
     msg }}</div>
</template>
<script setup>
import {
    
     capitalize } from './helpers'
</script>

<template>
  <div>{
    
    {
    
     capitalize('hello') }}</div>
</template>

使用组件

<script setup> 范围里的值也能被直接作为自定义组件的标签名使用:

<script setup>
import MyComponent from './MyComponent.vue'
</script>

<template>
  <MyComponent />
</template>

动态组件

由于组件被引用为变量而不是作为字符串键来注册的,在 <script setup> 中要使用动态组件的时候,就应该使用动态的:is来绑定:

<script setup>
import Foo from './Foo.vue'
import Bar from './Bar.vue'
</script>

<template>
  <component :is="Foo" />
  <component :is="someCondition ? Foo : Bar" />
</template>

递归组件

一个单文件组件可以通过它的文件名被其自己所引用。例如:名为 FooBar.vue 的组件可以在其模板中用 <FooBar/> 引用它自己。

请注意这种方式相比于 import 导入的组件优先级更低。如果有命名的 import 导入和组件的推断名冲突了,可以使用 import 别名导入:

import {
    
     FooBar as FooBarChild } from './components'

命名空间组件

可以使用带点的组件标记,例如 <Foo.Bar> 来引用嵌套在对象属性中的组件。这在需要从单个文件中导入多个组件的时候非常有用:

<script setup>
import * as Form from './form-components'
</script>

<template>
  <Form.Input>
    <Form.Label>label</Form.Label>
  </Form.Input>
</template>

Element UI中没有这种命名空间组件,相反 Ant design 中有不少这种类型的组件。

使用自定义指令

全局注册的自定义指令将以符合预期的方式工作,且本地注册的指令可以直接在模板中使用,就像上文所提及的组件一样。

但这里有一个需要注意的限制:必须以 vNameOfDirective 的形式来命名本地自定义指令,以使得它们可以直接在模板中使用。

<script setup>
const vMyDirective = {
    
    
  beforeMount: (el) => {
    
    
    // 在元素上做些操作
  }
}
</script>
<template>
  <h1 v-my-directive>This is a Heading</h1>
</template>
<script setup>
  // 导入的指令同样能够工作,并且能够通过重命名来使其符合命名规范
  import {
    
     myDirective as vMyDirective } from './MyDirective.js'
</script>

defineProps 和 defineEmits

运行时声明

标准setup语法中,propsemit都是通过setup传参的方式来使用。在语法糖中需要使用defineProps defineEmits 两个API来声明

<script setup>
const props = defineProps({
    
    
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    
    
    type: String,
    required: true
  },
  // Number 类型的默认值
  propD: {
    
    
    type: Number,
    default: 100
  },
  // 对象类型的默认值
  propE: {
    
    
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
    
    
      return {
    
     message: 'hello' }
    }
  },
  // 自定义类型校验函数
  propF: {
    
    
    validator(value) {
    
    
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propG: {
    
    
    type: Function,
    // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
    default() {
    
    
      return 'Default function'
    }
  }
})

const emit = defineEmits(['change', 'delete'])
// setup code


console.log(props.foo,emit('change'))
</script>

如果你使用的是ts,可以使用纯类型声明来声明 prop 和 emits(只是用与于ts)

仅限类型的 props/emit 声明

const props = defineProps<{
    
    
  foo: string
  bar?: number
}>()

const emit = defineEmits<{
    
    
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()

注: defineProps 或 defineEmits 只能是要么使用运行时声明,要么使用类型声明。同时使用两种声明方式会导致编译报错。

使用类型声明时的默认 props 值

仅限类型的 defineProps 声明的不足之处在于,它没有可以给 props 提供默认值的方式。为了解决这个问题,提供了 withDefaults 编译器宏:

interface Props {
    
    
  msg?: string
  labels?: string[]
}

const props = withDefaults(defineProps<Props>(), {
    
    
  msg: 'hello',
  labels: () => ['one', 'two']
})

defineExpose

使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。如果想要通过ref来获取组件中的属性和方法,你必须要通过defineExpose指定哪些属性和方式是可以被访问到的

<script setup>
import {
    
     ref } from 'vue'

const a = 1
const b = ref(2)

defineExpose({
    
    
  a,
  b
})
</script>

useSlots 和 useAttrs

useSlotsuseAttrs是用来访问模板中插槽和属性的,相当于标准setup中的第二个参数setup(props,{slots,attr,emmit})

<script setup> 使用 slotsattrs 的情况应该是很罕见的,因为可以在模板中通过 $slots$attrs 来访问它们。在你的确需要使用它们的罕见场景中,可以分别用 useSlotsuseAttrs 两个辅助函数:

<script setup>
import {
    
     useSlots, useAttrs } from 'vue'

const slots = useSlots()
const attrs = useAttrs()
</script>

与普通的 <script> 一起使用

<script setup> 可以和普通的 <script>一起使用。普通的 <script> 在有这些需要的情况下或许会被使用到:

  • 无法在 <script setup> 声明的选项,例如 inheritAttrs 或通过插件启用的自定义的选项。
  • 声明命名导出。
  • 运行副作用或者创建只需要执行一次的对象。
<script>
// 普通 <script>, 在模块范围下执行(只执行一次)
runSideEffectOnce()

// 声明额外的选项
export default {
    
    
  inheritAttrs: false,
  customOptions: {
    
    },
  name:'aComponent'
}
</script>

<script setup>
// 在 setup() 作用域中执行 (对每个实例皆如此)
</script>

style特性

具体看官方文档,这里只看一下常用的特性

深度选择器

深度选择器由2.0中的/deep/变为 :deep(),例如:

<style scoped>
:deep(.b) {
    
    
  /* ... */
}
</style>

状态驱动的动态 CSS

单文件组件的 <style> 标签可以通过 v-bind 这一 CSS 函数将 CSS 的值关联到动态的组件状态上:

<script setup>
const theme = {
    
    
  color: 'red'
}
</script>

<template>
  <p>hello</p>
</template>

<style scoped>
p {
    
    
  color: v-bind('theme.color');
}
</style>

实际开发中感觉使用:style="{}"方式更加常见一些。

猜你喜欢

转载自blog.csdn.net/weixin_41897680/article/details/124646903