初学vue
1、vue3中计算属性computed的基本使用
功能和vue2中的一样,只是写法上有些许区别,但vue3目前仍可以使用vue2中的写法,不过不推荐。
vue3中计算属性的使用具体看例子,不赘述了
<template>
姓:<input type="text" v-model="person.firstName">
<br>
名:<input type="text" v-model="person.lastName">
<br>
<span>全名:{{person.fullName}}</span>
<br>
直接修改计算属性计算出的全名:<br>
<input type="text" v-model="person.fullName">
</template>
<script>
// 引入计算属性的组合API
import {reactive,computed} from "vue"
export default {
name:"ComputedTest",
setup(){
// 定义一个数据(对象类型)
let person = reactive({
firstName:"张",
lastName:"三"
})
// 计算属性
// 简写形式(这样就没有考虑计算属性被修改的情况
// person.fullName = computed(()=>{
// return person.firstName + "-" + person.lastName
// })
// 完整写法(这样可以对计算属性进行读写操作
person.fullName = computed({
get(){
return person.firstName + "-" + person.lastName
},
set(value){
const nameArr = value.split("-") // 按照”-“拆分全名
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
return {
person
}
},
}
</script>
2、vue3中监视属性watch的基本使用
2.1 监视ref定义的数据
vue3中watch和vue2中的使用方式很相似。
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我加1</button>
<hr>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg+='!'">添加感叹号</button>
</template>
<script>
// 引入ref的组合API
import {ref,watch} from "vue"
export default {
name:"WatchTest01",
setup(){
let sum = ref(0)
let msg = ref("你好呀")
// 情况一:监视ref所定义的一个响应式数据
watch(sum,(newValue,oldValue)=>{
console.log("sum变了",newValue,oldValue)
})
// 传入第三个参数{immediate:true},用于页面刷新后立即监视
// watch(sum,(newValue,oldValue)=>{
// console.log("sum变了",newValue,oldValue)
// },{immediate:true})
// 情况二:监视ref所定义的多个响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log("sum或msg变了",newValue,oldValue);
})
// 返回一个对象
return {
sum,
msg
}
}
}
</script>
<style>
</style>
关于watch监视ref定义的数据是否要用到
.value
的问题:
(1)当ref定义的是一个基本数据类型时,如下:<h2>当前求和为:{{sum}}</h2> <button @click="sum++">点我加1</button> ---------------------------------------------------------- let sum = ref(0) watch(sum,(newValue,oldValue)=>{ console.log("sum的值改变了",newValue,oldValue) })
分析:watch这里第一个参数必须是sum而不能是sum.value,因为ref中定义的是一个基本类型数据,如果用sum.value的话,就相当于直接监视0这个数字,而使用sum的话就是在监视sum这个结构,打印出sum,
console.log(sum)
,可以看到结果是一个refImpl对象,而这个对象下就包括value值,所以要监视整个sum。
(2)当ref定义的是一个引用数据类型时,如下:<h3>姓名:{{person.name}}</h3> <h3>年龄:{{person.age}}</h3> <h3>薪资:{{person.job.salary}}</h3> <button @click="person.name += '!'">修改姓名</button> <button @click="person.age += 1">增长年龄</button> <button @click="person.job.salary += 3">涨薪</button> ----------------------------------------------------------- let person = ref({ name:"张三", age:18, job:{ salary:20 } }) // 第一种方式实现监视到对象中的所有属性 watch(person.value,(newValue,oldValue)=>{ console.log("person中的属性改变了”,newValue,oldValue) }) // 第二种方式实现监视到对象中的所有属性 watch(person,(newValue,oldValue)=>{ console.log("person中的属性改变了”,newValue,oldValue) },{{deep:true}})
分析:如果这里不使用这两种方式来对对象进行监视,那么就无法起到监视效果。
- 对于方式一,利用的是使用ref对引用类型进行定义时,底层会自动转换成reactive函数对对象进行定义,那么此时
console.log(person)
可以看到结果如下,person是一个refimpl对象
- 对于方式二,直接利用{{deep:true}}配置项进行深度监视,监视的时person.value,当person.value下面的数据发生改变时,深度监视到就会立即更新页面。
2.2 监视reactive定义的数据
<template>
<h3>姓名:{{person.name}}</h3>
<h3>年龄:{{person.age}}</h3>
<h3>薪资:{{person.job.salary}}</h3>
<button @click="person.name += '!'">修改姓名</button>
<button @click="person.age += 1">增长年龄</button>
<button @click="person.job.salary += 3">涨薪</button>
</template>
<script>
import {reactive,watch} from "vue"
export default {
name:"WatchTest02",
setup(){
let person = reactive({
name:"张三",
age:18,
job:{
type:"前端工程师",
salary:15
}
})
// 监视reactive中的数据
// 情况一:监视reactive所定义的一个响应式数据的全部属性
// 1、此处无法正确的获取oldValue
// 2、reactive的监视是强制深度监视,关不了
/*
watch(person,(newValue,oldValue)=>{
console.log("person变化了",newValue,oldValue)
},{deep:false}) // 此处的deep配置无效
*/
// 情况二:监视reactive所定义的一个响应式数据中的某个属性
/*
watch(()=>person.name,(newValue,oldValue)=>{
console.log("person变化了",newValue,oldValue)
})
*/
// 情况三:监视reactive所定义的一个响应式数据中的某些属性
/*
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
console.log("person中的name或age变化了",newValue,oldValue)
})
*/
// 情况四:监视reactive所定义的对象中的某个属性(如果这个属性依然是个对象),那么deep配置有效
watch(()=>person.job,(newValue,oldValue)=>{
console.log("person的job属性变化了",newValue,oldValue)
},{deep:true}) // 此处deep配置有效
return {
person
}
}
}
</script>
2.3 watchEffect函数
- watch的套路是既要指名监视的属性,也要指明监视的回调
- watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
- watchEffect有点像computed:
- 区别在于computed注重的是计算出来的值(回调函数的返回值),所以必须要写返回值
- 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
<template>
<h3>姓名:{{person.name}}</h3>
<h3>年龄:{{person.age}}</h3>
<h3>薪资:{{person.job.salary}}</h3>
<button @click="person.name += '!'">修改姓名</button>
<button @click="person.age += 1">增长年龄</button>
<button @click="person.job.salary += 3">涨薪</button>
</template>
<script>
import {reactive,ref,watchEffect} from "vue"
export default {
name:"WatchTest02",
setup(){
let sum = ref(0)
let person = reactive({
name:"张三",
age:18,
job:{
type:"前端工程师",
salary:15
}
})
watchEffect(()=>{
// watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调
// 使用sum和person对象中的age
const x1 = sum.value
const x2 = person.age
console.log("watchEffect配置的回调执行了!",x1,x2)
})
return {
sum,
person
}
}
}
</script>
可以看到只有在watchEffect中用到的对象才会被监视到,并且页面刷新时watchEffect就会自动执行一次
3、Vue3生命周期
和vue2的区别
(1)和vue2一样,主要是8个生命周期钩子,但有两个钩子又和vue2不一样,vue3将vue2中的beforeDestroy和destroyed换成了beforeUnmounte和unmounted
(2)在创建组件对象时,vue2是直接new Vue(),之后是走一步算一步,哪里需要挂载东西再挂载东西,例如会进行对象上是否有el的判断,没有则自动挂载上,;而vue3是Vue.create(option).mount(el),直接把需要的东西准备好,甚至提前把el直接挂载到对象上。
两种方式使用生命周期钩子
- 第一种方式:通过配置项的形式使用生命周期钩子
setup(){ ... }, beforeCreate(){......}, created(){......}, beforeMounted(){......}, mounted(){......}, beforeDestroy(){......}, destroyed(){......}, beforeUnmounted(){......}, unmounted(){......}
- 第二种方式:通过组合式API的形式去使用生命周期钩子(也就是将生命周期钩子放到setup配置项中)
// 引入API import {} from "vue" -------------------- setup(){ ...... onBeforeMounted(()=>{...}) onMounted(()=>{...}) onBeforeDestroy(()=>{...}) onDestroyed(()=>{...}) onBeforeUnmounted(()=>{...}) onUnmounted(()=>{...}) }
注意点:
(1)原来vue2中的beforeDestroy和destroyed不能使用,取而代之的是beforeUnmounted和unmounted
(2)将生命周期钩子放到setup配置项中时,需要注意生命周期钩子的形式变了,并且不支持beforeCreate和created写入setup中,因为setup会在这两个钩子执行之前执行.
(3)如果同时使用了这两中方式,那么会有执行先后顺序问题,写在setup中的钩子的优先级会更高,例如:onBeforeMounted会比BeforeMounted先执行。(建议只是用其中一种方式)
4、自定义hook函数
- 定义
本质是一个函数,把setup函数中使用的CompositionAPI进行了封装,类似于vue2中的mixin。 - 优势
可以复用代码,让setup中的逻辑更加清楚易懂
例如,实现这么一个功能,鼠标点击屏幕,显示鼠标点击时的坐标。
如果只是一个人要用到这个功能,那么这个功能就可以直接写在组件中,如下:
<template>
<h1>鼠标点击屏幕,显示鼠标点击时的坐标</h1>
<h2>鼠标横坐标:{{point.x}}</h2>
<h2>鼠标纵坐标:{{point.y}}</h2>
</template>
<script>
import { reactive,onMounted,onBeforeUnmount} from "vue"
export default {
name:"HookTest",
setup() {
// 定义变量:表示点的坐标
const point = reactive({
x:0,
y:0
})
// 定义函数:获取坐标
function usePoint(event){
point.x = event.pageX
point.y = event.pageY
console.log("横坐标:"+ point.x,"纵坐标:"+ point.y);
}
// 在onMounted钩子中给window绑定事件
onMounted(() => {
window.addEventListener("click",usePoint)
})
// 在onBeforeUnmount钩子中给window解绑事件
onBeforeUnmount(()=>{
window.removeEventListener("click",usePoint)
})
// 返回一个对象
return {
point
}
}
}
</script>
如果想要让这个功能做到随引随用,那么可以使用自定义hook函数进行封装,如下:
- src/hooks/usePoint.js
import {reactive,onMounted,onBeforeUnmount} from "vue"
export default function usePoint(){
// 定义变量:表示点的坐标
const point = reactive({
x:0,
y:0
})
// 定义函数:获取坐标
function usePoint(event){
point.x = event.pageX
point.y = event.pageY
console.log("横坐标:"+ point.x,"纵坐标:"+ point.y);
}
// 在onMounted钩子中给window绑定事件
onMounted(() => {
window.addEventListener("click",usePoint)
})
// 在onBeforeUnmount钩子中给window解绑事件
onBeforeUnmount(()=>{
window.removeEventListener("click",usePoint)
})
// 返回一个获取到的对象
return point
}
- HookTest.vue
<template>
<h1>鼠标点击屏幕,显示鼠标点击时的坐标</h1>
<h2>鼠标横坐标:{{point.x}}</h2>
<h2>鼠标纵坐标:{{point.y}}</h2>
</template>
<script>
// 引入hook函数
import usePoint from "../hooks/usePoint"
export default {
name:"HookTest",
setup() {
// 调用hook函数
const point = usePoint()
// 接收usePoint()方法return过来的对象
// 返回point对象
return {
point
}
}
}
</script>
通过hook函数,无论哪个组件想要使用这个功能,那么只需要引入并调用即可