一、创建Vue3工程
1、使用Vite创建工程
// 创建工程
npm init vite-app <project-name>
// 进入工程目录
cd <project-name>
// 安装依赖
npm install
// 运行
npm run dev
二、Vue3中的响应式
1、setup函数
在vue3中不再像vue2一样需要多个配置项组合(选择式API),换了一种方式把所有的都放到setup中,setup相当于就是一个大舞台,把所有的配置项都往里面写
setup函数有两种返回值:1、返回一个对象 2、返回一个渲染函数,
export default {
name: 'App',
setup() {
const name = '张三'
const age = 18
return {
name,
age,
}
}
}
因为setup中访问不到vue2中的属性方法(但2可访问3),如果混用的话,有重名setup优先。
2、ref函数
作用:定义响应式数据
import { ref } from 'vue'
const name = ref('张三')
const age = ref(18)
在js中操作数据:count.value
ref定义数据类型可以是对象也可以是其他复杂一点的,操作时都要 .value
const person = ref({name: 'zzy', age: 18})
person.value.name = 'ktton'
3、reactive函数
作用:定义一个对象类型的响应式数据(基本数据类型用ref就可以了)
import { reactive } from 'vue'
const person = reactive({name: 'zzy', age: 18})
person.name = 'ht'
接收一个对象或数组,返回一个代理对象(Proxy对象),且这里的监视式深层次监视
Vue3相当于Vue2减少了this操作,不用干什么都要先this指向再进行操作
4、vue3中响应式的原理
对于ref和reactive是不一样的,ref简单类型是通过:Object.defineProperty()的get与set,当然啊,ref定义的复杂类型是通过reactive的Proxy,
而reactive是通过Proxy来实现响应式的(上文提到了),并通过Reflect来操作源数据
不管怎么样,总结来说,vue3中新增的就是对于复杂数据类型通过Proxy实现响应式,也就是两个点: 1、通过 Proxy(代理): 拦截对象中任意属性的变化, 包括:属性的增删、属性值的读写等。
2、通过Reflect(反射):对源对象进行上述操作
(1)Vue2响应式原理
vue2是通过Object.defineProperty()对对象类型数据进行getter setter来监视数据,但是问题也随之而来,直接的去进行新增属性、删除属性界面不会更新,直接通过下标修改数组,界面也不会更新
(2)Vue3中的Proxy
在vue3中解决了vue2中的两个问题
let person ={
name:'crt',
age :18
}
const p = new Proxy(person,{
get(target,propName){
console.log(`有人读到了这些数据`,target,propName);
// target 是读取到传入的数据
// propName 是读取到的是谁
return target[propName]
},
set(target,propName,value){
// set修改
console.log(`有人修改了person中的${propName},修改后的值为:${value}`);
target[propName] = value
},
deletePropenrty(target,propName){
console.log(`有人删除了person中的${propName}`);
return delete target[propName]
}
})
要是想要更加严谨一些,可以通过Reflect来进行增珊改查,就不需要去捕获错误(让框架少报红)
let person ={
name:'crt',
age :18
}
const p = new Proxy(person,{
get(target,propName){
console.log(`有人读到了这些数据`,target,propName);
// target 是读取到传入的数据
// propName 是读取到的是谁
// return target[propName]
return Reflect.get(target,propName)
},
set(target,propName,value){
// set修改
console.log(`有人修改了person中的${propName},修改后的值为:${value}`);
// target[propName] = value
return Reflect.set(target,propName)
},
deletePropenrty(target,propName){
console.log(`有人删除了person中的${propName}`);
// return delete target[propName]
return Reflect.deleteProperty(target,propName)
}
})
5、reactive和ref的区别
1、定义数据类型不同
ref用于定义基本数据类型(也可以定义复杂类型)
reactive用于定义对象或数组类型
2、原理不同
ref是通过:`Object.defineProperty()`的get与set,当然啊,复杂类型是通过reactive的Proxy
reactive是通过Proxy来实现响应式的(上文提到了),并通过Reflect来操作源数据
3、使用方式不同
ref定义的数据,操作时需要.value,模板读取不需要.value
reactive定义的数据,操作和读取都不需要.value
6、setup的两个注意点
(1)执行时机
setup函数的执行时机是在beforeCeate之前,在所有生命周期的最前面,这个时候this的指向是undefined,所有setup里面不能使用this来访问组件实例
(2)setup参数
setup接收两个参数:(props,context) props是一个对象,包含:组件外部传递过来,且组件内部声明接收了的属性。 context是一个对象,包含三个属性,分别是attrs、slots、emit 第一个attrs相当于this.slots,包含收到的插槽的内容。 第三个emit相当于this.$emit,用来触发组件的自定义事件。
props: ['name', 'age']
setup(props, context) {
console.log(props) // Proxy{name:'ktton',age:18}:组件外部传递过来,且组件内部声明接收了的属性。
console.log(context.attrs)//相当于this.$attrs
console.log(context.slots)相当于this.$slots
console.log(context.emit)//相当于this.$emit
}
三、计算属性和监视
1、computed函数
功能跟vue2没什么区别,就是变成了一个函数,还要手动引入。写法是传一个回调
import {computed} from 'vue'
setup(){
let fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
}
如果想要修改计算属性,需要通过get/set的写法来进行修改
import {computed} from 'vue'
setup(){
let fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
}
2、watch函数
跟vue2的功能一样,就换了个写法
基本数据:
<template lang="">
<h2>当前求和:{{sum}}</h2>
<h2>信息:{{msg}}</h2>
<button @click="sum++">点我+1</button>
<h2>工作:{{person.job.type}}</h2>
<h2>薪水:{{person.job.salary}}</h2>
<button @click="person.job.type+='!'">点击修改</button>
</template>
<script>
import {ref,reactive,watch} from 'vue'
export default {
name:'App',
setup(){
let sum = ref(0)
let msg = ref('hello')
const person = reactive({
name :"crt",
age :18,
job:{
type:'IT',
salary: '10K'
}
})
一、监视参数
(1)监听ref定义响应式数据
// watch监听
watch(sum,(newValue,oldValue)=>{
console.log(`值进行了变化`,oldValue,newValue); //监听单个ref响应数据
})
(2)监听多个ref定义数据
//监听多个ref数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum值或msg进行变化',newValue,oldValue)
},{immediate:true}) //立即监听
(3)监听reactive定义的响应式数据
监听reactive数据的问题:
1、第一个是reactive
定义的数据,监视时回调中无法获得oldValue
!oldValue和new一样
2、第二个是,监视reactive
定义的数据,默认开启的deep:true
,且deep
不能改成false
// 监听reactive数据
watch(person,(newValue,oldValue)=>{
console.log('发生了变化',newValue,oldValue);
},{immediate:true})
(4)监听reactive定义数据中的某个属性(指定)
这里要注意,第一个参数必须写成箭头函数,如果直接写person.job
,那么就相当于写了个死的值,这样是监视不到的。还有就是如果job
是一个对象,那么默认deep
是false
的,如果要深度监视需要手动开启deep:true
(deep配置有效)
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
(5)监听reactive定义中的某些属性(一些)
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true})
二、如果我是使用ref去定义对象数据类型那么我监视的时候要不要写.value
import {ref,reactive,watch} from 'vue'
export default {
name:'App',
setup(){
let sum = ref(0)
let msg = ref('hello')
const person = ref({
name :"crt",
age :18,
job:{
type:'code',
salary: '100K'
}
})
//要的
是需要的,ref去定义对象之类的,其实根本就是去借组reactive的Proxy实现响应式的
//如果是监听person中的某一个属性就要写.value
watch(person.value,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不奏效
//如果是监视大体,person就不用写.value
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:true})
3、watchEffect函数
-
watch的套路是:既要指明监视的属性,也要指明监视的回调。
-
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
watchEffect(()=>{ const x1 = sum.value const x2 = person.age console.log('watchEffect配置的回调执行了') })
可以说wathcEffect可以通过监视多个不同的属性不像watch只能监听一个
四、自定义hook
Vue 3 中的自定义 Hook 是一个函数,用于在组件之间共享逻辑代码。如果多个组件都需要类似的数据获取、事件处理、状态更新等操作,可以将这些操作封装在一个自定义 Hook 中,从而提高代码复用性,减少重复代码。
//我把下面这些逻辑操作封装到hook里面,然后暴露出来
//然后让app直接调用封装好的名称就好了
export const p = new Proxy(person,{
get(target,propName){
console.log(`有人读到了这些数据`,target,propName);
// target 是读取到传入的数据
// propName 是读取到的是谁
// return target\[propName]
return Reflect.get(target,propName)
},
set(target,propName,value){
// set修改
console.log(`有人修改了person中的${propName},修改后的值为:${value}`);
// target\[propName] = value
return Reflect.set(target,propName)
},
deletePropenrty(target,propName){
console.log(`有人删除了person中的${propName}`);
// return delete target[propName]
return Reflect.deleteProperty(target,propName)
}
}
return p