插槽:父组件和子组件内容的一个通信
子组件使用<slot>接收父组件传入的内容
如果内容有多个标签时,使用<template>包裹
默认插槽:
<template v-slot:default><h2>标题</h2><p>插槽内容</p> </template>
<slot></slot>
具名插槽:v-slot替代字符:#
<template v-slot:tree><p>树</p></template>
<slot name="tree"></slot>
作用域插槽:(可以传参)
<template v-slot:listtemp="slotList"><ul><li v-for="book in slotList.books">{{book}}</li></ul></template>
data() {return {title: "子组件",list:['javascript高级编程','vue高级','css高级']};}, <slot name="listtemp" :books="list"></slot>
依赖注入:利用props的话,只可以进行父子通信,如果要进行爷孙或者关系更深层的通信,要使用依赖注入。
跨组件通讯
依赖注入:provide-inject
在根元素写入要传的值:
data() {return {title: "父组件",msg:'这是根组件数据'}},provide(){return {message:this.msg}},
在子/孙组件写inject来接收
inject:['message']
注入别名:(根节点传入的时候名字与子孙组件的名字相重的时候,可以在用到的子组件的地方改个名字。)
下面的代码的意思是将message的名字改为msg,defalut的意思是如果没有传值下来,页面会显示的值为默认值。
inject:{msg:{from:'message',default:'默认值'}},
和响应式数据配合使用:message: computed(()=>this.msg)
如果父组件的值改变了,但是子组件不会发生变化,要利用计算属性来改变值:因为计算属性依赖的值变化他会跟着变化!
data() {return {title: "父组件",msg:'这是根组件数据'}},// 提供数据provide(){return {// message:this.msgmessage: computed(()=>this.msg)}},methods: {bindUpdateMessage(){this.msg = '新内容'}},
动态组件: 组件是动态变化的
- 让多个组件使用同一个挂载点,并动态切换,这就是动态组件
<component>元素包裹起来
<component :is="currentTab"></component>
可以实现多个组件来回切换
import Home from "./Home.js";
import Category from "./Category.js";
import Cart from "./Cart.js";
import My from "./My.js";
/*** 点击tab选项 内容区域切换为对应组件* 1. tab选项绑定点击事件* 2. 切换组件*/
export default {components: {Home,Category,Cart,My,},data() {return {title: "动态组件",currentTab:'home',list:[{name:'home',title:'首页'},{name:'category',title:'分类'},{name:'cart',title:'购物车'},{name:'my',title:'我的'},],isActive:false};},methods: {onTabChange(tabName){this.currentTab = tabName}},/*html*/template: `<div class="g-container"><div class="g-content"><component :is="currentTab"></component></div><!--<ul class="g-footer"><li @click="onTabChange('home')" :class="{active:currentTab=='home'}">首页</li><li @click="onTabChange('category')" :class="{active:currentTab=='category'}">分类</li><li @click="onTabChange('cart')" :class="{active:currentTab=='cart'}">购物车</li><li @click="onTabChange('my')" :class="{active:currentTab=='my'}">我的</li></ul>--><ul class="g-footer"><li v-for="item in list" @click="onTabChange(item.name)" :class="{active:currentTab==item.name}">{{item.title}}</li></ul></div>`,
};
购物车:(其它页面与此页面一样只改了Title的值)
/***/
export default {data() {return {title: "购物车",};},/*html*/template: `<div><h2>{{title}}</h2></div>`,
};
组件来回切换,在首页的时候,生命周期会经历创建和挂载,点击到其它页面时,首页的生命周期会被销毁,此时,所在的页面的生命周期就创建挂载起来。以此类推,如果我想实现一个组件缓存起来,不进行销毁。使用:<keep-alive>将不销毁的组件放这儿</keep-alive>
当一个组件在<keep-alive>中被切换时,他的activated和deactivated生命周期钩子被调用,用来代替mounted和unmounted。这适用于<keepAlive>的直接子节点及其所有子孙节点。
如何实现我想缓存哪些?哪些不缓存呢?
可以使用include / exclude来完成
<keep-alive include="Home,Category,Cart"><component :is="currentTab"></component></keep-alive>
在表达方式上,还可以用多样化:
组件如果想要条件性地被keepAlive缓存,就必须显示声明一个name选项。 name里面存放的是所在文件的文件名。
异步组件:(性能优化)从后端(服务端)拿到数据。
- Vue 提供了defineAsyncComponent方法来实现此功能
首先要引入:
import { defineAsyncComponent } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
获取异步主件,使用promise。这里只是模拟~
const AsyncChild = defineAsyncComponent(() => {return new Promise((resolve, reject) => {setTimeout(() => {//异步获取后端定义的异步组件const asyncComponent = {template: `<p>我是异步组件</p>`,};resolve(asyncComponent);}, 2000);});
});
获取后,进行注册
components: {Child,AsyncChild,},
在templeate中使用:
<async-child></async-child>
在显示我们异步主件前,先显示加载中....... 使用 Suspense即可
<!-- Suspense 作用: 首先显示 名为fallback的插槽内容,当异步组件加载完成后,显示异步组件 --><Suspense><async-child></async-child><template #fallback><p>加载中...</p></template></Suspense>
Teleport传送门:
Dialog是子组件,传送的是子组件
<Teleport to="body"><Dialog v-if="show" @closeDialog="show=false"></Dialog></Teleport>