Vue3新语法
1、data数据
1.1 响应式区别
Vue2中响应式是通过defineProperty实现的。
Vue3中响应式是通过ES6的Proxy实现的。
Vue3中实现响应式提供了ref和reactive两个组合式API。
1.2 ref和reactive的区别
ref特点
-
ref的参数一般是基本数据类型,也可以是对象类型
-
如果参数是对象类型,其实底层的本质还是reactive,系统会自动将ref转换为reactive,例如
ref(1) ===> reactive({value:1})
-
ref包括的数据,要访问内容需要用.value属性,在模板中使用的时候,系统会自动帮我们添加
.value
,在JS中访问ref中的数据,需要手动添加.value
-
ref的底层原理同reactive一样,都是Proxy
<template> <h1>{{ name }}</h1> <h1>{{ age }}</h1> </template> <script> import { ref} from 'vue' export default { name: 'App', setup () { //定义简单数据 const name = ref('frank') const age = ref(18) //定义方法 const handleChange = () => { name.value = 'mike' age.value = 20 } //暴露给模板 return { name, age, handleChange } } } </script>
reactive特点
-
reactive的参数一般是对象或者数组,他能够将复杂数据类型变为响应式数据。
-
reactive的响应式是深层次的,底层本质是将传入的数据转换为Proxy对象
import { reactive } from 'vue' export default { name: 'App', setup () { //定义复杂数据 const user = reactive({ name: 'frank', age: 18 }) //定义方法 const handleChange = () => { user.name = 'mike' user.age = 20 } //暴露给模板 return { user, handleChange } } }
2、method方法
定义变量指向一个箭头函数即可,可以在模板中调用该方法。
//方法定义 const addFn = () => { count.age++ }
3、计算属性
通过computed()方法创建计算属性。方法参数是一个箭头函数。
只读的计算属性
const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) //2
可写的计算属性
const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0
4、监听器
https://cn.vuejs.org/guide/essentials/watchers.html#basic-example
检测某个变量值的变化,变化后执行对应的逻辑代码。
与监听器相关的方法watch(),watchEffect(),watchPostEffect(),watchSyncEffect()
4.1 watch()
侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
https://cn.vuejs.org/api/reactivity-core#watch
监听一个getter函数,当函数返回值变化的时候,触发方法执行
const state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } )
//数据定义 const person = reactive({ name: 'san xiaogui', chineseName: [ '小王', '小陈' ] }) //变更方法 const changeNameFn = () => { person.name = '1111'; } //监听器 watch(() => { return person.name; }, (value, oldValue) => { console.log(oldValue) console.log(value) }, {deep: true})
监听一个ref
const count = ref(0) watch(count, (count, prevCount) => { /* ... */ })
4.2 watchEffect()
立即运行一个函数,同时响应式地追踪相关的依赖数据,并在依赖更改时重新执行。
const count = ref(0) watchEffect(() => console.log(count.value)) // -> 输出 0 count.value++ // -> 输出 1
4.3 区别
1.watch是惰性执行的,而watchEffect不是,不考虑watch第三个配置参数的情况下,watch在组件第一次执行的时候是不会执行的,只有在之后依赖项变化的时候再执行,而watchEffect是在程序执行到此处的时候就会立即执行,而后再响应其依赖变化执行。 2.watch需要传递监听的对象,watchEffect不需要
监听器创建时会返回方法引用,如果要停止监听,则需要通过调用该引用停止监听。
const stopWatch = watchEffect(() => console.log(count.value)) //停止 stopWatch()
5、生命周期
Vue2的钩子函数都是组件选项,Vue3提供了组合API的使用方式,组件选项方式是保留的。
//原Created内要执行的代码 console.log('HelloWorld Created') //生命周期函数 onMounted(() => { console.log('HelloWorld mounted') })
6、子组件定义
setup组件内必须通过defineProps,defineEmits,defineExpose进行声明。
<script setup> import {defineProps, defineEmits, defineExpose, reactive} from 'vue' // 定义接收属性:defineProps const props = defineProps({ name: { type: String, required: true }, age: Number }) // 定义触发父组件方法的事件:defineEmits const emit = defineEmits(['change', 'delete']) const subValue = reactive({ name: '1111', age: 12 }) const showDialogFn = (a) => { console.info('显示对话框', a) } function deleteHandler() { emit('delete', 'aaa') } // 对外公开的属性和方法:defineExpose defineExpose({ subValue, showDialogFn }) </script> <template> <!--显示传入数据--> <p>Child1 - name: {{ props.name }}, age: {{ props.age }}</p> <!--调用外部方法--> <button @click="$emit('change', 'bbb')">change</button> <!--调用外部方法--> <button @click="deleteHandler">delete</button> <slot></slot> </template>
7、父子组件交互
<script setup> import {ref, reactive, computed, onMounted, watch, watchEffect, getCurrentInstance} from 'vue' //导入子组件,无需注册,就可以直接使用。 import child from '@/components/child.vue' //获取子组件的引用(名称和组件的ref属性值相同),可以用来调用子组件公开的方法和属性 const childRef = ref(null) const person = reactive({ name: '志瑞', age: 43 }) //方法定义,绑定子组件的事件 const changeFn = () => { console.info('通过子附件调用父组件方法changeFn') } //方法定义,绑定子组件的事件 const deleteFn = () => { console.info('通过子附件调用父组件方法deleteFn') } //通过引用调用子附件的方法和属性 const invokeChild = () => { console.info('调用子组件') childRef.value.showDialogFn('123'); console.info(childRef.value.subValue); } </script> <template> <div class="card"> <!--给字符串传入属性,并绑定emit事件处理函数--> <child ref="childRef" :name="person.name" :age="person.age" @change="changeFn" @delete="deleteFn"> <div>Slot的内容</div> </child> <div> <button @click="invokeChild">调用子组件</button> </div> </div> </template> <style scoped> .read-the-docs { color: #888; } </style>
8、组件导入
同vue2的组件导入方法