Vue3.0动态组件<component>与KeepAlive:VOA模式

文章介绍了如何在Vue应用中使用动态组件根据条件渲染不同的组件,以及如何利用KeepAlive实现组件之间的数据缓存,确保用户切换组件时保留之前输入的数据。
摘要由CSDN通过智能技术生成

动态组件的使用方式:

<template>
  <div>
    <Navbar></Navbar>
    <Home v-if="componentName == '首页'"></Home>
    <List v-else-if="componentName == '列表'"></List>
    <Center v-else-if="componentName == '我的'"></Center>
    <Tabbar></Tabbar>

    <!--我们发现上面有5个组件,其中Home,List,Center三个组件会根据v-if条件渲染,
      最终只会有一个组件渲染出来,那我们可以改成动态组件来表示,代码如下-->

    <Navbar></Navbar>
    <!--这个componentName就是组件的名称比如你的子组件名称叫Navbar那他就是Navbar-->
    <!--is表示你这个动态组件应该是一个什么组件?如果是Home则会渲染成Home组件-->
    <component :is="componentName"></component> 
    <Tabbar></Tabbar>

  </div>
</template>
<script>
import store from "./components/store";
import Navbar from "./components/Navbar.vue" //导入Navbar组件模板
import Home from "./components/Home.vue";
import List from "./components/List.vue";
import Center from "./components/Center.vue";
import Tabbar from "./components/Tabbar.vue";
export default {
  inheritAttrs: false,
  data() {
    return {
      nvaTitle: "首页",
      componentName: "Home"
    }
  },
  components: {
    Navbar,
    Home,
    List,
    Center,
    Tabbar
  },
  provide() {
    return {
      app: this, //向外提供一个值,这个值的名称是我们自己定义的,this表示当前根组件对象(可以供其他组件可以直接获取到)
    }
  },
  mounted() { //钩子函数,项目已启动则订阅
    var obj = {
      "我的": "Home",
      "列表": "List",
      "首页": "Center"
    } 
    //订阅
    store.subscribe((name) => { //参数name传递的值其实就是"我的","列表","首页"
      this.componentName = obj[name] //如果name是"我的",那么obj[name] 的值就是Home,
    })
  }
}
</script>

动态组件的使用案例

我有7个组件 App.vue是根组件,它里面有5个子组件Navbar,Home,List,Center,Tabbar

其中Navbar是导航,Tabbar是底部,Home,List, Center则是内容。

现在是点击底部Tabbar组件中的【首页,列表,我的】要显示不同的内容:

如点击【首页】中间应该显示的是Home组件

如点击【列表】中间应该显示的是List组件

如点击【我的】中间应该显示的是Center组件

如下图

App.vue

<template>
  <div>
    <!-- <Navbar></Navbar>
    <Home v-if="componentName == '首页'"></Home>
    <List v-else-if="componentName == '列表'"></List>
    <Center v-else-if="componentName == '我的'"></Center>
    <Tabbar></Tabbar> -->

    <!--我们发现上面有5个组件,其中Home,List,Center三个组件会根据v-if条件渲染,
      最终只会有一个组件渲染出来,那我们可以改成动态组件来表示,代码如下-->

    <Navbar></Navbar>
    <!--这个componentName就是组件的名称比如你的子组件名称叫Navbar那他就是Navbar-->
    <!--is表示你这个动态组件应该是一个什么组件?如果是Home则会渲染成Home组件-->
    <component :is="componentName"></component> 
    <Tabbar></Tabbar>

  </div>
</template>
<script>
import store from "./components/store";
import Navbar from "./components/Navbar.vue" //导入Navbar组件模板
import Home from "./components/Home.vue";
import List from "./components/List.vue";
import Center from "./components/Center.vue";
import Tabbar from "./components/Tabbar.vue";
export default {
  inheritAttrs: false,
  data() {
    return {
      nvaTitle: "首页",
      componentName: "Home"
    }
  },
  components: {
    Navbar,
    Home,
    List,
    Center,
    Tabbar
  },
  provide() {
    return {
      app: this, //向外提供一个值,这个值的名称是我们自己定义的,this表示当前根组件对象(可以供其他组件可以直接获取到)
    }
  },
  mounted() { //钩子函数,项目已启动则订阅
    var obj = {
      "我的": "Home",
      "列表": "List",
      "首页": "Home"
    } 
    //订阅
    store.subscribe((name) => { //参数name传递的值其实就是"我的","列表","首页"
      this.componentName = obj[name] //如果name是"我的",那么obj[name] 的值就是Home,
    })
  }
}
</script>

Navbar.vue

<template>
    <div>
        <button>返回</button>
        <span>{{nvaTitle}}</span>
        <button>首页</button>
    </div>
</template>
<script>
import store from "./store"
export default {
   
    data(){
       return{
        nvaTitle:"首页"
       }
    },
    components: {
    },
    mounted(){
        store.subscribe(this.mysubscribe) 
    },
    methods:{
        mysubscribe(value){
            this.nvaTitle=value
        }
    }
}
</script>
<style scoped>
div {
    display: flex;
    width: 100%;
    justify-content: space-between;
    height: 50px;
    line-height: 50px;
    background: gray;

}
</style>

Tabbar.vue

<template>
    <ul>
        <TabbarItem v-for="item in datalist" :key="item" :itemStr="item"></TabbarItem>
    </ul>
