vue3的变化
1:v-if和v-for的优先级被更改,但还是不推荐一起使用
2:组件的事件要在emits选项中声名
3:destroyed生命周期(销毁)重命名为unmounted
4:自定义指令的apl已经更改与生命周期一致
5:新增三个组件:Fragment支持多个根节点,Suspense可以在组件渲染之前的等待时间显示指定内容,Teleport可以让子组件能够在视觉上跳出父组件
6:新增v-memo,可以换成html模板,比如v-for列表不会变化就缓存,(内存换时间)
7:用proxy代替object.defineProperty,可以监听数组下的变化,以及对象新增属性
8:重构虚拟DOM,在编译时会将事件缓存,将slot编译为lazy,保存静态节点直接复用,以及添加静态标记,Diff算法使用最长递增子序列优化对比流程,使得虚拟DOM生成速度变快
9:在里使用v-bind,给css绑定js变量(如color:v-bind(str))
10:新增Composition API(组合式API)可以更好的逻辑复用和代码组织
11:全局函数set和delete以及实例方法delete移除
12:off,$once实例方法被移除,组件实例不再实现事件触发接口
模板的引入
<template>
<Cjy></Cjy>
</template>
<script setup lang="ts">
import Cjy from './components/Cjy.vue'
</script>
响应式数据
ref()和reactive()
直接 let x=20 这样的数据不是响应式的,必须用ref包装一下
ref()和reactive()的区别 ref多用于基础数据类型 reactive多用于复杂数据类型
<template>
<div>
TSY组件{{num}}
<p>{{objref.x}}</p>
<button @click="num++">++</button>
<button @click="hdclick">++</button>
<button @click="hdclickobj">++</button>
<p ref="op">asd</p>
<p>{{obj2re.y}}</p>
</div>
</template>
<script lang="ts">
import { nextTick,defineComponent,ref,Ref,reactive,toRefs} from 'vue'
export default defineComponent({
setup(){
// ref响应式
//let num = 20;这样子定义的数据不是响应式数据(做不到双向数据绑定)
let num:Ref<number>= ref(20);//用ref包起来,这个num是vue内部封装的一个响应式数据
// num是给包装过后的对象,num.value才能拿到20这个数据
// 所以要操作这个响应式数据需要使用 .value
//模板是还是继续使用{{num}}
const hdclick=()=>{
num.value++
}
// 对复杂数据的响应式
// ref()和reactive()的区别;ref要 .value.值 ,reactive直接 .值
// 应用场景 ref()多用于基础数据类型,reactive用于复杂数据类型
let obj={
x:0
}
let objref=ref(obj)
const hdclickobj=()=>{
objref.value.x++
}
let obj2={
y:1
}
let obj2re=reactive(obj2)
console.log(obj2re.y);
// 解构:toRefs的作用就是reactive的对象解构从响应式数据
let {y}=toRefs(obj2re)
console.log(y);
// 获取DOM
let op =ref();
// onMounted(()=>{
// console.log(op.value);
// })
nextTick(()=>{
console.log(op.value);
})
return{
// 定义的方法和数据向外暴露,否则模板是访问不到
num,
objref,
hdclick,
hdclickobj,
op,
obj2re
}
},
})
</script>
数据监听wacth,watchEffect
// 基础数据类型
let x=ref(0);
watch(x,(oldvla,newval)=>{
console.log(oldvla);
console.log(newval);
})
//复杂数据类型
let obj={
num:0
}
let {num}=toRefs(reactive(obj));
watch(num,(oldvla,newval)=>{
console.log(oldvla);
console.log(newval);
})
/ num是解构出来的的可以这样监听,如果没有解构出来呢
// 方式一
watch(()=>objerf.num,(oldvla,newval)=>{
console.log(oldvla);
console.log(newval);
})
// 方式二
watch([()=>objerf.num],(oldvla,newval)=>{
console.log(oldvla);
console.log(newval);
})
// watchEffect,在页面刷新时就触发,立即触发
watchEffect(()=>{
// 凡是写在这里的数据,只要发送变化,就会被立即监听
console.log(num.value);
console.log(x.value);
console.log(objerf.num);
})
计算属性
计算属性分为只读的和可写的
import {toRefs,ref,computed,reactive} from "vue"
// 计算属性
let num=ref(20)
//创建一个只读的计算属性
let numx=computed(()=>{
return num.value*2
})
let obj={
x:0
}
let {x}=toRefs(reactive(obj))
let objx=computed(()=>{
return x.value*3
})
//可写计算属性
const refx = computed({
get:():number=>{
// ! ! ! 注意get一定要有返回值
return x.value
},
set:(val)=>{
x.value=val;
}
})
// 访问触发get
refx.value
// 改值,触发set
refx.value=5;
console.log(x.value);//5
父子组件通信
父传子
父组件
<template>
<h1>父组件</h1>
<!-- 父传子,直接通过自定义属性传值 -->
<Son :num="num"></Son>
</template>
<script setup lang="ts">
import Son from "./Son.vue"
import {ref} from "vue"
let num = ref(10)
</script>
子组件
<template>
<h1>子组件{{ num }}</h1>
</template>
<script setup lang="ts">
import { ref, defineProps } from "vue";
let x=ref(0)
//用defineProps接收
defineProps({
num:{
type:Number,//类型
default:30//默认值
}
})
</script>
子传父 子组件
<template>
<h1>子组件</h1>
<button @click="getdata">传</button>
</template>
<script setup lang="ts">
import { ref} from "vue";
let x=ref(20);
// 先定义事件
const emit=defineEmits<{
(event:'getfun',id:number):void
}>()
const getdata=()=>{
// 之前是$emit('自定义事件',参数)
emit('getfun',x.value)
}
</script>
父组件
<template>
<h1>父组件</h1>
<Son @getfun="getdata"></Son>
</template>
<script setup lang="ts">
import Son from "./Son.vue"
// 接收
const getdata=(id:number)=>{
console.log(id);
}
</script>