组件选项,在组件创建之前执行,一旦 props 被解析,就将作为组合式 API 的入口
- 所有声明了的 prop,不管父组件是否向其传递了,都将出现在 props 对象中。其中未被传入的可选的 prop 的值会是undefined。
- setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新,所以不能使用 ES6解构,会消除 prop 的响应性
- 如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成此操作
- 如果某个属性是可选的 prop,则传入的 props 中可能没有该属性。在这种情况下,toRefs 不适用 。需要使用 toRef 替代。
- context.attrs —— // Attribute (非响应式对象,等同于 $attrs)
- context.slots —— // 插槽 (非响应式对象,等同于 $slots)
- context.emit —— // 触发事件 (方法,等同于 $emit)
- context.expose —— // 暴露公共 property (函数)
const count = ref(1)
const obj = reactive({ count })
// ref 会被解包
console.log(obj.count === count.value) // true
const count = ref(1)
const obj = reactive({})
obj.count = count
console.log(obj.count) // 1
console.log(obj.count === count.value) // true
<script>
import { ref, reactive } from "vue";
setup(){
const str = ref("vue3.0")
const obj = reactive ({name: '张三', age: 20})
function changeStr(){
str.value = "vue3.0牛逼"
}
function changeObj(){
obj.name= "李四"
}
return { str, obj, changeStr, changeObj }
}
</script>
ref 和 reactive 本质我们可以简单的理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value
原因在于jsonData尽管是响应式的,但是响应式的是它的属性,而不是它自身,重赋值它自身跟重赋值它的属性是两码事。所以,想在组合式API中让数据具备响应式,必须用ref,因为ref又对Proxy包装了一层,修改ref其实是修改它的value,它的value一定是响应式的,因此视图就正常更新了
更多详细讲解 https://www.jianshu.com/p/cfe25e757d0e
通常当我们需要将数据从父组件传递到子组件时,我们通过props实现。 设想一下这样的一个组件结构,这个结构中有一些嵌套层级很深的组件,我们想在内嵌层级很深的一个子组件中,调用顶层父组件的某些数据。在这种情况下,如果我们仍需要通过prop从父组件到子组件之间的组件链中传递数据,会进行很多次传递,这可能挺烦人的。
为了应对这种情况,我们可以使用provide与inject的组合。父组件可以无视组件层级的深度,作为所有子组件的依赖提供者。这个特性基于两部分:父组件通过provide选项提供数据,并且子组件通过inject选项使用所提供的数据。
使用 provide 时,首先需要从 vue 显式导入 provide 方法
provide 函数定义property接收两个参数:
使用 inject 时,也需要从 vue 显式导入
inject函数有两个参数:
ps:provide/inject 只能写在setup中,即不能写在异步函数和回调函数中,因为那时已经不在setup生命周期中了
<template>
<div class="parent">
<h1>父组件的值:{{ primaryValue }}</h1>
<button @click="changeFatherValue(88)">父组件的值改变</button>
<chidCom></chidCom>
</div>
</template>
<script>
import chidCom from "../components/childCom.vue";
import { ref, reactive, provide } from "vue";
export default {
components: {
chidCom,
},
setup() {
let primaryValue = ref(4);
let objectValue = reactive({
name: "pzp",
age: "23",
});
provide("primaryValue", primaryValue);
provide("objectValue", objectValue);
console.log(primaryValue.value, objectValue.name);
let changeFatherValue = (val) => {
primaryValue.value = val;
objectValue.name = "pzpa";
};
provide('changeFatherValue', changeFatherValue)
return {
primaryValue,
objectValue,
changeFatherValue,
};
},
// methods: {
// changeFatherValue() {
// this.primaryValue = 8
// this.objectValue.name = 'pzpa'
// },
// },
};
</script>
<template>
<div>
<h1>父组件注入基础类型值:{{ fatherPrimary }}</h1>
<h1>父组件注入对象类型值:{{ fatherObject.name }}</h1>
<button @click="changeFatherValue(66)">子组件改变父组件值</button>
</div>
</template>
<script>
import { inject } from "vue";
export default {
setup() {
let fatherPrimary = inject("primaryValue");
let fatherObject = inject("objectValue");
let changeFatherValue = inject('changeFatherValue')
return {
fatherPrimary,
fatherObject,
changeFatherValue
};
},
};
</script>
changeFatherValue
官文给出的该方法的描述为:getCurrentInstance 支持访问内部组件实例。特别强调了
getCurrentInstance 只暴露给高阶使用场景,典型的比如在库中。强烈反对在应用的代码中使用 getCurrentInstance。请不要把它当作在组合式 API 中获取 this 的替代方案来使用
使用方法详解
计算属性和方法的区别
接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误
或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
侦听器数据源可以是返回值的 getter 函数,也可以直接是 ref
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接侦听ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
const firstName = ref('')
const lastName = ref('')
watch([firstName, lastName], (newValues, prevValues) => {
console.log(newValues, prevValues)
})
firstName.value = 'John' // logs: ["John", ""] ["", ""]
lastName.value = 'Smith' // logs: ["John", "Smith"] ["John", ""]
ps:在同一个函数里同时改变这些被侦听的来源,侦听器仍只会执行一次,即多个同步更改只会触发一次侦听器
在Vue3中,不能通过this.$store来获取使用vuex中存储的值,并且也不能使用getCurrentInstance来替代this进行使用。
此时若需要获取vuex的实例,就需要用到useStore
方法
ps:同理,对于路由的使用也是通过useRoute
和useRouter
方法
import { useRoute, useRouter } from "vue-router"
import { useStore } from 'vuex'
setup(props, context) {
// vue 3.0中vuex的使用
let store = useStore()
let storeValue = computed(() => store.state.user)
return {
storeValue
}
}
- vue3修改了虚拟dom的算法(即diff算法 - 比对虚拟dom有没有变化)
- vue2需要diff所有的虚拟dom节点,而vue3参考了SVELTE框架的思想,先分层次-然后找不变化的层-针对变化的层进行diff,更新速度不会再受template大小的影响,而是仅由可变的内容决定。经过尤雨溪自己的测试,大概有6倍的速度提升。
关于数据双向绑定的实现,vue2 采用了defineProperty,而vue3则采用了proxy。
优点:
/* vue2.0*/
var a = { b: 123, c: 444 };
Object.defineProperty(a, "b", {
set: function (newvalue) {
console.log("i am be set");
},
}); //只能获取到newvalue这个参数
/* vue3.0 */
var a = { b: 123, c: 444 };
var newa = new Proxy(a, {
set: function (target, key, newvalue) {
console.log(target, key, newvalue);
},
}); //可以获取到target,key,newvalue三个参数