1. 文件目录结构
在views目录中放页面基础结构的组件在components里放页面中各个功能模块的组件2. 使用组件
(1)在页面中单独引用
<template><Nav></Nav></template><script>import nav from '@/components/Nav.vue'export default {name: 'Home',components: {Nav },</script>
(2)在全局引用
在mian.js里
注册单个组件
import Nav from '@/components/Nav.vue' ponent('Nav', Nav) // 全局注册Nav组件
注册所有组件
const components = require.context('./components', true, /\.vue$/);components.keys().forEach(key => {const name = key.match(/\/(\w+?)\.vue$/)[1];ponent(name, components(key).default);});
3. 组件传值
(1)父组件向子组件传值
父组件通过绑定自定义属性来实现,v-bind
(简写为:
)绑定需要传递给子组件的值,子组件通过props
来接收父组件传递的值。<!-- 父组件 --><Child :name="zhang"></Child>
// 子组件export default {props: {name: {type: String, // 限制类型required: true, // 限制必要性default: "", // 指定默认值},},}
(2)子组件给父组件传值
// 子组件<button @click="changeName">改变父组件的name</button> export default {methods: {//子组件的事件changeName() {this.$emit('handleChange', 'zhang') // 触发父组件中handleChange事件并传参Jack// 此处事件名称与父组件中绑定的事件名称要一致}}}
// 父组件<child @handleChange="changeName"></child>methods: {changeName(name) {// name形参是子组件中传入的值Jackthis.name = name}}
(3)通过 $parent ,$children,$root 或 $refs 访问组件实例
// 子组件export default {data () {return {title: '子组件'}},methods: {sayHello () {console.log('Hello');}}}
// 父组件<template><child ref="child" /></template><script>export default {created () {// 通过 $ref 来访问子组件console.log(this.$refs.child.title); // 子组件this.$refs.child.sayHello(); // Hello// 通过 $children 来调用子组件的方法this.$children.sayHello(); // Hello }}</script>
(4)$attrs和$listeners
$attrs
$attrs在vue的2.40版本以上可使用$attrs,当一个组件没有声明任何 prop 时,$attrs里包含所有父作用域的绑定的自定义属性 (class 和 style 除外),并且可以通过v-bind="$attrs"
传入内部组件如果给组件传递的数据,组件不使用props接收,那么这些数据将作为组件的HTML元素的特性,这些特性绑定在组件的HTML根元素上(可使用inheritAttrs: false
取消)inheritAttrs: false
的含义是不希望本组件的根元素继承父组件的attribute,同时父组件传过来的属性(没有被子组件的props接收的属性),也不会显示在子组件的dom元素上,但是在组件里可以通过其$attrs可以获取到没有使用的注册属性, ``inheritAttrs: false`是不会影响 style 和 class 的绑定
$listeners
$listeners
它是一个对象,里面包含了作用在这个组件上的所有监听器并且可以通过 v-=“$listeners” 传入内部组件
<!-- 父组件 --><template><div><HomeHeader@toHome="logoCilck":value="22"aa="aa"></HomeHeader></div></template>
// 子组件<template><Menu v-bind="$attrs" v-on="$listeners"></Menu></template>export default {name: "HomeHeader",inheritAttrs: false, // 避免传入的未声明的值绑定到子组件的根元素上mounted() {console.log(this.$attrs); // {value: 22, aa: 'aa'}console.log(this.$listeners) // {toHome: ƒ}},};
// 孙子组件export default {name: 'Menu',mounted() {console.log(this.$attrs); // {value: 22, aa: 'aa'}console.log(this.$listeners) // {toHome: ƒ}},};
(5)子组件之间传值
将props
和$emit
结合使用,子组件先传给父组件,再由父组件传给另一个子组件。EventBus
,创建一个 EventBus.js 文件,并暴露一个 vue 实例
import Vue from 'Vue'export default new Vue()
在要传值的文件里导入这个空 vue 实例,绑定事件并通过 $emit 触发事件函数
(也可以在 main.js 中全局引入该 js 文件,我一般在需要使用到的组件中引入)
<template><div><p>姓名: {{name }}</p><button @click="changeName">修改姓名</button></div></template> <script>import {EventBus } from "../EventBus.js"export default {data() {return {name: 'John',}},methods: {changeName() {this.name = 'Lily'EventBus.$emit("editName", this.name) // 触发全局事件,并且把改变后的值传入事件函数}}}</script>
在接收传值的组件中也导入 vue 实例,通过 $on 监听回调,回调函数接收所有触发事件时传入的参数
import {EventBus } from "../EventBus.js" export default {data() {return {name: ''}},created() {EventBus.$on('editName', (name) => {this.name = name})}}
(6)provide,inject
它们需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
// 父组件export default {provide: {// 它的作用就是将 name 这个变量提供给它的所有子组件。name: 'zhang'}}
export default {inject: ['name'], // 注入了从父组件中提供的name变量mounted () {console.log(this.name); // zhang}}
4. 插槽
**slot
**默认插槽
插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码
具名插槽
<!-- 子组件 --><template><div class= 'button'><button> </button><slot name='one'> 这就是默认值1</slot><slot name='two'> 这就是默认值2 </slot><slot name='three'> 这就是默认值3 </slot></div></template>
<!-- 父组件 --><template><div class= 'app'><ebutton> <template v-slot:one> 这是插入到one插槽的内容 </template><template v-slot:two> 这是插入到two插槽的内容 </template><template v-slot:three> 这是插入到three插槽的内容 </template></ebutton></div></template>
作用域插槽 ( 父组件 在子组件 处使用子组件 data)
//子组件 : (假设名为:ebutton)<template><div class= 'button'><button> </button><slot name= 'one' :value1='child1'> 这就是默认值1</slot> //绑定child1的数据<slot :value2='child2'> 这就是默认值2 </slot> //绑定child2的数据,这里我没有命名slot</div> </template>new Vue({el:'.button',data:{child1:'数据1',child2:'数据2'}})
//父组件:(引用子组件 ebutton)<template><div class= 'app'><ebutton> // 通过v-slot的语法 将插槽 one 的值赋值给slotonevalue <template v-slot:one = 'slotonevalue'> {{slotonevalue.value1 }}</template>// 同上,由于子组件没有给slot命名,默认值就为default<template v-slot:default = 'slottwovalue'> {{slottwovalue.value2 }}</template></ebutton></div></template>
$slots
vm.$slots是一个对象,键名是所有具名slot的名称,加上一个default,而键值则是一个存放VNode节点的数组。