补充:认识Mixin
组件和组件之间会存在相同的代码逻辑,将相同的代码逻辑进行抽取,使用Mixin来完成。
分发组件中的可复用功能,一个Mixin对象可以包含任何组件选项;当组件使用Mixin对象时,所有Mixin对象的选项将被混合进入该组件本身的选项中。
在 Vue 2 中,mixins 是创建可重用组件逻辑的主要方式。尽管在 Vue 3 中保留了 mixins 支持,但对于组件间的逻辑复用,Composition API 是现在更推荐的方式。
// 混入对象
export const demoMixin ={
data(){
return{
message:"hello DemoMixin"
}
},
methods:{
foo(){
console.log("demoMixin's foo")
}
},
created(){
console.log("执行了demoMixin里面的created周期")
}
}
在App.vue中导入:
<template>
<div>
<h2>{{message}}</h2>
<button @click="foo">按钮</button>
</div>
</template>
<script>
import {demoMixin} from "./Mixins/demoMixin.js"
export default{
mixins:[demoMixin],
data(){
return{
// message:"hello Vue.app"
}
}
}
</script>
<style>
</style>
Mixin的合并规则
(1)data函数返回值对象属性发生了冲突,那么会保留组件自身的数据;
(2)生命周期的钩子函数会合并在数组中,都会被调用;
(3)值为对象的选项,例如methods、components等,如果key相同,会取组件对象的键值对。
全局混入
如果组件中的某些选项,是所有组件都需要拥有的,那么这个时候我们可以使用全局的Mixin;
全局的Mixin可以使用应用app的方法mixin
完成注册,一旦注册,那么全局混入的选项将会影响每一个组件。
在main.js中编辑:
const app = createApp(App)
app.mixin({
created(){
console.log("全局的create生命周期")
}
})
app.mount('#app')
extends和Mixin的使用方法相同。
1.组合式 API (Composition API)
options API 的弊端
Options API的一大特点就是在对应的属性中编写对应的功能模块;比如data定义数据、methods定义方法、computed定义计算属性、watch监听属性改变,还有生命周期钩子。
弊端:
要实现一个功能时,对应的代码逻辑会被拆分到各个属性中;当组件变得更大更复杂时,逻辑关注点的列表就会增长,那么同一个功能逻辑就会被拆分的很分散;这时的代码可读性非常差。
**认识composition API **
composition API 帮我们把同一个逻辑关注点的相关代码收集在一起。
setup函数其实就是组件的另一个选项,用来代替之前编写的大部分其他选项(例如data、methods、computed、watch、生命周期等等)
2.setup函数的参数
第一个参数props
父组件传过来的属性会被放到props对象中,我们在setup中如果需要使用,可以通过props参数直接获取。
//子组件
export default{
props:{
message:{
type : String,
required :true
}
},
setup(props){
console.log(props.message)
}
}
//父组件
<template>
<div>
<home message="hahaha"></home>
</div>
</template>
<script>
import Home from "./Home.vue"
export default {
components: {
Home
}
}
</script>
第二个参数context
context参数包含三个属性
attrs:所有非props的attribute
slots:父组件传过来的插槽
emit:组件本身要发送事件时用emit
setup(props,context){
console.log(props.message),
console.log(context.attrs.id, context.attrs.class)
console.log(context.slots)
console.log(context.emit)
}
// 解构写法
setup(props,{attrs,slots,emit}){
console.log(props.message),
console.log(attrs.id, attrs.class)
console.log(slots)
console.log(emit)
}
3.setup返回值
setup的返回值可以在模板template中被使用;
也就是说我们可以通过setup的返回值来替代data选项
setup(){
//...
return {
title:"hello home title"
}
}
4.setup中不能使用this
this并没有指向当前实例;在setup被调用之前,data、computed、methods等都没有被解析,所以无法在setup中获取this。
5.reactiveAPI
使用reactive函数处理数据,数据再次使用就会进行依赖收集,当数据发生改变时,所收集到的依赖都会进行对应的响应式操作。
事实上,之前在data中编写的数据,也是在内部交给了reactive函数将其编程响应式对象。
<h2>当前计数:{{state.counter}}</h2>
<button @click="btnclick">+1按钮</button>
setup(){
const state = reactive({
counter :100
})
const btnclick =() => {
state.counter++
}
return {
state,
btnclick
}
}
reactive API传入的类型是有限制的,传入的必须是一个对象或数组类型;如果传入基本类型会报警告。
vue3提供了另一个API:ref API
6.ref API
ref会返回一个可变的响应式对象,该对象作为一个相应式的引用,维护着它内部的值,它内部的值是在ref的value属性中被维护的。
首先引入ref:import {ref} from "vue"
<template>
Home page
<!-- 在 template模板中使用ref时,会自动解包 -->
<h2>当前计数:{{counter}}</h2>
<button @click="btnclick">+1按钮</button>
</template>
<script>
import {ref} from "vue"
export default{
setup(){
let counter= ref(100)
const btnclick =() => {
// 逻辑代码中不会自动解包,所有要拿到value
counter.value++
}
return {
counter,
btnclick
}
}
}
</script>
ref 自动解包
ref自动解包是浅层解包,如果在外层包含一个函数,就不会自动解包;
如果将ref放到一个reactive属性中,在template中会自动解包。
7.readonly
readonly:将包裹的对象变为只读,并且是深度只读。
<template>
<button @click="btnclick">改变状态</button>
</template>
<script>
import {ref,readonly,reactive} from "vue"
export default{
setup(){
// 1.普通对象
const info1 = {name:"phoebe"}
const readonlyinfo1 =readonly(info1)
// 2.响应式对象reactive
const info2 = reactive({name:"phoebe"})
const readonlyinfo2 =readonly(info2)
// 3.响应式对象ref
const info3 = ref("phoebe")
const readonlyinfo3 =readonly(info3)
const btnclick =() => {
readonlyinfo3.name="queen"
}
return {
btnclick
}
}
}
</script>