vue组件通信
参照博客:https://www.jianshu.com/p/7df2576a8a2b
方法一、prop和
$emit
1.prop--父组件向子组件传值
a.prop大小写: postTitle 等价于 post-title;
b.prop类型:
以数组形式:
1 props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
以对象形式:(通常你希望每个 prop 都有指定的值类型)
1 props: { 2 title: String, 3 likes: Number, 4 isPublished: Boolean, 5 commentIds: Array, 6 author: Object, 7 callback: Function, 8 contactsPromise: Promise // or any other constructor 9 }
c.传递静态或者动态prop
1 <!-- 静态赋值 --> 2 <blog-post title="My journey with Vue"></blog-post> 3 <!-- 动态赋予一个变量的值 --> 4 <blog-post v-bind:title="post.title"></blog-post> 5 <!-- 动态赋予一个复杂表达式的值 --> 6 <blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>
d.传递的数据可以是字符串、数组、数字、对象、布尔值
1 //父组件 2 <template> 3 <div id="app"> 4 <users v-bind:users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名 5 </div> 6 </template> 7 <script> 8 import Users from "./components/Users" 9 export default { 10 name: 'App', 11 data(){ 12 return{ 13 users:["Henry","Bucky","Emily"] 14 } 15 }, 16 components:{ 17 "users":Users 18 } 19 }
1 //子组件 2 <template> 3 <div class="hello"> 4 <ul> 5 <li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面 6 </ul> 7 </div> 8 </template> 9 <script> 10 export default { 11 name: 'HelloWorld', 12 props:{ 13 users:{ //这个就是父组件中子标签自定义名字 14 type:Array, 15 required:true 16 } 17 } 18 } 19 </script>
2.$emit--子组件向父组件传值(通过事件形式)
1 // 子组件 2 <template> 3 <header> 4 <h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件 5 </header> 6 </template> 7 <script> 8 export default { 9 name: 'app-header', 10 data() { 11 return { 12 title:"Vue.js Demo" 13 } 14 }, 15 methods:{ 16 changeTitle() { 17 this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值” 18 } 19 } 20 } 21 </script>
1 // 父组件 2 <template> 3 <div id="app"> 4 <app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致 5 // updateTitle($event)接受传递过来的文字 6 <h2>{{title}}</h2> 7 </div> 8 </template> 9 <script> 10 import Header from "./components/Header" 11 export default { 12 name: 'App', 13 data(){ 14 return{ 15 title:"传递的是一个值" 16 } 17 }, 18 methods:{ 19 updateTitle(e){ //声明这个函数 20 this.title = e; 21 } 22 }, 23 components:{ 24 "app-header":Header, 25 } 26 } 27 </script>
总结:子组件通过 events 给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。
方法二、
$parent和
$children
与 ref
ref:如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件实例。
$parent / $children:访问父 / 子实例。
需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。
我们先来看个用 ref
来访问组件的例子:
1 // 子组件 2 export default { 3 data () { 4 return { 5 title: '这是子组件的数据' 6 } 7 }, 8 methods: { 9 sayHello () { 10 console.log('hello');
11 } 12 } 13 }
1 // 父组件 2 <template> 3 <children ref="comA"></children> //首先你的给子组件做标记 4 </template> 5 <script> 6 export default { 7 mounted () { 8 const comA = this.$refs.comA; 9 console.log(comA.title); // 这是子组件的数据 10 comA.sayHello(); // hello 11 } 12 } 13 </script>
用$parent / $children直接访问组件实例
1 在父组件中 2 this.$children 3 在子组件中 4 this.$parent
方法三、vuex
参照博客:https://segmentfault.com/a/1190000015782272
1.安装vuex
1 pm install vuex --save
2.在src文件目录下新建一个名为store的文件夹,为方便引入并在store文件夹里新建一个index.js,里面的内容如下:
1 import Vue from 'vue'; 2 import Vuex from 'vuex'; 3 Vue.use(Vuex); 4 const store = new Vuex.Store(); 5 export default store;
3.接下来,在 main.js里面引入store,然后再全局注入一下,这样一来就可以在任何一个组件里面使用this.$store了:
1 import store from './store'//引入store 2 new Vue({ 3 el: '#app', 4 router, 5 store,//使用store 6 template: '<App/>', 7 components: { App } 8 })
4.配置state、getter、mutation、action
1 import Vue from 'vue'; 2 import Vuex from 'vuex'; 3 Vue.use(Vuex); 4 const state={ //要设置的全局访问的state对象 5 showFooter: true, 6 changableNum:0 7 //要设置的初始属性值 8 }; 9 const getters = { //实时监听state值的变化(最新状态) 10 isShow(state) { //承载变化的showFooter的值 11 return state.showFooter 12 }, 13 getChangedNum(){ //承载变化的changebleNum的值 14 return state.changableNum 15 } 16 }; 17 const mutations = { 18 show(state) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象); 19 state.showFooter = true; 20 }, 21 hide(state) { //同上 22 state.showFooter = false; 23 }, 24 newNum(state,sum){ //同上,这里面的参数除了state之外还传了需要增加的值sum 25 state.changableNum+=sum; 26 } 27 }; 28 const actions = { 29 hideFooter(context) { //自定义触发mutations里函数的方法,context与store 实例具有相同方法和属性 30 context.commit('hide'); 31 }, 32 showFooter(context) { //同上注释 33 context.commit('show'); 34 }, 35 getNewNum(context,num){ //同上注释,num为要变化的形参 36 context.commit('newNum',num) 37 } 38 }; 39 const store = new Vuex.Store({ 40 state, 41 getters, 42 mutations, 43 actions 44 }); 45 export default store;
而在外部组件里进行全局执行actions里面方法的时候,你只需要用执行:
this.$store.dispatch('hideFooter')
或this.$store.dispatch('showFooter')
以及this.$store.dispatch('getNewNum',6) //6要变化的实参
想要获取state值:
this.$store.state
5.modules 模块化 以及 组件中引入 mapGetters、mapActions 和 mapStates的使用
因为在大多数的项目中,我们对于全局状态的管理并不仅仅一种情况的需求,有时有多方面的需求,比如写一个商城项目,你所用到的全局state可能是关于购物车这一块儿的也有可能是关于商品价格这一块儿的;像这样的情况我们就要考虑使用vuex中的 modules 模块化了,具体怎么使用modules呢?咱们继续一步一步的走:
首先,在store文件夹下面新建一个modules文件夹,然后在modules文件里面建立需要管理状态的js文件(collection.js 、footerStatus.js),既然要把不同部分的状态分开管理,那就要把它们给分成独立的状态文件了。
而对应的store文件夹下面的index.js 里面的内容就直接改写成:
1 import Vue from 'vue'; 2 import Vuex from 'vuex'; 3 import footerStatus from './modules/footerStatus' 4 import collection from './modules/collection' 5 Vue.use(Vuex); 6 export default new Vuex.Store({ 7 modules:{ 8 footerStatus, 9 collection 10 } 11 });
1 //collection.js 2 const state={ 3 collects:[], //初始化一个colects数组 4 }; 5 const getters={ 6 renderCollects(state){ //承载变化的collects 7 return state.collects; 8 } 9 }; 10 const mutations={ 11 pushCollects(state,items){ //如何变化collects,插入items 12 state.collects.push(items) 13 } 14 }; 15 const actions={ 16 invokePushItems(context,item){ //触发mutations里面的pushCollects ,传入数据形参item 对应到items 17 context.commit('pushCollects',item); 18 } 19 }; 20 export default { 21 namespaced:true,//用于在全局引用此文件里的方法时标识这一个的文件名 22 state, 23 getters, 24 mutations, 25 actions 26 }
1 //footerStatus.js 2 const state={ //要设置的全局访问的state对象 3 showFooter: true, 4 changableNum:0 5 //要设置的初始属性值 6 }; 7 const getters = { //实时监听state值的变化(最新状态) 8 isShow(state) { //承载变化的showFooter的值 9 return state.showFooter 10 }, 11 getChangedNum(){ //承载变化的changebleNum的值 12 return state.changableNum 13 } 14 }; 15 const mutations = { 16 show(state) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象); 17 state.showFooter = true; 18 }, 19 hide(state) { //同上 20 state.showFooter = false; 21 }, 22 newNum(state,sum){ //同上,这里面的参数除了state之外还传了需要增加的值sum 23 state.changableNum+=sum; 24 } 25 }; 26 const actions = { 27 hideFooter(context) { //自定义触发mutations里函数的方法,context与store 实例具有相同方法和属性 28 context.commit('hide'); 29 }, 30 showFooter(context) { //同上注释 31 context.commit('show'); 32 }, 33 getNewNum(context,num){ //同上注释,num为要变化的形参 34 context.commit('newNum',num) 35 } 36 }; 37 export default { 38 namespaced: true, //用于在全局引用此文里的方法时标识这一个的文件名 39 state, 40 getters, 41 mutations, 42 actions 43 }
mapState,mapGetters,mapActions的使用:首先 在需要用的 组件里面先导入 import {mapState,mapGetters,mapActions} from 'vuex';
1 <template> 2 <div class="children1"> 3 <button class="joinStatus" @click="invokePushItems(item)">加入收藏列 然后跳转到children2页面查看</button> 4 <li v-for="(val,index) in arrList" :key="index"> 5 <h5>{{val.productName}}</h5> 6 <p>{{val.price}}</p> 7 </li> 8 </div> 9 </template> 10 11 <script> 12 import {mapState,mapGetters ,mapActions} from "vuex"; 13 export default { 14 name: "children1", 15 data() { 16 return { 17 item: { 18 id: "01", 19 productName: "苹果", 20 price: "1.6元/斤" 21 } 22 }; 23 }, 24 methods: { 25 ...mapActions("collection", [ 26 //collection是指modules文件夹下的collection.js 27 "invokePushItems" //collection.js文件中的actions里的方法,在上面的@click中执行并传入实参 28 ]) 29 }, 30 computed: { 31 // ...mapState({ //用mapState来获取collection.js里面的state的属性值 32 // arrList:state=>state.collection.collects 33 // }), 34 ...mapGetters("collection", { 35 //用mapGetters来获取collection.js里面的getters 36 arrList: "renderCollects" 37 }) 38 } 39 }; 40 </script>
方法四、eventBus 兄弟组件通信
1.使用 eventBus 首先我们创建一个 bus.js 文件,里面的内容如下
import Vue from 'vue'; export default new Vue();
2.在需要使用 eventBus 的组件中引入上面创建的 bus.js 文件。
import Bus from 'common/js/bus.js';
3.发布Bus消息的组件
Bus.$emit('getTarget', event.target);
4.接收Bus消息的组件
Bus.$on('getTarget', target => {
console.log(target);
});
5.解决多次触发在发布组件添加解绑事件
beforeDestroy () { bus.$off('getTarget') },