用法:
<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>案例
我有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中的函数并且立即执行 (函数带几个参数需要自己根据自己的实际情况来决定)
        })
    } 
}



















