大家好!我叫椰_季,是一个刚入行不久得前端工程师,本着在提升自我学习能力为前提和认识一些前端方面得朋友为主要任务。准备发布一篇自己学习vue3.0基础语法的总结。学习途径来源于B站张天禹老师。
我们先来说一说vue2.0存在的一些缺陷,大家都知道vue2.0中数据的代理方式是使用的defineProperty来实现响应式的。那么defineProperty存在什么样的问题呢
不能监听数组的变化
必须遍历对象的每个属性
必须深层遍历嵌套的对象
1、数据规模是否庞大。创建Vue实例的时候,一旦对象是一个深层的引用(老千层饼了),递归进行Observer的创建显然会花很多时间;
2、对所有属性的变化进行监听,也需要消耗不小的内存;
3、新增/删除属性的时候,怎么调用/卸载defineProperty;
4、vue2的官方文档,对开发者说明了defineProperty的一些限制,比如说数组在两种情况下是无法监听的:
1、利用索引直接设置一个数组项时,例如:arr[indexOfItem] = newValue;
2、修改数组的长度时,例如:arr.length = newLength;
当我们的项目需求变得更复杂时,watch,computed,inject,provide等配置,这个.vue文件也会逐渐增大
以上图片来源于花果山大圣,具体了解v2的option以及v3的composition,参考大圣这篇文章
1、setup是Vue3.0中一个新的配置项,值为一个函数,setup是所有Composition API(组合API)表演的舞台
2、组件中所用到的:数据、方法等等,均要配置在setup中
3、若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用
此处需要将setup 中定义的值 return 返回出去,模板中才能使用
4、setup的一些注意点:
1、在vue3中是可以继续使用vue2中的语法的,但是官方不推荐这样使用。
2、Vue2.x配置(data、methos、computed...)中可以访问到setup中的属性、方法。但在setup中不能访问到Vue2.x配置(data、methos、computed...)。
3、如果有重名, setup优先。
4、setup执行的时机,在beforeCreate之前执行一次,this是undefined
5、setup的参数:
props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
context:上下文对象
attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 `this.$attrs`
slots: 收到的插槽内容, 相当于 `this.$slots`
emit: 分发自定义事件的函数, 相当于 `this.$emit`
作用:定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
语法:const 代理对象 = reactive(源对象)接收一个对象(或数组),对象(proxy对象)
reactive定义的响应式数据是 深层次的
内部基于ES6的 Proxy实现,通过代理对象操作源对象内部数据进行操作
`
//reactvie处理对象是深层次的
let job2 = reactive({
type:'php',
salary:'40k'
})
let hobby = reactive(['吃饭','睡觉','写代码'])
function change(){
// name.value = "李四"
// age.value = 20
// job.value.type = "java工程师"
// job.value.salary = "30k"
// // 如果创建的对象是通过reactive创建的,那么修改直接通过对象.里面的属性就好,不需要像ref那样 多加一层.value
// job2.type = "go开发"
// job2.salary = "60k"
// console.log(name,age,job.value);
// 在vue3中 可以直接通过 这样修改
hobby[0] = '学习'
}
`
从定义数据角度对比:
reactive
转为代理对象。从原理角度对比:
Object.defineProperty()
的get
与set
来实现响应式(数据劫持)。从使用角度对比:
.value
,读取数据时模板中直接读取不需要.value
。.value
。与Vue2.x中computed配置功能一致
`
import { reactive, computed } from “vue”;
setup() {
let person = reactive({
name: “张三”,
finame: “狂徒”,
});
// 计算属性的简写形式,是只读的没有考虑修改
// person.quanc = computed(() => {
// return person.name + “-” + person.finame;
// });
person.quanc = computed({
get() {
// 用户读取数据
return person.name + “-” + person.finame;
},
set(value) {
// 这里获取的value是有 - 的 通过截取-将值拆分成数组,然后再进行 索引的第0 和第 1 个获得对应的姓 和名
const qwe = value.split(“-”);
person.name = qwe[0];
person.finame = qwe[1];
},
});
return {
person,
};
},
`
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变化了',newValue,oldValue)
})
/* 情况三:监视reactive定义的响应式数据
若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效
//情况四:监视reactive定义的响应式数据中的某个属性
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
//情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
如果都是利用ref创建的,利用watch来监视的话。基本类型的值 直接在第一个参数内传入定义的变量名。
如果是对象类型的话:
一、可以在变量名的后方加上.value 那么v3中他内部会借助reactive 来实现深层次监听。
二、可以不添加.value ,可以在第三个参数内加上deep:true也可以开启深度监听
watch的套路是:既要指明监视的属性,也要指明监视的回调
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那么它就监视哪个属性
watchEffect有点像computed:
但是computed注重的是计算出来的值(回调函数的返回值),所以必须要写返回值
而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值
import { ref, watch, reactive, watchEffect } from "vue";
setup() {
let qwe = ref(0);
let www = ref("你哈");
let person = reactive({
name: "张三",
age: 18,
fn: {
j1: {
st: 20,
},
},
});
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(() => {
let f1 = qwe.value;
let f2 = person.fn.j1.st;
console.log("haha");
});
return {
qwe,
www,
person,
};
},
}
setup(){
//数据
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
const x = toRefs(person)
console.log('******',x)
//返回一个对象(常用)
// 一般我们要将响应式对象中的某个属性单独提供给外部使用时使用toRef
return {
person,
// name:toRef(person,'name'),
// age:toRef(person,'age'),
// salary:toRef(person.job.j1,'salary'),
...toRefs(person)
}
}
}
Fragment
Teleport
我是一个弹窗
```
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
```
我是App组件
加载中.....
学习是一辈子的事,不光指学习计算机技术,生活的方方面面都需要保持一个学习的心,祝大家学习愉快。
第一次总结写文章,文中如有错误,欢迎码友在评论区指正。