👏作者简介:大家好,我是小童,Java开发工程师,博客博主,Java领域新星创作者
📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
插槽 Slots
我们已经了解到组件能够接收任意类型的 JavaScript 值作为 props,但组件要如何接收模板内容呢?在某些场景中,我们可能 想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这 些片段
<template>
<h3>ComponentA</h3>
<ComponentB>
<h3>插槽传递视图内容</h3>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
components: {
ComponentB
}
}
</script>
<template>
<h3>ComponentB</h3>
<slot></slot>
</template>
<slot> 元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽
内容 (slot content) 将在哪里被渲染
实时效果反馈
1. 下列那个是插槽使用中,插槽出口的关键字:
A props
B data
C emit
D slo
插槽Slots(续集)
渲染作用域
插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的
<template>
<h3>ComponentA</h3>
<ComponentB>
<h3>{{ message }}</h3>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data(){
return{
message:"message在父级"
}
},
components: {
ComponentB
}
}
</script>
<template>
<h3>ComponentB</h3>
<slot></slot>
</template>
默认内容
在外部没有提供任何内容的情况下,可以为插槽指定默认内容
<template>
<h3>ComponentB</h3>
<slot>插槽默认值</slot>
</template>
具名插槽
<template>
<h3>ComponentA</h3>
<ComponentB>
<template v-slot:header>
<h3>标题</h3>
</template>
<template v-slot:main>
<p>内容</p>
</template>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data(){
return{
message:"message在父级"
}
},
components: {
ComponentB
}
}
</script>
<template>
<h3>ComponentB</h3>
<slot name="header"></slot>
<hr>
<slot name="main"></slot>
</template>
v-slot 有对应的简写 # ,因此 < template v-slot:header > 可以简写为 < template #header > 。其意思就是“将这部分模板片段传入子组件的 header 插槽中”
<template>
<h3>ComponentA</h3>
<ComponentB>
<template #header>
<h3>标题</h3>
</template>
<template #main>
<p>内容</p>
</template>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data(){
return{
message:"message在父级"
}
},
components: {
ComponentB
}
}
</script>
插槽Slots(再续集)
在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时 将一部分数据提供给插槽
我们也确实有办法这么做!可以像对组件传递 props 那样,向一个 插槽的出口上传递 attributes
<template>
<h3>ComponentA</h3>
<ComponentB v-slot="slotProps">
<h3>{{ message }}-{{ slotProps.text }}</h3>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data(){
return{
message:"message在父级"
}
},
components: {
ComponentB
}
}
</script>
<template>
<h3>ComponentB</h3>
<slot :text="message"></slot>
</template>
<script>
export default {
data(){
return{
message:"ComponentB中的数据"
}
}
}
</script>
具名插槽传递数据
<template>
<h3>ComponentA</h3>
<ComponentB #header="slotProps">
<h3>{{ message }}-{{ slotProps.text }}</h3>
</ComponentB>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default {
data(){
return{
message:"message在父级"
}
},
components: {
ComponentB
}
}
</script>
<template>
<h3>ComponentB</h3>
<slot name="header" :text="message">
</slot>
</template>
<script>
export default {
data(){
return{
message:"ComponentB中的数据"
}
}
}
</script>
组件生命周期
每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码
生命周期示意图
<template>
<h3>组件生命周期</h3>
<p>{{ message }}</p>
<button @click="updateHandle">更新数据
</button>
</template>
<script>
export default {
data(){
return{
message:"老数据"
}
},
methods:{
updateHandle(){
this.message = "新数据"
}
},
beforeCreate(){
console.log("组件创建之前");
},
created(){
console.log("组件创建之后");
},
beforeMount(){
console.log("组件渲染之前");
},
mounted(){
console.log("组件创建之后");
},
beforeUpdate(){
console.log("数据更新之前");
},
updated(){
console.log("数据更新之后");
},
beforeUnmount(){
console.log("组件卸载之前");
},
unmounted(){
console.log("组件卸载之后");
}
}
</script>
实时效果反馈
1. 下列那个是组件渲染之后执行的生命周期函数:
A created
B mounted
C updated
D unmounted
生命周期应用
组件的生命周期会随着我们对 Vue 的了解越多,也会越来越重要,这里我们先讲两个常用的应用常见:
1 通过 ref 获取元素DOM结构
2 模拟网络请求渲染数据
通过 ref
<template>
<h3>组件生命周期应用</h3>
<p ref="name">xiaotong</p>
</template>
<script>
export default {
beforeMount(){
console.log(this.$refs.name); // undefind
},
mounted(){
console.log(this.$refs.name);
}
}
</script>
模拟网络请求渲染数据
<template>
<h3>组件生命周期应用</h3>
<ul>
<li v-for="(item,index) in banner" :key="index">
<h3>{{ item.title }}</h3>
<p>{{ item.content }}</p>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
banner: []
}
},
mounted() {
this.banner = [
{
"title": "我在爱尔兰",
"content": "爱尔兰(爱尔兰语:Poblacht na hÉireann;英语:Republic of Ireland), 是一个西欧的议会共和制国家,西临大西洋,东靠爱尔兰海,与英国隔海相望,是北美通向欧洲的通道爱尔兰自然",
},
{
"title": "一个人的东京",
"content": "东京(Tokyo)是日本国的首都,是亚洲第一大城市,世界第二大城市。全球最大的经济中心之一。东京的著名观光景点有东京铁塔、皇居、国会议事堂、浅草寺、浜离宫、上野公园与动物园",
},
{
"title": "普罗旺斯的梦",
"content": "普罗旺斯(Provence) 位于法国东南部,毗邻地中海和意大利,从地中海沿岸延伸到内陆的丘陵地区,中间有大河“Rhone”流过。自古就以靓丽的阳光和蔚蓝的天空,迷人的地中海和心醉",
},
{
"title": "相约夏威夷之夏",
"content": "夏威夷州位于北太平洋中,距离美国本土3,700公里,总面积16,633平方公里,属于太平洋沿岸地区。首府为檀香山。在1778至1898年间,夏威夷也被称为“三明治群岛”(Sandwich Islands)",
}
]
}
}
</script>
动态组件
有些场景会需要在两个组件间来回切换,比如 Tab 界面
A、B两个组件
<template>
<h3>ComponentA</h3>
</template>
<template>
<h3>组件切换</h3>
<component :is="currentTab"></component>
<button @click="changeComponentHandle">切换</button>
</template>
<script>
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"
export default {
components: {
ComponentA,
ComponentB
},
data(){
return{
currentTab:"ComponentA",
}
},
methods:{
changeComponentHandle(){
this.currentTab = this.currentTab == "ComponentA" ? "ComponentB" : "ComponentA"
}
}
}
</script>
组件保持存活
当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过 <keep-alive> 组件强制被切换掉的组件仍然保持“存活”的状态
组件被卸载
<template>
<h3>ComponentA</h3>
</template>
<script>
export default {
beforeUnmount(){
console.log("组件卸载之前");
},
unmounted(){
console.log("组件卸载之后");
}
}
</script>
保持存活
<template>
<h3>ComponentA</h3>
<p>{{ message }}</p>
<button @click="updateHandle">修改数据</button>
</template>
<script>
export default {
data(){
return{
message:"老数据"
}
},
methods:{
updateHandle(){
this.message = "新数据"
}
}
}
</script>
实时效果反馈
1. 保持组件存活的方案,下列那个是正确的:B
A <component is='...'> B <keep-alive> C beforeMounte D unmounted
异步组件
在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent
<template>
<h3>组件切换</h3>
<keep-alive>
<component :is="currentTab"></component>
</keep-alive>
<button @click="changeComponentHandle">切换
</button>
</template>
<script>
import { defineAsyncComponent } from 'vue'
import ComponentA from "./components/ComponentA.vue"
const AsyncComponentB = defineAsyncComponent(() =>
import('./components/ComponentB.vue'))
export default {
components: {
ComponentA,
AsyncComponentB
},
data() {
return {
currentTab: "ComponentA",
}
},
methods: {
changeComponentHandle() {
this.currentTab = this.currentTab == "ComponentA" ? "AsyncComponentB" : "ComponentA"
}
}
}
</script>
依赖注入
通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props
这一问题被称为“prop 逐级透传”
provide 和 inject 可以帮助我们解决这一问题。 一个父组件相对于其 所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖
Provide (提供)
要为组件后代提供数据,需要使用到 provide
export default {
provide: {
message: 'hello!'
}
}
data
export default {
data() {
return {
message: 'hello!'
}
},
provide() {
// 使用函数的形式,可以访问到 `this`
return {
message: this.message
}
}
}
除了在一个组件中提供依赖,我们还可以在整个应用层面提供依赖
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
Inject (注入)
要注入上层组件提供的数据,需使用 inject
export default {
inject: ['message'],
created() {
console.log(this.message) // injected value
}
}
注入会在组件自身的状态之前被解析,因此你可以在 data() 中访问到 注入的属性
export default {
inject: ['message'],
data() {
return {
// 基于注入值的初始数据
fullMessage: this.message
}
}
}
温馨提示
provide 和 inject
实时效果反馈
1. 下列可以实现"prop 跨组件透传"的关键字是:A
A Provide Inject B <keep-alive> C Props D defineAsyncComponent
Vue 应用
应用实例
每个 Vue 应用都是通过 createApp 函数创建一个新的 应用实例
import { createApp } from 'vue'
const app = createApp({
/* 根组件选项 */
})
根组件
我们传入 createApp
import { createApp } from 'vue'
// 从一个单文件组件中导入根组件
import App from './App.vue'
const app = createApp(App)
挂载应用
应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一 个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串
app.mount('#app')
<div id="app"></div>
公共资源
在 src 目录下的 assets