一、Props和emit 父组件A通过props的方式向子组件B传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。 1.父组件向子组件传值 接下来我们通过一个例子,说明父组件如何向子组件传递值:在子组件Users.vue中如何获取父组件App.vue中的数据 users:[“Henry”,”Bucky”,”Emily”]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <template> <div id="app" > <users v-bind:users="users" ></users>/ /前者自定义名称便于子组件调用,后者要传递数据名 </ div></template> <script> import Users from "./components/Users" export default { name: 'App' , data ( ) { return { users:["Henry" ,"Bucky" ,"Emily" ] } }, components:{ "users" :Users } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <template> <div class ="hello" > <ul> <li v-for ="user in users" >{{user}}</li>/ /遍历传递过来的值,然后呈现到页面 </u l> </div> </template> <script> export default { name: 'HelloWorld' , props:{ users:{ type:Array , required:true } } } </script>
总结:父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed
二、EventBus eventBus可以在全局定义,实现全项目通讯,使用方法也很简单。
1、初始化——全局定义 全局定义,可以将eventBus绑定到vue实例的原型上,也可以直接绑定到window对象上.
1 2 3 4 5 Vue.prototype.$EventBus = new Vue(); window .EventBus = new Vue();
2、触发事件
1 2 3 4 this .$EventBus.$emit('eventName' , param1,param2,...)EventBus.$emit('eventName' , param1,param2,...)
3、监听事件
1 2 3 4 5 6 7 8 this .$EventBus.$on('eventName' , (param1,param2,... )=> { }) EventBus.$on('eventName' , (param1,param2,... )=> { })
4、移除监听事件
为了避免在监听时,事件被反复触发,通常需要在页面销毁时移除事件监听。或者在开发过程中,由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听。
1 2 3 4 this .$EventBus.$off('eventName' );EventBus.$off('eventName' );
三、Provide和Inject
官方解释 provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的property。 inject 可以是一个字符串数组、也可以是一个对象 说白了,就是provide在祖先组件中注入,inject 在需要使用的地方引入即可。 我们可以把依赖注入看做一部分大范围的prop,只不过它以下特点: ● 祖先组件不需要知道哪些后代组件使用它提供的属性 ● 后代组件不需要知道被注入的属性是来自那里
注意: provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
下面举一个例子:
祖先 index.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 <template> <div class ="grandPa" > 爷爷级别 : <strong > {{ nameObj.name }} 今年 <i class ="blue" > {{ age }}</i > 岁, 城市<i class ="yellow" > {{ city }}</i > </strong > <child /> <br> <br> <el-button type="primary" plain @click="changeName" >改变名称</el-button> </div> </template> <script> import child from '@/components/ProvideText/parent' export default {name: 'ProvideGrandPa' , components: { child }, data: function ( ) { return { nameObj: { name: '小布' }, age: 12 , city: '北京' } }, provide ( ) { return { nameObj: this .nameObj, cityFn: () => this .city, age: this .age } }, methods: { changeName ( ) { if (this .nameObj.name === '小布' ) { this .nameObj.name = '貂蝉' this .city = '香港' this .age = 24 } else { this .nameObj.name = '小布' this .city = '北京' this .age = 12 } } } } </script> <style lang="scss" scoped> .grandPa{ width: 600px; height:100px; line-height: 100px; border: 2px solid #7fffd4; padding:0 10px; text-align: center; margin:50px auto; strong{ font-size: 20px; text-decoration: underline;; } .blue{ color: blue; } } </style>
中间组件 parent.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <template> <div class ="parent" > 父亲级别 : <strong > 只用作中转</strong > <son /> </div> </template> <script> import Son from './son' export default {name: 'ProvideParent' , components: { Son } } </script> <style lang="scss" scoped> .parent{ height:100px; line-height: 100px; border: 2px solid #feafef; padding:0 10px; margin-top: 20px; strong{ font-size: 20px; text-decoration: underline;; } } </style>
后代组件 son.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <template> <div class ="son" > 孙子级别 : <strong > {{ nameObj.name }} 今年 <i class ="blue" > {{ age }}</i > 岁, 城市<i class ="yellow" > {{ city }}</i > </strong > </div> </template> <script> export default {name: 'ProvideSon' , inject: ['nameObj' , 'age' , 'cityFn' ], computed: { city ( ) { return this .cityFn() } } } </script> <style lang="scss" scoped> .son{ height:100px; line-height: 100px; padding:0 10px; margin: 20px; border: 1px solid #49e2af; strong{ font-size: 20px; text-decoration: underline;; } .blue{ color: blue; } } </style>
执行之后会发现一个小细节。 无论我点击多少次,孙子组件的年龄age字段永远都是12并不会发生变化。 正是官网所提到的provide 和 inject绑定并不是可响应的。这是刻意为之的。 所以大家使用的时候,一定要注意注入的方式,不然很可能无法实现数据响应。
四、vuex vuex的通信,大家可以前往我的另一篇博客vue状态管理之Vuex
五、$attrs/$listeners 1.简介 多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用。为此Vue2.4 版本提供了另一种方法—-$attrs/$listeners ● $attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。通常配合 inheritAttrs 选项一起使用。 ● $listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件 接下来我们看个跨级通信的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <template> <div> <h2>浪里行舟</h2> <child-com1 :foo="foo" :boo="boo" :coo="coo" :doo="doo" title="前端工匠" ></child-com1> </div> </template> <script> const childCom1 = () => import ("./childCom1.vue" );export default { components: { childCom1 }, data ( ) { return { foo: "Javascript" , boo: "Html" , coo: "CSS" , doo: "Vue" }; } }; </script>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template class ="border" > <div> <p>foo: {{ foo }}</p> <p>childCom1的$attrs: {{ $attrs }}</p> <child-com2 v-bind="$attrs" ></child-com2> </div> </template> <script> const childCom2 = () => import ("./childCom2.vue" );export default { components: { childCom2 }, inheritAttrs: false , props: { foo: String }, created ( ) { console .log(this .$attrs); } }; </script>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <template> <div class ="border" > <p>boo: {{ boo }}</p> <p>childCom2: {{ $attrs }}</p> <child-com3 v-bind="$attrs" ></child-com3> </div> </template> <script> const childCom3 = () => import ("./childCom3.vue" );export default { components: { childCom3 }, inheritAttrs: false , props: { boo: String }, created ( ) { console .log(this .$attrs); } }; </script>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <template> <div class ="border" > <p>childCom3: {{ $attrs }}</p> </div> </template> <script> export default { props: { coo: String , title: String } }; </script>
没有继承数据的对象,格式为{属性名:属性值}。Vue2.4提供了$attrs , $listeners 来传递数据与事件,跨级组件之间的通讯变得更简单。 简单来说:$attrs与$listeners 是两个对象,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。
六、$parent / $children与 ref ● ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例 ● $parent / $children:访问父 / 子实例 需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。我们先来看个用 ref来访问组件的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 export default { data () { return { title: 'Vue.js' } }, methods: { sayHello () { window .alert('Hello' ); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 <template> <component-a ref="comA" ></component-a> </template> <script> export default { mounted () { const comA = this .$refs.comA; console .log(comA.title); comA.sayHello(); } } </script>