文章目录
内容分发(插槽)
Vue2.6.0 之后采用全新 v-slot 语法取代之前的 slot、slot-scope
默认(匿名)插槽
父组件:
<template>
<Child>hello<Child>
<!-- 等价于 -->
<Child>
<template v-slot:default>hello</template>
</Child>
<!-- 等价于,v-slot: 缩写 -->
<Child>
<template #default>hello</template>
</Child>
</template>
<script setup lang="ts">
import Child from './Child'
</script>
子组件:<slot>
<div>
<slot></slot>
<!-- 等价于 -->
<slot name="default"></slot>
</div>
具名插槽
父组件:
<template>
<Child>
hello
<template #header>头部</template>
</Child>
<!-- 等价于 -->
<Child>
<template v-slot:default>hello</template>
<template v-slot:header>头部</template>
</Child>
<!-- 等价于,v-slot: 缩写 -->
<Child>
<template #default>hello</template>
<template #header>头部</template>
</Child>
</template>
子组件:
<div>
<slot name="header"></slot>
<slot></slot>
</div>
注意:
- 内容顺序是根据 child 的 slot 顺序来的,与 parent 顺序无关
v-slot
只能添加在<template>
上** (只有一种例外情况:独占默认插槽的缩写语法)
备用内容
父组件:
<Child></Child>
子组件:
<div>
<slot>Submit</slot>
</div>
渲染结果:
<div>Submit</div>
渲染作用域
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
如需将子模版的内容传递给父级模板,可以使用作用域插槽。
作用域插槽
传递子组件数据,传递事件
具名插槽作用域:
父组件:
<template>
<Child>
<template v-slot:default="slotProps">{{slotProps.title}}</template>
<template v-slot:header="slotProps">{{slotProps.firstName}}--{{slotProps.lastName}}</template>
</Child>
<!-- 等价于,v-slot: 缩写 -->
<Child>
<template #header="slotProps">{{slotProps.title}}</template>
<template #default="slotProps">{{slotProps.firstName}}--{{slotProps.lastName}}</template>
</Child>
</template>
子组件:
<div>
<slot name="header" title="标题"></slot>
<slot firstName="张" lastName="三"></slot>
</div>
独占默认插槽的缩写语法:
当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot
直接用在组件上:
父组件:
<template>
<Child #default="slotProps">{{slotProps.firstName}}--{{slotProps.lastName}}</Child>
</template>
子组件:
<div>
<slot firstName="张" lastName="三"></slot>
</div>
注意:
- 默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确
- 只要出现多个插槽,请始终为所有的插槽使用完整的基于
<template>
的语法
解构插槽 Prop
<template>
<Child #default="{ firstName, lastName }">{{firstName}}--{{lastName}}</Child>
<!-- 重命名 -->
<Child #default="{ firstName: firstN, lastName: lastN }">{{firstN}}--{{lastN}}</Child>
<!-- 默认值 -->
<Child #default="{ firstName='王', lastName }">{{firstName}}--{{lastName}}</Child>
</template>
动态插槽名
默认插槽:
<template>
<Child v-slot:[dynamicSlotName]></Child>
<!-- 等价于,v-slot: 缩写 -->
<Child #[dynamicSlotName]></Child>
</template>
具名插槽:
<template>
<Child>
<template v-slot:[dynamicSlotName]></template>
<template v-slot:[dynamicSlotName]="slotProps"></template>
</Child>
<!-- 等价于,v-slot: 缩写 -->
<Child>
<template #[dynamicSlotName]></template>
<template #[dynamicSlotName]="slotProps"></template>
</Child>
</template>
逻辑扩展
Vue.mixin 混入(Vue2)
混入是分发 Vue组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
缺点:如果混入多个,会导致混入里面的数据来源不明。 容易导致变量/方法命名冲突,这样只能修改当前组件内冲突的命名,不可能修改mixin混入里的命名,因为不确定会不会影响其他已使用混入的组件。
使用
全局混入:
// 混入对象(复用代码):它是一个配置对象,选项和组件里面一样
const mymixin = {
// data、methods、生命周期、
methods: {
dosomething () {}
}
}
// 全局混入:将混入对象传入
Vue.mixin(mymixin)
局部混入:
// 混入对象(复用代码):它是一个配置对象,选项和组件里面一样
const mymixin = {
methods: {
dosomething () {}
}
}
// 局部混入:做数组项设置到mixins选项,仅作用于当前组件
const Comp = {
mixins: [mymixin]
// 缺点:
// mixins: [mymixin, mymixin1, mymixin2, ...]
}
引入mixins 组件的生命周期
结论:
- mixins 的生命周期都比 调用mixins的组件快
- 变量来源不明确(隐式传入),不利于阅读,使代码变得难以维护
<script>
import common from '@/mixins/common.js'
export default {
mixins: [common],
beforeCreate() {
console.log('2、index beforeCreate')
},
created() {
console.log('4、index created')
},
beforeMount() {
console.log('6、index beforeMount')
},
mounted() {
console.log('8、index mounted')
},
beforeUpdate() {
console.log('10、index beforeUpdate')
},
updated() {
console.log('12、index updated')
},
beforeDestory() {
console.log('14、index beforeDestory')
},
destoryed() {
console.log('16、index destoryed')
}
}
</script>
common.js
export default {
data() {
return {}
},
methods:{},
computed: {},
filters: {},
beforeCreate() {
console.log('1、mixins beforeCreate')
},
created() {
console.log('3、mixins created')
},
beforeMount() {
console.log('5、mixins beforeMount')
},
mounted() {
console.log('7、mixins mounted')
},
beforeUpdate() {
console.log('9、mixins beforeUpdate')
},
updated() {
console.log('11、mixins updated')
},
beforeDestory() {
console.log('13、mixins beforeDestory')
},
destoryed() {
console.log('15、mixins destoryed')
}
}
Vue.extends 扩展:优先级高于mixin
extends扩展 用法跟 mixins 混入 非常相似,但是:
- 在局部组件中只能扩展单个对象,而混入可以是多个
- 另外如果和mixin混入发生冲突,该选项优先级较高
// 扩展对象(复用代码):它是一个配置对象,选项和组件里面一样
// 与混入对象一致
const myextends = {
methods: {
dosomething () {}
}
}
// 在局部组件中只能扩展单个对象
const Comp = {
extends: myextends // extends 不是数组,mixin可以使用数组混入多个对象
}
注意 Vue.extend 方法,不是扩展
Vue.extend 只是把当前的组件的配置对象变成构造函数,不是扩展。
Hook / Composition API 【推荐】
Vue3中的 hook 通常被称为 Composition API。相当于 Vue2 的 mixin,不同在于 hooks 是函数
Vue3 引入 Composition API,利用独立出来的响应式模块可以很方便的编写独立逻辑并提供响应式的数据,然后在setup选项中组合使用。
hook 优点:
- 解决 mixins 变量来源不明确(隐式传入),不利于阅读,代码难以维护 问题
- 帮助我们提高代码的复用性,让我们在不同的组件中都利用 hook 函数
Vue3 hook 库: Get Started 、VueUse
示例:
组件使用:
<script setup lang="ts">
import useBase64 from './hook/index'
useBase64({ name: 'xxx' }).then(res => {
console.log(res) // 123
})
</script>
逻辑抽取:
import {onMounted} from 'vue'
type Options = {
name: string
}
export default function (options: Options) {
return new Promise(resolve => {
onMounted(() => {
resolve('123')
})
})
}
hook VS mixins
共同点:
都是对代码片段进行抽离,实现复用,使得组件的逻辑更加清晰和可维护。
不同点:
hook | Mixins | |
---|---|---|
定义 | hook是通过Composition API引入的一种新特性,类似于React的hook。 | mixin是一种对Vue组件进行扩展的方式。 |
使用 | 使用setup方法,可以组织和复用各类逻辑。 | 使用mixin属性,加载公用的代码片段。 |
命名冲突 | 可以通过重新定义函数名来避免。 | 后一个mixin的函数覆盖先前的函数。 |
来源 | 来源清晰 | 使用多个mixins 时,变量/函数来源不明 |