Vue3.0-如此简单的setup

本文详细介绍了Vue3.0中的setup语法糖,包括安装Vue3.0,setup的基本用法,如响应式、组件、自定义指令、props与emits的定义,以及与typescript的结合使用。通过示例展示了setup如何简化代码,提高性能,并提到了与普通<script>标签的配合使用场景。最后,强调了setup在TypeScript环境下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 安装Vue3.0

  • npm init vue@latest,选择所需配置
  • 根据安装成功后的指令提示
    • cd vue3setup 进入项目
    • npm install 安装依赖
    • npm run dev 启动项目

2. setup语法糖

script setup 是在单文件组件(SFC)中使用组合式API的编译时语法糖。当同时使用SFC与组合式API时该语法是默认推荐。相比于普通的<script>语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码
  • 能够使用纯TypeScript声明props和自定义事件
  • 更好的运行时性能(其模板会被编译成统一作用域内的渲染函数,避免了渲染上下文代理对象)
  • 更好的IDE类型推导性能(减少了语言服务器从代码中抽取类型的工作)

2.1 setup语法糖基本用法

  • 若要启用该语法糖,需要在<script>标签上添加setup属性,里面的代码会被编译成组件setup()函数的内容。这意味着与普通的<script>只在组件被首次引入的时候执行一次不同,<script setup>中的代码会在每次组件实例被创建的时候执行。

2.1.1 顶层绑定暴露给模板

  • 当使用<script setup>时,任何在<script setup>声明的顶层的绑定(包含变量、函数声明,以及import导入的内容)都能在模板中直接使用
  • 变量、函数以及import内容,直接可在<template />中进行使用
  • 引入组件自动注册
  • 引入工具函数,即刻使用
<template>
  <div class="about">
    <button @click="logCurName">{{myPageName}}</button>
    <div>
      初始值为 {{calcdouble(initHalf)}}
    </div>
    <ActivityTip />
  </div>
</template>

<script setup>
// 顶层引入工具函数
import calcdouble from "../utils/calcdouble.js";
// 顶层引入组件
import ActivityTip from '../components/ActivityTip.vue'
// 顶层定义变量
const myPageName = 'this is an about page'
const initHalf = 3
// 顶层定义方法
function logCurName() {
  console.log(myPageName)
}
</script>

2.1.2 响应式

想要将某个值定义为响应式,可以使用composition Api中的ref,覆盖范围较广。

<template>
	<button @click="times++">Add res {{times}}</button>
</template>
<script setup>
	const times = ref(0)
</script>

2.1.3 使用组件

  • 动态组件: 可以通过当前的某种状态判断要加载哪种具体的组件,也可引用多个组件,通过is属性引入对应的组件,引入进来的组件AComponent、BComponent可以看做变量来进行使用
<template>
	<div>
		<component :is="AComponent" />
		<component :is="showAStatus ? AComponent: BComponent"/>
	</div>
</template>
<script setup>
	import AComponent from "../components/AComponent.vue";
	import BComponent from "../components/BComponent.vue";
	
	const showAStatus = ref(false);
</script>

2.1.4 使用自定义指令

除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。

  • 全局自定义指令在script setup中正常工作
  • 本地自定义指令在script setup中无需显示注册,但命名必须遵守vNameOfDirective
<template>
	<div>自动聚焦当前输入框: <input v-input-focus type="text" /></div>
</template>

<script setup>
	const vInputFocus = {
	  mounted: (el) => {
	    el.focus();
	  },
	};
</script>
  • 若从外部环境导入某个具体的指令,可以通过重命名来使其符合命名规范
autoFocus.js

const autoFocus = {
  mounted: (el) => {
    el.focus();
  },
};

export {
  autoFocus
}

页面中使用autoFocus,不符合指令规范,在引入中将其修改
<template>
	<div>自动聚焦当前输入框: <input v-auto-focus type="text" /></div>
</template>
<script setup>
	import { autoFocus as vAutoFocus } from '../utils/autoFocus.js'
</script>

2.1.5 defineProps()和defineEmits()

父子组件通信时大多数情况下会遇到props将参数从父组件传入子组件,使用emit将子组件某些值回传给父组件。与之前的原理相同,只是写法上略有些变化。

  • defineProps 和 defineEmits 都是只能在 <script setup> 中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。
  • defineProps 接收与 props 选项相同的值,defineEmits 接收与 emits 选项相同的值。
  • defineProps 和 defineEmits 在选项传入后,会提供恰当的类型推导。
    传入到 defineProps 和 defineEmits 的选项会从 setup 中提升到模块的作用域。因此,传入的选项不能引用在 setup 作用域中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块作用域内。

父组件: 引入子组件,定义传入子组件初始props值,定义子组件传出的方法并接收传出值

<template>
	<div>
		<AComponent :curCount="curCount" @addCurCount="addCurCount"/>
	</div>
</template>
<script setup>
	import AComponent from "../components/AComponent.vue";
	const curCount = ref(4)
	function addCurCount(val) {
	  curCount.value += val
	}
