1、简介
2020年9月18日,vue.js发布3.0版本,代号One Piece(海贼王)
2、vue3带来了什么
1、性能的提升
打包大小减少41%
初次渲染快55%,更新渲染快133%
内存减少54%
2、源码的升级
使用proxy代替defineProperty实现响应式
重写了虚拟Dom实现和Tree-shaking
3、拥抱了TypeScript
4、新的特性
1、 组合api compositionAPI
-
setup设置
-
ref与reactive
-
watch与watchEffect
-
provide与inject
2、新的组件内置 -
Fragment
-
Teleport
-
Suspense
3、其他改变
新的生命周期钩子
data选择应始终声明为一个函数
移除keycode支持作为v-on的修饰符
一、创建vue3.0工程
二、常用Composition API
1、初时setup
<template>
<!-- vue3的组件结构可以没有根标签 -->
<h1>我的个人信息</h1>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<button style="width:80px;height:40px;border-radius:5px" @click="sayHello">点击我</button>
</template>
<script>
export default {
name: 'App',
setup(){
let name='zhangjing'
let age =18
function sayHello(){
alert(`你好呀,我叫${name},年龄${age}`)
}
return {
name,
age,
sayHello
}
}
}
</script>
<template>
<h1>我的个人信息</h1>
<!-- <h2>{{name}}</h2>
<h2>{{age}}</h2> -->
<!-- <button style="width:80px;height:40px;border-radius:5px" @click="sayHello">点击我</button> -->
</template>
<script>
import {h} from 'vue'
export default {
name: 'App',
//此处只是测试setup暂时不考虑响应式的问题
setup(){
// let name='zhangjing'
// let age =18
// function sayHello(){
// alert(`你好呀,我叫${name},年龄${age}`)
// }
//返回一个对象(常用)
// return {
// name,
// age,
// sayHello
// }
//返回一个函数(渲染函数),将上面内容替换了
return ()=>
h('h2','我的名字')
}
}
</script>
<style>
</style>
此处没有展示我的个人信息字样
2、ref函数处理基本数据类型
控制台已经打印出数据,但是页面没变化
<template>
<h1>我的个人信息</h1>
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
export default {
name: "App",
setup() {
let name = "zhangjing";
let age = 18;
function addInfo(){
name='张静'
age=20
console.log(name,age)
}
return {
name,
age,
addInfo
};
},
};
</script>
<style>
</style>
<template>
<h1>我的个人信息</h1>
<!-- vue3解析发现name是ref对象,则自动的读取了value的值 -->
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
import {ref} from 'vue'
export default {
name: "App",
setup() {
//想把一个普通数据变成响应式,就必须使用ref
let name = ref("zhangjing")
let age = ref(18)
function addInfo(){
// name='张静'
// age=20
name.value='张静'
age.value=20
console.log(name,age)//引用实现的实例对象,简称引用对象
}
return {
name,
age,
addInfo
};
},
};
</script>
<style>
</style>
ref函数处理引用数据类型
<template>
<h1>我的个人信息</h1>
<!-- vue3解析发现name是ref对象,则自动的读取了value的值 -->
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
import {ref} from 'vue'
export default {
name: "App",
setup() {
//想把一个普通数据变成响应式,就必须使用ref
let name = ref("zhangjing")
let age = ref(18)
let job=ref({
type:'前端工程师',
salay:'30k'
})
function addInfo(){
// name.value='张静'
// age.value=20
// console.log(name,age)//引用实现的实例对象,简称引用对象
console.log(job)
console.log(job.value)
}
return {
name,
age,
addInfo
};
},
};
</script>
<style>
</style>
<template>
<h1>我的个人信息</h1>
<!-- vue3解析发现name是ref对象,则自动的读取了value的值 -->
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<h2>{{job.type}}</h2>
<h2>{{job.salay}}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
import {ref} from 'vue'
export default {
name: "App",
setup() {
//想把一个普通数据变成响应式,就必须使用ref
let name = ref("zhangjing")
let age = ref(18)
let job=ref({
type:'前端工程师',
salay:'30k'
})
function addInfo(){
// name.value='张静'
// age.value=20
// console.log(name,age)//引用实现的实例对象,简称引用对象
console.log(job)
console.log(job.value)
job.value.type='软件开发工程师'
job.value.salay='35k'
}
return {
name,
age,
addInfo,
job
};
},
};
</script>
<style>
</style>
3、reactive函数
<template>
<h1>我的个人信息</h1>
<!-- vue3解析发现name是ref对象,则自动的读取了value的值 -->
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<h2>{{job.type}}</h2>
<h2>{{job.salay}}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
name: "App",
setup() {
//想把一个普通数据变成响应式,就必须使用ref
let name = ref("zhangjing")
let age = ref(18)
let job=reactive({
type:'前端工程师',
salay:'30k'
})
function addInfo(){
// name.value='张静'
// age.value=20
// console.log(name,age)//引用实现的实例对象,简称引用对象
console.log(job)
// console.log(job.value)
// job.value.type='软件开发工程师'
// job.value.salay='35k'
job.type='后端开发工程师'
job.salay='36k'
console.log(job)
}
return {
name,
age,
addInfo,
job
};
},
};
</script>
<style>
</style>
对象嵌套对象也是可以监听到的
<template>
<h1>我的个人信息</h1>
<!-- vue3解析发现name是ref对象,则自动的读取了value的值 -->
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<h2>{{job.type}}</h2>
<h2>{{job.salay}}</h2>
<h2>{{job.a.b.c}}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
name: "App",
setup() {
//想把一个普通数据变成响应式,就必须使用ref
let name = ref("zhangjing")
let age = ref(18)
let job=reactive({
type:'前端工程师',
salay:'30k',
a:{
b:{
c:666
}
}
})
function addInfo(){
// name.value='张静'
// age.value=20
// console.log(name,age)//引用实现的实例对象,简称引用对象
console.log(job)
// console.log(job.value)
// job.value.type='软件开发工程师'
// job.value.salay='35k'
job.type='后端开发工程师'
job.salay='36k'
job.a.b.c=888
console.log(job)
}
return {
name,
age,
addInfo,
job
};
},
};
</script>
<style>
</style>
数组也可通过reactive变成响应式的
<template>
<h1>我的个人信息</h1>
<!-- vue3解析发现name是ref对象,则自动的读取了value的值 -->
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<h2>{{job.type}}</h2>
<h2>{{job.salay}}</h2>
<h2>{{job.a.b.c}}</h2>
<h2>{{hobby}}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
name: "App",
setup() {
//想把一个普通数据变成响应式,就必须使用ref
let name = ref("zhangjing")
let age = ref(18)
let job=reactive({
type:'前端工程师',
salay:'30k',
a:{
b:{
c:666
}
}
})
let hobby=reactive(['看书','听歌','旅游'])
function addInfo(){
// name.value='张静'
// age.value=20
// console.log(name,age)//引用实现的实例对象,简称引用对象
// console.log(job)
// console.log(job.value)
// job.value.type='软件开发工程师'
// job.value.salay='35k'
// job.type='后端开发工程师'
// job.salay='36k'
// job.a.b.c=888
// console.log(job)
console.log(hobby[0])
hobby[0]='看电影'
console.log(hobby[0])
}
return {
name,
age,
addInfo,
job,
hobby
};
},
};
</script>
<style>
</style>
<template>
<h1>我的个人信息</h1>
<h2>{{ person.name }}</h2>
<h2>{{ person.age }}</h2>
<h2>{{ person.job.type }}</h2>
<h2>{{ person.job.salay }}</h2>
<h2>{{ person.job.a.b.c }}</h2>
<h2>{{ person.hobby }}</h2>
<button @click="addInfo">点击修改我的信息</button>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
setup() {
let person = reactive({
name: "zhangjing",
age: "18",
job: {
type: "前端工程师",
salay: "30k",
a: {
b: {
c: 666,
},
},
},
hobby: ["看书", "听歌", "旅游"],
});
function addInfo() {
person.name = "张静";
person.age = 20;
person.job.type = "软件开发工程师";
person.job.salay = "35k";
person.job.a.b.c = 888;
person.hobby[0] = "看电影";
}
return {
person,
addInfo
};
},
};
</script>
<style>
</style>
点击后效果
4、模拟vue3中的响应式
实际上用的是reflect,封装框架友好
5、reactive对比ref
6、setup的两个注意点
第一个参数 setup里面的第一个参数props
attrs
<template>
<h1>我的个人信息</h1>
<h2>{{ person.name }}</h2>
<h2>{{ person.age }}</h2>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
// props:['msg','school'],
//setup只能收到两个参数
setup(props,context) {
console.log('------------',context)
console.log(context.attrs)
let person = reactive({
name: "zhangjing",
age: "18",
});
return {
person,
};
},
};
</script>
此时没有使用props,所以arrs里面有值
contxt.emit的使用
context.slots
7、computed计算属性
1、计算属性与监视
vue2的写法如下图所示,能实现,但不建议这么使用
Demo.vue
<template>
姓:<input v-model="person.firstName" />
<br />
名:<input v-model="person.lastName" />
<br/>
<span>全名:{{fullName}}</span>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
computed: {
//vue2中是可以用vue3中的属性的,要使用this
fullName() {
return this.person.firstName + this.person.lastName;
},
},
setup() {
let person = reactive({
firstName: "张",
lastName: "三",
});
return {
person,
};
},
};
</script>
App.vue
<template>
<Demo />
</template>
<script>
import Demo from "./components/Demo.vue";
export default {
components: { Demo },
name: "App",
};
</script>
下面是vue3的写法
Demo.vue
<template>
姓:<input v-model="person.firstName" />
<br />
名:<input v-model="person.lastName" />
<br/>
<span>全名:{{fullName}}</span>
</template>
<script>
import { reactive ,computed} from "vue";
export default {
name: "App",
// //vue2的用法,不建议使用
// computed: {
// //vue2中是可以用vue3中的属性的,要使用this
// fullName() {
// return this.person.firstName + this.person.lastName;
// },
// },
setup() {
//数据
let person = reactive({
firstName: "张",
lastName: "三",
});
//计算属性
let fullName=computed(()=>{
return person.firstName+person.lastName
})
return {
person,
fullName
};
},
};
</script>
App.vue
<template>
<Demo />
</template>
<script>
import Demo from "./components/Demo.vue";
export default {
components: { Demo },
name: "App",
};
</script>
vue3这么写,全名这个属性直接添加到person这个对象上,用的reative是响应式的可以直接追加
<template>
姓:<input v-model="person.firstName" />
<br />
名:<input v-model="person.lastName" />
<br />
<span>全名:{{ person.fullName }}</span>
</template>
<script>
import { reactive, computed } from "vue";
export default {
name: "App",
setup() {
//数据
let person = reactive({
firstName: "张",
lastName: "三",
});
//计算属性
//简写,没有考虑计算属性被修改的情况
person.fullName = computed(() => {
return person.firstName + person.lastName;
});
return {
person,
};
},
};
</script>
2、 watch函数的使用
App.vue
<template>
<Demo />
</template>
<script>
import Demo from "./components/Demo.vue";
export default {
components: { Demo },
name: "App",
};
</script>
Demo.vue
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<h2>当前信息为:{{ msg }}</h2>
<button @click="msg += '!'">修改信息</button>
<br />
<h2>{{ person.name }}</h2>
<h2>{{ person.age }}</h2>
<button @click="person.name += '!'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
<br />
<h2>薪水:{{ person.job.j1.salary }}k</h2>
<button @click="person.job.j1.salary++">涨薪水了</button>
</template>
<script>
import { ref, reactive, watch } from "vue";
export default {
name: "App",
//vue2的简单写法
// watch: {
// // sum(newValue, oldValue) {
// // console.log("sum的值变化了",newValue,oldValue);
// // },
// sum: {
// immediate: true, //立即监听
// deep:true,//深度监视,默认是浅层次的监视
// handler(newValue, oldValue) {
// console.log("sum的值变化了", newValue, oldValue);
// },
// },
// },
setup() {
let sum = ref(0);
let msg = ref("你好");
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
//vue3
// 情况一:监视ref所定义的一个响应式数据
// watch(sum, (newValue, oldValue) => {
// console.log("sum的值变化了", newValue, oldValue);
// },{immediate:true}); //第三个函数可以写immediate和deep
//情况二:监视ref所定义的多个响应式数据
// watch([sum, msg], (newValue,oldValue) => {
// console.log(newValue,oldValue);
// //[1,'你好'][0,'你好']
// },{immediate:true});
// 情况三:监视reactive所定义的一个响应式数据的全部属性,
// 注意:1、此处无法正确的获得oldValue,目前无法解决。
// 2、默认开启了深度监视(deep配置无效)
// watch(person, (newValue, oldValue) => {
// console.log("person变化了");
// console.log(newValue); //坑 新旧数据一样了欸
// console.log(oldValue);
// },{deep:false});//此处的deep配置无效
//情况四:监听reactive所定义的一个响应式数据中的某个属性(用函数形式)
// watch(()=>person.age,(newValue,oldValue)=>{
// console.log('person的age变化了',newValue,oldValue) //能拿到oldValue
// })
//情况五:监听reactive所定义的一个响应式数据中的某些属性
// watch([() => person.age, () => person.name], (newValue, oldValue) => {
// console.log("person的age或者变化了", newValue, oldValue);
// });
//特殊情况:层次比较深 注意:由于监视的是reactive所定义的对象中的某个属性,所以deep的配置有效(对比情况三监听对象的属性仍然是对象可以用deep)
// watch(()=>person.job,(newValue,oldValue)=>{
// console.log('person的job变化了',newValue,oldValue)
// },{deep:true}) //不能拿到oldValue
return {
sum,
msg,
person,
};
},
};
</script>
特殊情况:层级比较深得
watch中value值的问题
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<h2>当前信息为:{{ msg }}</h2>
<button @click="msg += '!'">修改信息</button>
<br />
<h2>{{ person.name }}</h2>
<h2>{{ person.age }}</h2>
<button @click="person.name += '!'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
<br />
<h2>薪水:{{ person.job.j1.salary }}k</h2>
<button @click="person.job.j1.salary++">涨薪水了</button>
</template>
<script>
import { ref, watch } from "vue";
export default {
name: "App",
setup() {
let sum = ref(0);
let msg = ref("你好");
let person = ref({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
console.log(sum);
console.log(msg);
console.log(person);
// //正确写法
// watch(sum, (newValue, oldValue) => {
// console.log("sum值变化了", newValue, oldValue);
// });
// //不对,检测是结构,不能检测0
// watch(sum.value, (newValue, oldValue) => {
// console.log("sum值变化了", newValue, oldValue);
// });
//监听不到---ref生成的对象,任何属性发生变化能捕获到,value是proxy对象,只有地址变化才能检测到,改变内层数据对象不变化
// watch(person, (newValue, oldValue) => {
// console.log("person值变化了", newValue, oldValue);
// });
//1、监听得到---监听实例对象的 。value属性是proxy实例对象,是reactive生成的,也就是说是reactive所定义的数据,是深层次的
// watch(person.value,(newValue, oldValue) => {
// console.log("person值变化了", newValue, oldValue);
// });
// 2、监听得到 person。value里面的内容能被监测到了
watch(person,(newValue, oldValue) => {
console.log("person值变化了", newValue, oldValue);
},{deep:true});
return {
sum,
msg,
person,
};
},
};
</script>
3、watchEffect函数
当前求和为:{{ sum }}
setup() {
let sum = ref(0);
let msg = ref(“你好”);
let person = reactive({
name: “张三”,
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// watch(person, (newValue, oldValue) => {
// console.log("person值变化了", newValue, oldValue);
// });
watchEffect(() => {
const x1 = sum.value;
const x2=person.job.j1.salary
console.log("watchEffect所指定的回调执行了",x1,x2);
});
return {
sum,
msg,
person,
};
},
};
8、vue3的生命周期
beforeDestory 和destoryed变为beforeUnmount和unmounted
App.vue
<template>
<button @click="isShow = !isShow">是否展示Demo</button>
<Demo v-if="isShow" />
</template>
<script>
import Demo from "./components/Demo.vue";
import { ref } from "vue";
export default {
components: { Demo },
name: "App",
setup() {
let isShow = ref(true);
return {
isShow,
};
},
};
</script>
Demo.vue
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
</template>
<script>
import { ref } from "vue";
export default {
name: "demoTest",
setup() {
let sum = ref(0);
return {
sum,
};
},
//通过配置项的形式使用生命周期钩子
beforeCreate() {
console.log("---beforeCreate---");
},
created() {
console.log("---created---");
},
beforeMount() {
console.log("---beforeMount---");
},
mounted() {
console.log("---mounted---");
},
beforeUpdate() {
console.log("---beforeUpdate---");
},
updated() {
console.log("---updated---");
},
beforeUnmount() {
console.log("---beforeUnmount---");
},
unmounted() {
console.log("---unmounted---");
},
};
</script>
同一个阶段生命周期的钩子,vue3的先执行
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
</template>
<script>
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onUnmounted,
onBeforeUnmount,
} from "vue";
export default {
name: "demoTest",
setup() {
console.log("--- setup ---");
let sum = ref(0);
//通过组合式API的方式去使用生命周期钩子
onBeforeMount(() => {
console.log("--- onBeforeMount ---");
}),
onMounted(() => {
console.log("--- onMounted ---");
}),
onBeforeUpdate(() => {
console.log("--- onBeforeUpdate ---");
}),
onUpdated(() => {
console.log("--- onUpdated ---");
}),
onUnmounted(() => {
console.log("--- onUnmounted ---");
}),
onBeforeUnmount(() => {
console.log("--- onBeforeUnmount ---");
});
return {
sum,
};
},
//#region
//通过配置项的形式使用生命周期钩子
// beforeCreate() {
// console.log("---beforeCreate---");
// },
// created() {
// console.log("---created---");
// },
// beforeMount() {
// console.log("---beforeMount---");
// },
// mounted() {
// console.log("---mounted---");
// },
// beforeUpdate() {
// console.log("---beforeUpdate---");
// },
// updated() {
// console.log("---updated---");
// },
// beforeUnmount() {
// console.log("---beforeUnmount---");
// },
// unmounted() {
// console.log("---unmounted---");
// },
//#endregion
};
</script>
9、自定义hook
Demo.vue
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<hr />
<h2>当前点击时鼠标的坐标为:x:{{ point.x }},y:{{ point.y }}</h2>
</template>
<script>
import { ref, reactive, onMounted, onBeforeUnmount } from "vue";
export default {
name: "demoTest",
setup() {
let sum = ref(0);
let point = reactive({
x: 0,
y: 0,
});
function savePoint(event) {
point.x = event.pageX;
point.y = event.pageY;
console.log(event.pageX, event.pageY);
}
onMounted(() => {
console.log("=");
window.addEventListener('click', savePoint);
});
onBeforeUnmount(() => {
console.log("777");
window.removeEventListener('click', savePoint);
});
return {
sum,
point,
};
},
};
</script>
App.vue
<template>
<button @click="isShow = !isShow">是否展示Demo</button>
<Demo v-if="isShow" />
</template>
<script>
import Demo from "./components/Demo.vue";
import { ref } from "vue";
export default {
components: { Demo },
name: "App",
setup() {
let isShow = ref(true);
return {
isShow,
};
},
};
</script>
使用hook可以这么写
// function savePoint(){
import { reactive, onMounted, onBeforeUnmount } from "vue";
export default function(){
//实现鼠标打点的相关数据
let point = reactive({
x: 0,
y: 0,
});
//实现鼠标打点的相关方法
function savePoint(event) {
point.x = event.pageX;
point.y = event.pageY;
console.log(event.pageX, event.pageY);
}
//实现鼠标打点的钩子
onMounted(() => {
console.log("=");
window.addEventListener('click', savePoint);
});
onBeforeUnmount(() => {
console.log("777");
window.removeEventListener('click', savePoint);
});
return point
}
// export default savePoint
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<hr />
<h2>当前点击时鼠标的坐标为:x:{{ point.x }},y:{{ point.y }}</h2>
</template>
<script>
import { ref } from "vue";
import usePoint from "../hooks/usePoint";
export default {
name: "demoTest",
setup() {
let sum = ref(0);
let point = usePoint();
return {
sum,
point
};
},
};
</script>
App.vue
<template>
<button @click="isShow = !isShow">是否展示Demo</button>
<Demo v-if="isShow" />
</template>
<script>
import Demo from "./components/Demo.vue";
import { ref } from "vue";
export default {
components: { Demo },
name: "App",
setup() {
let isShow = ref(true);
return {
isShow,
};
},
};
</script>
效果和上面的写法是一样的,可以对usePoint.js进行复用了
10、toRef
<template>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>薪水:{{ person.job.j1.salary }}k</h2>
<button @click="person.name += '!'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
<button @click="person.job.j1.salary++">涨薪水了</button>
</template>
<script>
import { reactive, toRef } from "vue";
export default {
name: "App",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
const name1 = person.name;
console.log("name1", name1);
const name2 = toRef(person, "name");
console.log("name2", name2);
return {
person,
name1,
name2,
};
},
};
</script>
toRef的使用方法
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪水:{{ salary }}k</h2>
<button @click="name += '!'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="salary++">涨薪水了</button>
</template>
<script>
import { reactive, toRef } from "vue";
export default {
name: "App",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// console.log("person", person);
// const name1 = person.name; //不是响应式的
// console.log("name1", name1);
// const name2 = toRef(person, "name"); //是响应式的,指的就是person中的name属性
// console.log("name2", name2);
return {
// person,
// name1,
// name2,
// name: ref(person.name),//如果这么写,初始化使用了张三,但修改时改的不是person对象里面的值
name: toRef(person, "name"),
age: toRef(person, "age"),
salary: toRef(person.job.j1, "salary"),
};
},
};
</script>
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪水:{{ salary }}k</h2>
<button @click="name += '!'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="salary++">涨薪水了</button>
</template>
<script>
import { reactive, toRef,toRefs } from "vue";
export default {
name: "App",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// console.log("person", person);
// const name1 = person.name; //不是响应式的
// console.log("name1", name1);
// const name2 = toRef(person, "name"); //是响应式的,指的就是person中的name属性
// console.log("name2", name2);
const x=toRefs(person)//把一个对象的所有属性都变成ref形式
console.log(x)
return {
// person,
// name1,
// name2,
// name: ref(person.name),//如果这么写,初始化使用了张三,但修改时改的不是person对象里面的值
name: toRef(person, "name"),
age: toRef(person, "age"),
salary: toRef(person.job.j1, "salary"),
};
},
};
</script>
toRefs的使用
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪水:{{ job.j1.salary }}k</h2>
<button @click="name += '!'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">涨薪水了</button>
</template>
<script>
import { reactive,toRefs } from "vue";
export default {
name: "App",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
return {
...toRefs(person)
};
},
};
</script>
三、其他的composition api
1、shallowReactive和shallowRef的使用
<template>
<h4>当前的x.y值是:{{ x.y }}</h4>
<button @click="x.y++">修改x的值</button>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪水:{{ job.j1.salary }}k</h2>
<button @click="name += '!'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">涨薪水了</button>
</template>
<script>
import { reactive, toRefs, shallowRef } from "vue";
export default {
name: "App",
setup() {
// let person = shallowReactive({//只考虑第一层数据的响应式
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// let x = ref(0);
// let x=shallowRef(0)//是基本数据类型时无差别
let x = shallowRef({//shallowRef处理对象值不好使,ref可以
y: 0,
});
console.log(x)
return {
x,
...toRefs(person),
};
},
};
</script>
<template>
<h4>当前的x.y值是:{{ x.y }}</h4>
<button @click="x.y++">修改x的值</button>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪水:{{ job.j1.salary }}k</h2>
<button @click="name += '!'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">涨薪水了</button>
</template>
<script>
import { reactive, toRefs, ref } from "vue";
export default {
name: "App",
setup() {
// let person = shallowReactive({//只考虑第一层数据的响应式
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// let x = ref(0);
// let x=shallowRef(0)//是基本数据类型时无差别
let x = ref({//shallowRef处理对象值不好使,ref可以
y: 0,
});
console.log(x)
return {
x,
...toRefs(person),
};
},
};
</script>
2、readonly与shallowReadonly
person这个数据不能改
person第一层的数据不能改
数据可能是别人传递的
3、 toRaw和markRaw
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪水:{{ job.j1.salary }}k</h2>
<h2 v-show="person.car">座驾信息:{{person.car}}</h2>
<button @click="name += '!'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">涨薪水了</button>
<button @click="addCar">配一台车</button>
<button @click="person.car.name+='?'">换车名</button>
<button @click="person.car.price++">换价格</button>
</template>
<script>
import { reactive, toRefs,markRaw} from "vue";
export default {
name: "App",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
function addCar(){
let car ={name:'奔驰',price:'18'}
// person.car=car //这里添加的信息会自动变成响应式的
person.car=markRaw(car)//car永远不会成为响应式数据了,但是数据改了,只不过页面不显示而已
console.log(person)
}
return {
person,
...toRefs(person),
addCar
};
},
};
</script>
4、customRef
<template>
<input type="text" v-model="keyWord" />
<h3>{{ keyWord }}</h3>
</template>
<script>
import { customRef } from "vue";
export default {
name: "App",
setup() {
// let keyWord = ref('hello');//使用vue提供的ref
// 自定义一个ref, 名为myRef;
function myRef(value, delay) {
let timer;
console.log("---", value);
return customRef((track, trigger) => {
//customRef定义要传入一个函数,要返回一个对象
return {
get() {
console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`);
track(); //通知vue追踪value的变化(提前和get商量了一下,让其认为value是有用的)
return value;
},
set(newValue) {
console.log(`有人把myRef这个容器中的数据改为了${newValue}`);
clearTimeout(timer);
timer = setTimeout(() => {
value = newValue;
trigger(); //通知vue去重新解析模板
}, delay);
},
};
});
}
let keyWord = myRef("hello", 500);
return {
keyWord,
};
},
};
</script>
5、provide与inject
祖组件传值,后代组件可以接收值
6、响应式数据的判断
四、compositionAPI的优势
五、新的组件
1、Fragment组件
2、Teleport
3、suspense
这么写的话 ,蓝色组件会受到settimeout的影响
(网速慢或者说用promise都能出现加载中这个效果)
六、其他
https://www.bilibili.com/video/BV1Zy4y1K7SH?p=168&vd_source=c2279a533bc837e2d5b9ca3570c0a841
视频观看笔记