Skip to content
当前页面

提示:

Vue3.2 版本开始才能使用语法糖!

什么是 setup script

它是 Vue3 的一个新语法糖,在 setup 函数中。所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 setup() 返回对象中。相对于之前的写法,使用后,语法也变得更简单。 使用方式极其简单,仅需要在 script 标签加上 setup 关键字即可。示例:

vue
<script setup></script>

里面的代码会被编译成组件 setup() 函数的内容。这意味着与普通的 <script> 只在组件被首次引入的时候执行一次不同,<script setup> 中的代码会在每次组件实例被创建的时候执行。

组件自动注册

在 script setup 中,引入的组件可以直接使用,无需再通过 components 进行注册,并且无法指定当前组件的名字,它会自动以文件名为主,也就是不用再写 name 属性了。示例:

vue
<template>
  <Child />
</template>

<script setup>
import Child from "./Child.vue";
</script>

属性和方法无需返回

<script setup>中无需 return 声明的变量、函数

vue
<script setup>
//import引入的内容
import { getToday } from "./utils";
// 变量
const msg = "Hello!";
// 函数
function log() {
  console.log(msg);
}
</script>

<!--在template中直接使用声明的变量、函数以及import引入的内容-->
<template>
   
  <div @click="log">{{ msg }}</div>
   
  <p>{{ getToday() }}</p>
</template>

使用 props

defineProps 代替 props,接收父组件传递的数据(父组件向子组件传参)

html
<script setup>
  // import { defineProps } from "vue";
  // defineProps在<script setup>中自动可用,无需导入
  // 需在.eslintrc.js文件中【globals】下配置【defineProps: true】
  const props = defineProps({
    title: String,
  });
</script>

使用 emits

defineEmit 代替 emit,子组件向父组件传递数据(子组件向外暴露数据)

vue
<script setup>
// import { defineEmits } from "vue";
// defineEmits<script setup>中自动可用,无需导入
// 需在.eslintrc.js文件中【globals】下配置【defineEmits: true】
const emit = defineEmits(["change", "delete"]);
</script>

组件之间使用 v-model

  1. 子组件
vue
<template>
  <span @click="changeInfo">我叫{{ modelValue }},今年{{ age }}</span>
</template>

<script setup>
defineProps({
  modelValue: String,
  age: Number,
});

const emit = defineEmits(["update:modelValue", "update:age"]);
const changeInfo = () => {
  // 触发父组件值更新
  emit("update:modelValue", "Tom");
  emit("update:age", 30);
};
</script>
  1. 父组件
vue
<template>
  <!-- v-model:modelValue简写为v-model // 可绑定多个v-model -->
  <child v-model="state.name" v-model:age="state.age" />
</template>

<script setup>
import { reactive } from "vue";
// 引入子组件
import child from "./child.vue";
const state = reactive({
  name: "Jerry",
  age: 20,
});
</script>

获取 slots 和 attrs

可以通过useContext从上下文中获取 slots 和 attrs。不过提案在正式通过后,废除了这个语法,被拆分成了useAttrsuseSlots

vue
<!--旧-->
<script setup>
import { useContext } from "vue";
const { slots, attrs } = useContext();
</script>

<!--新-->
<script setup>
import { useAttrs, useSlots } from "vue";
const attrs = useAttrs();
const slots = useSlots();
</script>

defineExpose API

使用 <script setup> 的组件,父组件是无法通过 ref 或者 $parent 获取到子组件的 ref 等响应数据,需要通过defineExpose 主动暴露

vue
<script setup>
import { defineExpose } from "vue";
const a = 1;
const b = 2;
//主动暴露组件属性
defineExpose({
  a,
});
</script>

在 setup 访问路由

访问路由实例组件信息:route 和 router

提示:

setup 里不能访问 this,不能再直接访问 this.$routerthis.$route。(getCurrentInstance可以替代this但不推荐)

推荐:使用useRoute 函数和useRouter函数替代this.$routethis.$router

vue
<script setup>
import { useRouter, useRoute } from 'vue-router'
    const route = useRoute()
    const router = useRouter()
    
    function pushWithQuery(query) {
      router.push({
        name: 'search',
        query: {
          ...route.query,
        },
      })
    }
  <script/>

路由导航守卫

vue
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from "vue-router";

// 添加一个导航守卫,在当前组件将要离开时触发。
onBeforeRouteLeave((to, from, next) => {
  next();
});

// 添加一个导航守卫,在当前组件更新时触发。
// 在当前路由改变,但是该组件被复用时调用。
onBeforeRouteUpdate((to, from, next) => {
  next();
});
</script>

生命周期

通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。

下表包含如何在 Option API 和 setup() 内部调用生命周期钩子

Option APIsetup 中
beforeCreate不需要
created不需要
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
activatedonActivated
deactivatedonDeactivated

原型绑定与组件内使用

  1. main.js
js
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);

// 获取原型
const prototype = app.config.globalProperties;

// 绑定参数
prototype.name = "Jerry";
  1. 组件内使用
vue
<script setup>
import { getCurrentInstance } from "vue";

// 获取原型
const { proxy } = getCurrentInstance();

// 输出
console.log(proxy.name);
</script>

v-bind() CSS 变量注入

vue
<template>
  <span>Jerry</span>
</template>

<script setup>
import { ref, reactive } from "vue";
// prop接收样式
const props = defineProps({
  border: {
    type: String,
    default: "1px solid yellow",
  },
});

// 常量声明样式
const background = "red";

// 响应式数据声明样式
const color = ref("blue");
const style = reactive({
  opacity: "0.8",
});
</script>

<style lang="scss" scoped>
span {
  // 使用常量声明的样式
  background: v-bind(background);

  // 使用响应式数据声明的样式
  color: v-bind(color);
  opacity: v-bind("style.opacity");

  // 使用prop接收的样式
  border: v-bind("props.border");
}
</style>