一. 概述
在Vue2
时期,组件里定义的各类变量、方法、计算属性等是分别存放到data
、methods
、computed
等选项里,这样编写的代码不便于后期的查阅,查找一个业务逻辑需要在各个选项来回切换。vue3.0
组合式APIsetup
函数的推出就是为了解决这个问题,它让我们的逻辑关注点更加集中,语法也更加精简,但是当我们在使用vue3.0
的语法就构建组件的时候,总是需要把外面定义的方法变量必须要return出去才能在<template>
,比较麻烦一些. vue3.2
语法糖的出现以及一些新增的API,让我们的代码进一步简化。【学习视频分享:vue视频教程、web前端视频】
什么是语法糖?
语法糖(英语:Syntactic sugar)是由英国计算机科学家彼得·兰丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。
(资料图片)
Vue3.2
语法糖
来看下vue3.0
与vue3.2
的单文件组件(SFC,即.vue 文件)的结构对比
vue3.0
组件<template> <div> </div></template><script>export default { components: { }, props: { }, setup () { return {} }}</script><style scoped></style>
vue3.2
组件<template> <MyTestVue :title="title" @click="changeTitle" /></template><script setup>import MyTestVue from "./MyTest.vue";import { ref } from "vue";const title = ref("测试一下")const changeTitle = () => { title.value = "Hello,World"}</script><style scoped></style>
对比vue3.0
与vue3.2
版本的组件模板,最主要的变化是3.2中没有了setup
函数,而是把它放在了script标签中。
我们定义的属性和方法也不用在return中返回,直接就可以用在模板语法中...
这些是直观的变化,接下来我们学习具体的用法。
二.使用介绍
1.组件注册
vue3.0
中使用组件,需要使用 components 选项来显式注册:
<script>import ComponentA from "./ComponentA.js"export default { components: { ComponentA }, setup() { // ... }}</script>
vue3.2
<script setup>
的单文件组件中,导入的组件可以直接在模板中使用,组件会自动注册,并且无需指定当前组件的名字,它会自动以文件名为主,也就是不用再写name属性了。
<script setup>import ComponentA from "./ComponentA.vue"</script><template> <ComponentA /></template>
2.Props 声明
在vue3.0
中,prop
可以使用props
选项来声明
<script>export default { props: ["foo"], // 或者用这种方式指类型与默认值 // props: { // foo:{ // type: String, // default: "" // }, // }, setup(props) { // setup() 接收 props 作为第一个参数 console.log(props.foo) }}</script>
vue3.2
组件中,props
可以使用defineProps()
宏来声明
<script setup>const props = defineProps(["foo"])// 或者const propsOther = defineProps({ title: String, likes: Number})console.log(props.foo)</script>
注意事项:所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递,这意味着你不应该在子组件中去更改一个 prop。
3.计算属性
我们一般使用计算属性来描述依赖响应式状态的复杂逻辑。说白了就是这个计算属性的值依赖于其他响应式属性的值,依赖的属性发生变化,那么这个计算属性的值就会进行重新计算。
<script setup>import { ref, computed } from "vue"const firstName = ref("John")const lastName = ref("Doe")const fullName = computed({ // getter get() { return firstName.value + " " + lastName.value }, // setter set(newValue) { // 注意:我们这里使用的是解构赋值语法 [firstName.value, lastName.value] = newValue.split(" ") }})</script>
当调用fullName.value = "John Doe"
时,setter
会被调用,而firstName
和 lastName
会被更新,在vue3.2
中我们可以直接在<template>
标签中使用它,不在需要return返回。
4. watch
在组合式API中,我们可以使用watch
函数在每次响应式状态发生变化时触发回调函数,watch
的第一个参数可以是不同形式的“数据源”:它可以是一个ref
(包括计算属性)、一个响应式对象、一个 getter
函数、或多个数据源组成的数组:watch()
是懒执行的:仅当数据源变化时,才会执行回调,例如:
<script setup>import { ref,watch } from "vue";const props = defineProps({ title: String, itemList: { type: Array, default: () => [{ text: "title", value: 0 }] }})watch(() => props.itemList.length,(newValue,oldValue) => { console.log("newValue===",newValue); console.log("oldValue===",oldValue);})</script>
这里监听props.itemList.length
,当传入的itemList
数量发生变化时,后面的回调方法会被调用。当然wacth()
还有第三个可选参数:否开启深监听(deep)
, 如果这里这样写:
<script setup>import { ref,watch } from "vue";...watch(() => props.itemList,(newValue,oldValue) => { console.log("newValue===",newValue); console.log("oldValue===",oldValue);})</script>
当传入的itemList
数量发生改变时,回调函数不会触发,正确的写法是加上其第三个参数deep:true
<script setup>import { ref,watch } from "vue";...watch(() => props.itemList,(newValue,oldValue) => { console.log("newValue===",newValue); console.log("oldValue===",oldValue);},{deep:true})</script>
watch
也可以同时监听多个属性:
<script setup>import { ref,watch } from "vue";const props = defineProps({ title: String, itemList: { type: Array, default: () => [{ text: "title", value: 0 }] }})// 同时监听多个属性watch(() => [props.itemList,props.title],(newValue,oldValue) => { console.log("newValue===",newValue); console.log("oldValue===",oldValue);},{deep:true}) </script>
5. watchEffect()
与watch()
的懒执行不同的是,watchEffect()
会立即执行一遍回调函数,如果这时函数产生了副作用,Vue
会自动追踪副作用的依赖关系,自动分析出响应源。上面的例子可以重写为:
<script setup> ...watchEffect(() => { console.log("itemList===",props.itemList.length); console.log("title===",props.title);})</script>
这个例子中,回调会立即执行。在执行期间,它会自动追踪props.itemList.length
作为依赖(和计算属性的行为类似)。每当传入的itemList.length
变化时,回调会再次执行。
如果要清除watchEffect()
的的监听,只需要显示的调用watchEffect()
的返回函数就可以了,例如:
<script setup> ...const stopEffect = watchEffect(() => { console.log("itemList===",props.itemList.length); console.log("title===",props.title);})stopEffect()</script>
watch 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。我们能更加精确地控制回调函数的触发时机。watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。
6.组件的事件调用
6.1 子组件调用父组件的方法
vue3.0
中如果我们的子组件触发父组件的方法,我们的做法:
子组件<script>export default { emits: ["inFocus", "submit"], setup(props, ctx) { ctx.emit("submit",params) }}// 或者将可以将emit解构使用export default { setup(props,{emit}) { emit("submit",params) }}</script>父组件<template> <Children @submit="submitHandel"/> </div></template><script>export default { name: "TodoItem", setup(props, { emit }) { const submitHandel = () => { console.log("子组件调用了父组件的submitHandel方法"); } return { submitHandel, } }};</script>
vue3.2
语法糖中,子组件要触发的事件需要显式地通过 defineEmits()
宏来声明
子组件<script setup>const emit = defineEmits(["inFocus", "submit"])function buttonClick(parmas) { emit("submit", parmas)}</script>父组件<template> <Children @submit="submitHandel"/> </div></template><script setup> const submitHandel = () => { console.log("子组件调用了父组件的submitHandel方法"); }};</script>
6.2 父组件调用子组件的方法或是属性
vue3.0
中如果父组件触发子组件的方法或是属性,直接在return函数中返回就可以,数据都是默认隐式暴露给父组件的。
<script>// 子组件setup(props, { emit }) { const isShow = ref(false) // 父组件调用这个方法 const showSubComponent = () => { isShow.value = !isShow.value } return { // return 返回 showSubComponent, } }</script>
父组件中通过ref
获取到子组件,并对子组件暴露的方法进行访问
父组件<template> <div class="todo-list"> <TodoItemVue :itemList="itemList" @clickItemHandel="clickItemHandel" ref="todoItemVueRef" /> </div></template><script> import { ref } from "vue"; export default { setup(props, { emit }) { //获取子组件ref const todoItemVueRef = ref(null) // 调用子组件的方法 const callItemFuncHandel = () => { todoItemVueRef.value.showSubComponent() } return { todoItemVueRef } }};</script>
vue3.2
语法中,父组件的调用方式相同,子组件通过defineExpose()
将方法或是属性暴露出去
子组件<script setup>const isShow = ref(false)// 父组件调用这个方法const showSubComponent = () => { isShow.value = !isShow.value}// 通过defineExpose将方法暴露出去defineExpose({ showSubComponent})</script> 父组件<template> <div class="todo-list"> <TodoItemVue :itemList="itemList" @clickItemHandel="clickItemHandel" ref="todoItemVueRef" /> </div></template><script setup> import { ref } from "vue"; //获取子组件ref const todoItemVueRef = ref(null) // 调用子组件的方法 const callItemFuncHandel = () => { todoItemVueRef.value.showSubComponent() }</script>
7.Vuex的使用
在vue3.0
与vue3.2
中创建Vuex
没有区别,只不过在<template>
模板中使用Vuex的store
有细微差别。
import { createStore } from "vuex";import { ADD_ITEM_LIST, REDUCE_ITEM_LIST, CHANGE_ITEM_LIST_ASYNC } from "./constants";export default createStore({ state: { itemList: [ { text: "Learn JavaScript", done: true }, { text: "Learn Vue", done: false }, { text: "Build something awesome", done: false }, ], }, getters: { doneItemList: (state) => state.itemList.filter((todo) => todo.done), }, mutations: { // 使用ES2015风格的计算属性命名功能 来使用一个常量作为函数名 [ADD_ITEM_LIST](state, item) { console.log("增加数据", item); state.itemList.push(item); }, [REDUCE_ITEM_LIST](state) { console.log("减少数据"); state.itemList.pop(); }, }, actions: { [CHANGE_ITEM_LIST_ASYNC]({ commit, state }, todoItem) { /// 模拟网络请求 setTimeout(() => { commit(ADD_ITEM_LIST, todoItem); console.log("state===", state); }, 1000); }, }, modules: { },});
在vue3.0
中我们一般在return中对store.state
进行解构,然后可以直接在<template>
中使用state
中的值
<template> <div class="todo-item"> <ol> <li v-for="(item,index) in itemList" :key="index" class="todos" @click="clickItem(index)"> {{ item.text }} </li> </ol> </div></template><script> export default { name: "TodoItem", setup(props, { emit }) { return { // 对store.state进行解构 ...store.state, clickItem, count, isShow, showSubComponent, } }};</script>
vue3.2
中没有了return,需要我们显示的获取要使用的stare
的值
<template> <div class="todo-item"> <ol> <li v-for="(item,index) in itemList" :key="index" class="todos" @click="clickItem(index)"> {{ item.text }} </li> </ol> </div></template><script setup>import { useStore } from "vuex";const store = useStore()// 获取后在<template>中使用const itemList = store.state.itemList</script>
8. <style>
中的 v-bind
<style>
中的 v-bind
: 用于在 SFC <style>
标签中启用组件状态驱动的动态 CSS 值
<script setup>import { ref, watchEffect } from "vue";const color = ref("black")const callChangeColorHandel = () => { if(color.value === "black") { color.value = "red" }else { color.value = "black" }}</script><style lang="scss" scoped>.todo-list { color: v-bind(color);}</style>
触发callChangeColorHandel
函数,在<style>
中的v-bind
指令可以动态绑定的响应式状态。
三. 总结
整体来说,setup语法糖的引入简化了使用Composition API
时冗长的模板代码,也就是让代码更加简洁,可读性也更高。并且官方介绍vue3.2
在界面渲染的速度以及内存的使用量上都进行了优化,本文只是对setup语法糖的常用方式进行了总结,更多vue3.2
新特性可以去官方文档查看。
(学习视频分享:web前端开发、编程基础视频)
以上就是什么是语法糖?Vue3.2中怎么使用语法糖?的详细内容,更多请关注php中文网其它相关文章!