setup函数
- 从组件生命周期来看,它的执行在组件实例创建之前
beforeCreate执行。 - 这就意味着在
setup函数中this还不是组件实例,this此时是undefined - 在模版中需要使用的数据和函数,需要在
setup返回。
<template>
<div class="container">
<h1 @click="say()">{{msg}}</h1>
</div>
</template>
<script>
export default {
setup () {
console.log('setup执行了')
// 这输出undefined
console.log(this)
// 定义数据和函数
const msg = 'vue3'
const say = () => {
console.log(msg)
}
return { msg , say}
},
beforeCreate() {
console.log('beforeCreate执行了')
console.log(this)
}
}
</script>
setup的注意点
- setup执行的时机
- 在beforeCreate之前执行一次,this是undefined。
- setup的参数
- props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
- context:上下文对象
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
this.$attrs。 - slots: 收到的插槽内容, 相当于
this.$slots。 - emit: 分发自定义事件的函数, 相当于
this.$emit
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
官方文档中是这样写的
cn.vuejs.org/api/composi…
传入 setup 函数的第二个参数是一个 Setup 上下文对象。上下文对象暴露了其他一些在 setup 中可能会用到的值:
export default { setup(props, context) {
// 透传 Attributes(非响应式的对象,等价于 $attrs)
console.log(context.attrs)
// 插槽(非响应式的对象,等价于 $slots)
console.log(context.slots)
// 触发事件(函数,等价于 $emit)
console.log(context.emit)
// 暴露公共属性(函数)
console.log(context.expose) } }
该上下文对象是非响应式的,可以安全地解构:
export default {
setup(props, { attrs, slots, emit, expose }) {
...
}
}
总结: setup 组件初始化之前执行,它返回的数据和函数可在模版使用。
ref函数
- 作用: 定义一个响应式的数据
- 语法:
const xxx = ref(initValue)- 创建一个包含响应式数据的引用对象。
- JS中操作数据:
xxx.value - 模板中读取数据: 不需要.value,直接:
<div>{{xxx}}</div>
- 备注:
- 接收的数据可以是:基本类型、也可以是对象类型。
- 基本类型的数据:响应式依然是靠
Object.defineProperty()的get与set完成的。 - 对象类型的数据:内部 “ 求助 ”了Vue3.0中的一个新函数——
reactive函数。
<template>
<div class="container">
<div>{{name}}</div>
<div>{{age}}</div>
<button @click="updateName">修改数据</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
name: 'App',
setup () {
// 1. name数据
const name = ref('lin')
console.log(name)
const updateName = () => {
name.value = 'chen'
}
// 2. age数据
const age = ref(10)
// ref常用定义简单数据类型的响应式数据
// 其实也可以定义复杂数据类型的响应式数据
// 对于数据未之的情况下 ref 是最适用的
return {name, age, updateName}
}
}
</script>
使用场景:
- 当你明确知道需要的是一个响应式数据对象那么就使用 reactive 即可
- 其他情况使用ref
reactive函数
- 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用
ref函数) - 语法:
const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象 - reactive定义的响应式数据是“深层次的”。
- 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。
<template>
<div class="container">
<p>{{ obj.name }}</p>
<p>{{ obj.age }}</p>
<h1 @click="updateName()">点击更新</h1>
</div>
</template>
<script>
import { reactive } from '@vue/reactivity'
export default {
setup() {
const obj = reactive({
name: 'Code小叔',
age: 18
})
// 定义一个修改名字的方法
const updateName = () => {
obj.name = '我更新啦'
}
// 一定要记得return出去喔
return { obj, updateName }
}
}
</script>
reactie和ref对比
- 从使用角度对比:
- ref定义的数据:操作数据需要
.value,读取数据时模板中直接读取不需要.value。 - reactive定义的数据:操作数据与读取数据:均不需要
.value。
- ref定义的数据:操作数据需要
toRef和toRefs
举个栗子🌰
此处toRef可以从对象里,取出任意属性,变成响应式数据,没有取出的数据则将丢失响应式,当点击按钮的话也就不会随之变化
<template>
<button @click="change">有变化了</button>
</template>
<script setup lang="ts">
import { toRef } from 'vue'
const Preson = {
first: 1,
second: 2
}
const state = toRef(Preson, 'second')
const change = () => {
state.value++
console.log(Preson, state)
}
</script>
桥豆麻袋,相信看到这里,聪明的小朋友应该猜到
toRefs怎么用了,没错不要怀疑,就是你想的那样!
toRefs会帮我们批量的生成响应式的ref对象
<template>
<button @click="change">有变化了</button>
</template>
<script setup lang="ts">
import { reactive, toRefs } from 'vue'
const Preson = reactive({
first: 1,
second: 2
})
const { first, second } = toRefs(Preson)
const change = () => {
first.value++, second.value++
console.log(first, second)
}
</script>
watch函数
第一个参数:需要监听的源对象
第二个参数:回调函数callBack(newVal,oldVal)
第三个参数:options配置项是一个对象{ immediate:true //是否立即调用一次 deep:true //是否开启深度监听 }
const obj = reactive({
name: 'Code小叔',
age: 18,
job: {
demo1: {
salary: 10000
}
}
})
watch(obj, (newValue, oldValue) => {
console.log('watch触发', newValue, oldValue)
})
监听对象中的某个值
watch(() => obj.name,(newValue, oldValue) => {
console.log('watch触发', newValue, oldValue)
}
)
只监听子属性
watch(() => ({ ...obj }),(newValue, oldValue) => {
console.log('watch触发', newValue, oldValue)
}
)
监听多个数据
其中有任意一个数据变化都会触发监听
const demoNumer = ref(1)
const obj = reactive({
name: 'Code小叔',
age: 18
})
watch([() => obj.age, demoNumer],([newValue, oldValue], [numNew, numOld]) => {
console.log('watch触发', newValue, oldValue)
console.log('demoNumer触发', numNew, numOld)
}
)
⭐⭐⭐⭐⭐
如果你想初始化就执行一次监听,那么就用到了
{ immediate: true }
watch(obj,(newValue, oldValue) => {
console.log('watch触发', newValue, oldValue)
},{ immediate: true }
)
组件传参
传值
<template>
<div class="container">
<HelloWorld :money="sonData"></HelloWorld>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
import { ref } from 'vue'
export default {
setup() {
const sonData = ref(100)
return { sonData }
},
components: { HelloWorld }
}
</script>
<template>
<div>
<p>我是子组件</p>
<p>{{ money }}</p>
</div>
</template>
<script>
export default {
props: {
money: {
type: Number,
default: 0
}
},
setup(props) {
// 获取父组件中的money
console.log(props.money)
return {}
}
}
</script>
传事件
<template>
<div class="container">
<HelloWorld :money="sonData" @change-emit="emitMoney"></HelloWorld>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
import { ref } from 'vue'
export default {
setup() {
const sonData = ref(100)
const emitMoney = (newMoney) => {
sonData.value = newMoney
}
return { sonData, emitMoney }
},
components: { HelloWorld }
}
</script>
<template>
<div>
<p>我是子组件</p>
<p>{{ money }}</p>
<button @click="changeMoney">点击修改金额</button>
</div>
</template>
<script>
export default {
props: {
money: {
type: Number,
default: 0
}
},
setup(props, { emit }) {
// 获取父组件中的money
// 解构emit 触发自定义事件的函数
console.log(props.money)
const changeMoney = () => {
emit('change-emit', 2000)
}
return { changeMoney }
}
}
</script>
provide 与 inject
<template>
<div class="container">
<p>{{ sonData }}</p>
<HelloWorld></HelloWorld>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
import { provide, ref } from 'vue'
export default {
setup() {
const sonData = ref(100)
const emitMoney = (newMoney) => {
sonData.value = newMoney
}
// 将数据提供给后代组件
provide('money', sonData)
provide('changeMoney', emitMoney)
return { sonData }
},
components: { HelloWorld }
}
</script>
<template>
<div>
<p>我是子组件</p>
<p>{{ money }}</p>
<button @click="emitMoney">点击修改金额</button>
</div>
</template>
<script>
import { inject } from 'vue'
export default {
setup() {
const money = inject('money')
const changeMoney = inject('changeMoney')
const emitMoney = () => {
changeMoney(200)
}
return { money, emitMoney }
}
}
</script>