</script>

子组件: 接收props值,定义传出方法

<template>
  <div>
    <button @click="addCurCount">当前值{{ curCount }},点我加3</button>
  </div>
</template>

<script setup>
const emits = defineEmits(["addCurCount"]);
const props = defineProps({
  curCount: {
    type: Number,
  },
});

const addCurCount = function () {
  emits("addCurCount", 3);
};
</script>

2.1.6 defineExpose

我们可以在父组件通过ref获取子组件实例

父组件:
<template>
	<AComponent ref="Acom" :curCount="curCount" @addCurCount="addCurCount"/>
</template>
<script setup>
import AComponent from "../components/AComponent.vue";
import { onMounted, ref } from "vue";
const Acom = ref(null)
onMounted(() => {
  console.log(Acom.value, '获取子组件信息')
})
</script>

但子组件中定义的一些变量和方法我们是无法获取到的,此时在子组件中通过defineExpose将想要被父组件访问到的内容暴露出来,我们就可以在Acom.value中获取到啦

子组件:
<script setup>
	import { onMounted, ref } from "vue";
	const paramsA = ref(12)
	const paramsB = '这是一段固定的字符串'

	defineExpose({
	  paramsA,
	  paramsB,
	  addCurCount
	})
</script>

2.2 setup语法糖结合组件库的使用

结合普通script形式及setup script,对比一下增加setup语法糖后我们的代码会发生哪些不同的地方

  • 引入ant-design-vue组件库 main.js
import { Form, Input, Checkbox, Button } from "ant-design-vue";
import 'ant-design-vue/dist/antd.css';

app.use(Form);
app.use(Input);
app.use(Checkbox);
app.use(Button);
  • 相同的html结构
<template>
  <a-form
    :model="formState"
    name="basic"
    :label-col="{ span: 8 }"
    :wrapper-col="{ span: 16 }"
    autocomplete="off"
    @finish="onFinish"
    @finishFailed="onFinishFailed"
  >
    <a-form-item
      label="Username"
      name="username"
      :rules="[{ required: true, message: 'Please input your username!' }]"
    >
      <a-input v-model:value="formState.username" />
    </a-form-item>

    <a-form-item
      label="Password"
      name="password"
      :rules="[{ required: true, message: 'Please input your password!' }]"
    >
      <a-input-password v-model:value="formState.password" />
    </a-form-item>

    <a-form-item name="remember" :wrapper-col="{ offset: 8, span: 16 }">
      <a-checkbox v-model:checked="formState.remember">Remember me</a-checkbox>
    </a-form-item>

    <a-form-item :wrapper-col="{ offset: 8, span: 16 }">
      <a-button type="primary" html-type="submit">Submit</a-button>
    </a-form-item>
  </a-form>
</template>

  • 在页面中的使用 setup方式
<script setup>
import { reactive } from "vue";

const formState = reactive({
  username: "",
  password: "",
  remember: true,
});

const onFinish = (values) => {
  console.log("Success", values);
};

const onFinishFailed = (errorInfo) => {
  console.log("Failed:", errorInfo);
};
</script>

  • script方式JS内容
<script>
import { defineComponent, reactive } from 'vue';
export default defineComponent({
  setup() {
    const formState = reactive({
      username: '',
      password: '',
      remember: true,
    });

    const onFinish = values => {
      console.log('Success:', values);
    };

    const onFinishFailed = errorInfo => {
      console.log('Failed:', errorInfo);
    };

    return {
      formState,
      onFinish,
      onFinishFailed,
    };
  },

});
</script>

对比后即可发现,setup语法糖形式代码行数明显减少,更加清晰明了,易于阅读

2.3 setup语法糖中使用TypeScript

  • 在使用ts时,在script setup标签中增加lang="ts"
  • 内容中ts与正常使用情况下一致
  • 将上述js改为ts形式如下
<script setup lang="ts">
import { reactive } from "vue";

interface FormState {
  username: string;
  password: string;
  remember: boolean;
}

const formState = reactive<FormState>({
  username: "",
  password: "",
  remember: true,
});

const onFinish = (values: any) => {
  console.log("Success", values);
};

const onFinishFailed = (errorInfo: any) => {
  console.log("Failed:", errorInfo);
};
</script>

3. setup与普通的script同时使用

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

  • 声明无法在<script setup>中声明的选项。例如inheritAttrs或插件的自定义选项
  • 声明模块的具名导出
  • 运行系需要在模块作用域执行一次的副作用,或是创建单例对象
<script>
// 普通 <script>, 在模块作用域下执行 (仅一次)
runSideEffectOnce()

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

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

4. 限制

由于模块执行语义的差异,<script setup>中的代码依赖单文件组件的上下文。当将其移动到外部的.js 或者 .ts文件中的时候,对于开发者和工具来说都会感到混乱。因此<script setup>不能和src属性一起使用。

如果有用,点个赞呗~

总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值