目录
1、setup的两个注意点
- setup执行的时机
- 在beforeCreate之前执行一次,this是undefine
- setup的参数
- props:值为对象,包含:组件外部传递过来,且组件内部声明接受了的属性。
- context:上下文对象
- attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于this.$attrs
- slots:收到插槽的内容,相当于this.$slot,使用具名插槽时可用v-slot:名字
- emit:分发自定义事件的函数,相当于this.$emit
2、计算属性与监听
- 与Vue2.x中computed配置功能一样
- 写法
import { reactive,computed } from 'vue';
setup () {
// 数据
let person = reactive({
firstName: '张三',
lastName: 18
})
// 计算属性--简写(没有考虑计算属性被修改的情况)
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
}
}
3、watch函数
- 与Vue2.x中watch配置功能一致
- 两个小“坑”
- 监视reactive定义的响应式数据时:oldValue无法正确获取,强制开启了深度监视(deep配置时效)
- 监视reactive定义的相应式数据中某个属性时:deep配置有效
// 数据
let sum = ref(0)
let msg = ref('你好啊')
let person = reactive({
name: '张三',
age: 18,
job: {
j1: {
salary: 20
}
}
})
// 情况一:监视ref所定义的一个响应式数据,第三个参数配置属性
watch(sum, (newValue, oldValue) => {
console.log('sum变了', newValue, oldValue)
}, { immediate: true })
// 情况二:监视ref所定义的多个响应式数据
watch([sum, msg], (newValue, oldValue) => {
console.log('sum或msg变了', newValue, oldValue)
}, { immediate: true })
/* 情况三:监听reactive所定义的一个响应式数据的全部属性
1、注意:此处无法正确的获得oldValue
2、注意:强制开启了深度监视(deep配置无效)
*/
watch(person, (newValue, oldValue) => {
console.log(newValue, oldValue)
}, { deep: false })//此处的deep配置无效
//情况四:监视reactive所定义的一个响应式数据中的某个属性
watch(() => person.age, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
// 情况五:监视reactive所定义的一个响应式数据中的某些属性
watch([() => person.name, () => person.age], (newValue, oldValue) => {
console.log(newValue, oldValue)
})
// 特殊情况
watch(() => person.job, (newValue, oldValue) => {
console.log('person的job变化了', newValue, oldValue)
}, { deep: true })//此处由于监视的是reactive定义的对象中的某个属性,所以deep配置有效
如果对象是ref传对象类型,要注意一些差异
ref取值要.value
let person = ref({
name: '张三',
age: 18,
job: {
j1: {
salary: 20
}
}
})
//针对基础类型
watch(sum, (newValue, oldValue) => {
console.log('sum的值变化了', newValue, oldValue)
})
//如果不使用deep,可以使用person.value,但是person.value监视的就不再是refImpl,而是person.value下的reactive实例
watch(person, (newValue, oldValue) => {
console.log('person的值变化了', newValue, oldValue)
}, { deep: true })
4、watchEffect函数
- watch的套路是:既要指明监视的属性,也要指明监视的回调。
- watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
- watchEffect有点像computed:
- 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值
- 但watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
5、Vue3生命周期
- Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有两个被更名:
- beforeDestory改名为beforeUnmount
- destory改名为unmounted
- Vue3.0也提供了Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
- beforeCreate======> setup()
- created===========>setup()
- beforeMount=======>onBeforeMount
- mounted==========>onMounted
- beforeUpdate======>onBeforeUpdate
- updated==========>onUpdated
- beforeUnmount=====>onBeforeUnmount
- unmounted========>onUnmounted
6、自定义hook函数
- 什么是hook?——本质是一个函数,把setup函数中使用的Compoistion API进行了封装。
- 类似于vue2.x中的mixin。
- 自定义hook的又优势:复用代码,让setup中的逻辑更清楚易懂。
7、toRef
- 作用:创建一个ref对象,其value值指向另一个对象中的某个属性。
- 语法:const name = toRef(person,'name')。
- 应用:要将响应式对象中的某个属性单独提供给外部使用。
- 扩展:toRefs和toRef功能一致,但可以批量创建多个Ref对象,语法toRefs(person)
- 实例:
<template>
<div>
<h4>{{ person }}</h4>
<h4>姓名:{{ name }}</h4>
<h4>年龄:{{ age }}</h4>
<h4>薪资:{{ job.j1.salary }}</h4>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="job.j1.salary++">修改薪资</button>
</div>
</template>
<script>
import { ref, reactive, toRef, toRefs, shallowReactive } from "vue";
export default {
name: "Test",
setup() {
// let person = shallowReactive({
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
return {
person,
...toRefs(person),
};
},
};
</script>
<style>
</style>
8、组件基础
- props :单项传递,尽量不要直接修改props的属性,最好存到computed下使用
- $emit :点击子组件触发父组件的方法,可以将子组件的数据传递给父组件
Home.vue(父组件)
<Son @enlarge-text="changeText"
title="My journey with Vue" />
Son.vue(子组件)
<button @click="$emit('enlargeText',{age:'12',name:'123'})">
Enlarge text
</button>
- emits : 允许我们检查组件抛出的所有事件,事件触发前进行验证
emits: {
enlargeText: ({ age, name }) => {
console.log(age, "年龄")
console.log(name, '姓名')
}
},
- $event :父组件访问子组件抛出的值
父组件
<Son @enlarge-text="postFontSize+=$event"
title="My journey with Vue" />
子组件
<button @click="$emit('enlargeText',0.1)">
Enlarge text
</button>
- 自定义事件 v-model
默认情况下,组件上的 v-model
使用 modelValue
作为 prop 和 update:modelValue
作为事件。我们可以通过向 v-model
传递参数来修改这些名称:
<my-component v-model:title="bookTitle"></my-component>
在本例中,子组件将需要一个 title
prop 并发出 update:title
事件来进行同步:
app.component('my-component', {
props: {
title: String
},
emits: ['update:title'],
template: `
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)">
`
})
- 插槽
- 具名插槽 ----> v-slot="name"或者用简写 “#name”,默认是#default或v-slot:default
- 异步引入组件
components: {
Son: defineAsyncComponent(() =>
import('@/components/Son.vue')
)
},
9、自定义指令
- 动态指令
<div id="dynamicexample">
<h3>Scroll down inside this section ↓</h3>
<p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
const app = Vue.createApp({
data() {
return {
direction: 'right'
}
}
})
app.directive('pin', {
mounted(el, binding) {
el.style.position = 'fixed'
// binding.arg 是我们传递给指令的参数
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
}
})
app.mount('#dynamic-arguments-example')
动态指令的函数简写
app.directive('pin', (el, binding) => {
el.style.position = 'fixed'
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
})
vue3后组件可能会有多个根节点。当被应用在一个多根节点的组件上时,指令会被忽略,并且会抛出一个警告。