## Vue组件的基本使用 ### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#1%E7%88%B6-%E5%AD%90%E7%BB%84%E4%BB%B6%E7%9A%84%E9%80%9A%E4%BF%A1)1.父->子组件的通信 #### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#11-%E5%88%9B%E5%BB%BA%E5%AD%90%E7%BB%84%E4%BB%B6-showmessagevue)1.1 创建子组件 ShowMessage.vue ~~~ props 定义子组件接受数据 ~~~ ~~~ <template> <div> <p>{{content}}</p> </div> </template> props: { content: { type: String, required: true, default: "123" } } ~~~ #### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#12-%E5%88%9B%E5%BB%BA%E7%88%B6%E7%BB%84%E4%BB%B6)1.2 创建父组件 ~~~ 1 import引入 2 components定义 3 标签内使用使用 ~~~ ~~~ <template> <div> <show-message :content="content"></show-message> </div> </template> <script> import ShowMessage from './ShowMessage.vue'; export default { components: { ShowMessage, }, data() { return { title: "嘻嘻嘻", content: "我是嘻嘻嘻嘻", } } } </script> <style scoped> </style> ~~~ ### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#2%E5%AD%90---%E7%88%B6-%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1)2.子 -> 父 组件通信 #### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#21-%E5%88%9B%E5%BB%BA%E5%AD%90%E7%BB%84%E4%BB%B6-counteroperationvue)2.1 创建子组件 CounterOperation.vue ~~~ emits 定义传递的方法 父组件接收 this.$emit("add"); 执行传递 ~~~ 当点击 -1操作时 激活increment 方法 传递 this.$emit("sub"); 到父组件 ~~~ <template> <div> <button @click="increment">+1</button> <button @click="decrement">-1</button> <input type="text" v-model.number="num"> <button @click="incrementN">+n</button> </div> </template> <script> export default { emits: ["add", "sub", "addN"], data() { return { num: 0 } }, methods: { increment() { this.$emit("add"); }, decrement() { this.$emit("sub"); }, incrementN() { this.$emit('addN', this.num, "why", 18); } } } </script> <style scoped> </style> ~~~ #### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#22-%E5%AE%9A%E4%B9%89%E7%88%B6%E7%BB%84%E4%BB%B6)2.2 定义父组件 1.标签内接收@add 调用 addOne事件 2然后执行相应操作 ~~~ <template> <div> <h2>当前计数: {{counter}}</h2> <counter-operation @add="addOne" @sub="subOne" @addN="addNNum"> </counter-operation> </div> </template> <script> import CounterOperation from './CounterOperation.vue'; export default { components: { CounterOperation }, data() { return { counter: 0 } }, methods: { addOne() { this.counter++ }, subOne() { this.counter-- }, addNNum(num, name, age) { console.log(name, age); this.counter += num; } } } </script> <style scoped> </style> ~~~ ### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#3-%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6-%E5%AE%9E%E4%BE%8B-%E9%A1%B5%E9%9D%A2%E5%88%87%E6%8D%A2)3 父子组件 实例 页面切换 父页面 ~~~ <template> <div> <tab-control :titles="titles" @titleClick="titleClick"></tab-control> <h2>{{contents[currentIndex]}}</h2> </div> </template> <script> import TabControl from './TabControl.vue'; export default { components: { TabControl }, data() { return { titles: ["衣服", "鞋子", "裤子"], contents: ["衣服页面", "鞋子页面", "裤子页面"], currentIndex: 0 } }, methods: { titleClick(index) { this.currentIndex = index; } } } </script> <style scoped> </style> ~~~ 子页面 ~~~ <template> <div class="tab-control"> <div class="tab-control-item" :class="{active: currentIndex === index}" v-for="(title, index) in titles" :key="title" @click="itemClick(index)"> <span>{{title}}</span> </div> </div> </template> <script> export default { emits: ["titleClick"], props: { titles: { type: Array, default() { return [] } } }, data() { return { currentIndex: 0 } }, methods: { itemClick(index) { this.currentIndex = index; this.$emit("titleClick", index); } } } </script> <style scoped> .tab-control { display: flex; } .tab-control-item { flex: 1; text-align: center; } .tab-control-item.active { color: red; } .tab-control-item.active span { border-bottom: 3px solid red; padding: 5px 10px; } </style> ~~~ ### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#4%E9%9D%9E%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6-%E4%B9%8B%E9%97%B4%E9%80%9A%E4%BF%A1)4非父子组件 之间通信 #### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#41-%E7%88%B6%E7%BB%84%E4%BB%B6---%E5%AD%90%E5%AD%99%E7%BB%84%E4%BB%B6)4.1 父组件 -> 子、孙组件 ~~~ 父组件 provide 里面时提供给 子组件的数据 这里使用计算属性 是为了 实时显示子组件数据 ~~~ ~~~ <template> <div> <home></home> <button @click="addName">+name</button> </div> </template> <script> import Home from './Home.vue'; import { computed } from 'vue'; export default { components: { Home }, provide() { return { name: "why", age: 18, length: computed(() => this.names.length) // ref对象 .value } }, data() { return { names: ["abc", "cba", "nba"] } }, methods: { addName() { this.names.push("why"); console.log(this.names); } } } </script> <style scoped> </style> ~~~ ~~~ 子组件 inject接收父组件传来的数据 ~~~ ~~~ <template> <div> HomeContent: {{name}} - {{age}} - {{length.value}} </div> </template> <script> export default { inject: ["name", "age", "length"], } </script> <style scoped> </style> ~~~ ### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#5%E4%BA%8B%E4%BB%B6%E6%80%BB%E7%BA%BF%E7%9A%84%E4%BD%BF%E7%94%A8)5事件总线的使用 ~~~ 5.1 安装 ~~~ ~~~ npm install mitt 使用 import mitt from 'mitt'; const emitter = mitt(); export default emitter; ~~~ ~~~ 5.2 emitter.emit发射数据 ~~~ ~~~ import emitter from './utils/eventbus'; export default { methods: { btnClick() { console.log("about按钮的点击"); emitter.emit("why", {name: "why", age: 18}); // emitter.emit("kobe", {name: "kobe", age: 30}); } } } ~~~ ~~~ 5.3 emitter.on 接收数据 ~~~ ~~~ import emitter from './utils/eventbus'; export default { created() { emitter.on("why", (info) => { console.log("why:", info); }); emitter.on("kobe", (info) => { console.log("kobe:", info); }); emitter.on("*", (type, info) => { console.log("* listener:", type, info); }) } } ~~~ ### [](https://gitee.com/wmlzofia/learn/blob/master/vue/%E7%BB%84%E4%BB%B6.md#%E6%8F%92%E6%A7%BD%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8)插槽的基本使用 ~~~ 子组件中 定义插槽名name="" ~~~ ~~~ <template> <div class="left"> <slot name="left"></slot> </div> <div class="center"> <slot name="center"></slot> </div> <div class="right"> <slot name="right"></slot> </div> <div class="addition"> <slot :name="name"></slot> </div> </template> <script> export default { props: { name: String } // data() { // return { // name: "why" // } // } } </script> ~~~ ~~~ 父组件 # ~~~ ~~~ <template> <div> <nav-bar :name="name"> <template #left> <button>左边的按钮</button> </template> <template #center> <h2>我是标题</h2> </template> <template #right> <i>右边的i元素</i> </template> <template #[name]> <i>why内容</i> </template> </nav-bar> </div> </template> <script> import NavBar from './NavBar.vue'; export default { components: { NavBar }, data() { return { name: "why" } } } </script> <style scoped> </style> ~~~