</template>
<script>
import TabbarItem from "./TabbarItem.vue"
export default {
    data() {
        return {
            datalist: ["首页", "列表", "我的"]
        }
    },
    components: {
        TabbarItem
    }
}
</script>
<style scoped>
ul {
    display: flex;
    position: fixed;
    bottom: 0;
    width: 100%;
    height: 50px;
    line-height: 50px;
}

li {
    flex: 1;
    text-align: center;
}
</style>

TabbarItem.vue

<template>
    <li @click="handelClick">
        {{ itemStr }}
    </li>
</template>
<script >
import store from "./store"
export default {
    props: ["itemStr"],
    inject: ["app"],//在App.vue根组件中通过provide向外提供了一个app的值,我们可以通过注入的方式获取
    methods: {
        handelClick() {
            //this.app.nvaTitle = this.itemStr //这个app就是根组件,根组件中有一个nvaTitle的对象,我们可以重新给他赋值,它的值变化后就会自动流向需要这个值的子组件。
            store.publish(this.itemStr);
            this.app.nvaTitle = this.itemStr;
           

        }
    }
}
</script>

Home.vue

<template>
    <div>
        Home
    </div>
</template>

List.vue

<template>
    <div>
        List
    </div>
</template>

Center.vue

<template>
    <div>
        Center
    </div>
</template>

store.js

export default {
    datalist: [], //存放带一个参数的函数集合

    //订阅
    subscribe(fun) {
        this.datalist.push(fun) //将一个带一个参数的函数添加到datalist中 
    },

    //发布
    publish(value) {
        this.datalist.forEach(fun=>{  
            fun(value)   //遍历datalist中的函数并且立即执行 (函数带几个参数需要自己根据自己的实际情况来决定)
        })
    } 
}

动态组件的数据缓存<KeepAlive>

我在Home组件的input中填写了数据,当切换到List组件中,再返回Home组件,需要保持之前填写的数据还在,那么就需要用到KeepAlive

<KeepAlive>是让他包裹的组件保持活着,而不是切换组件的时候将其它组件移除

include属性表示哪些组件需要缓存。  三种写法:include="home,list" 或者 include=["home,list"] 或者 include="/home|list/"  这里我需要home和list组件需要缓存,

exclude属性表示哪些缓存不需要缓存。三种写法:exclude="home,list" 或者 exclude=["home,list"] 或者 exclude="/home|list/"  这里我需要home和list组件不需要缓存,

注意:当用到include或exclude后,需要component动态组件所需要表示的组件中给他取一个名字 举列:在Home组件中给Home组件取一个名叫home,取List组件中给他取一个名字叫list,去Center组件中给他取一个名字叫center

案列

父组件

<template>
  <div>
    <Navbar></Navbar>
    <!--我有个需求:因为Home,List,Center组件是会随时切换的,点下【我的】就会切换到Home组件,点下【列表】就会切换到List组件,
    我在Home组件的input中填写了数据,当切换到List组件中,再返回Home组件,需要保持之前填写的数据还在,那么就需要用到KeepAlive
    <KeepAlive>是让他包裹的组件保持活着,而不是切换组件的时候将其它组件移除
    include属性表示哪些组件需要缓存。  三种写法:include="home,list" 或者 include=["home,list"] 或者 include="/home|list/"  这里我需要home和list组件需要缓存,
    exclude属性表示哪些缓存不需要缓存。三种写法:exclude="home,list" 或者 exclude=["home,list"] 或者 exclude="/home|list/"  这里我需要home和list组件不需要缓存,
    注意:当用到include或exclude后,需要component动态组件所需要表示的组件中给他取一个名字 举列:在Home组件中给Home组件取一个名叫home,取List组件中给他取一个名字叫list,去Center组件中给他取一个名字叫center
    -->
    <KeepAlive include="home,list"> <!-- <KeepAlive exclude="center"></KeepAlive> -->
      <component :is="componentName"></component> 
    </KeepAlive>
  
    <Tabbar></Tabbar>

  </div>
</template>
<script>
import store from "./components/store";
import Navbar from "./components/Navbar.vue" //导入Navbar组件模板
import Home from "./components/Home.vue";
import List from "./components/List.vue";
import Center from "./components/Center.vue";
import Tabbar from "./components/Tabbar.vue";
export default {
  inheritAttrs: false,
  data() {
    return {
      nvaTitle: "首页",
      componentName: "Home"
    }
  },
  components: {
    Navbar,
    Home,
    List,
    Center,
    Tabbar
  },
  provide() {
    return {
      app: this, //向外提供一个值,这个值的名称是我们自己定义的,this表示当前根组件对象(可以供其他组件可以直接获取到)
    }
  },
  mounted() { //钩子函数,项目已启动则订阅
    var obj = {
      "我的": "Center",
      "列表": "List",
      "首页": "Home"
    } 
    //订阅
    store.subscribe((name) => { //参数name传递的值其实就是"我的","列表","首页"
      this.componentName = obj[name] //如果name是"我的",那么obj[name] 的值就是Home,
    })
  }
}
</script>

Home子组件

<template>
    <div>
        Home
        <input type="text">
    </div>
</template>
<script>
export default{
    name:"home" //组件的名称叫home
}
</script>

List子组件

<template>
    <div>
        List
        <input type="text">
    </div>
</template>
<script>
export default{
    name:"list" //组件的名称叫list
}
</script>

Center子组件

<template>
    <div>
        Center
        <input type="text">
    </div>
</template>
<script>
export default{
    name:"center" //组件的名称叫center
}
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值