vue组件的作用域是相对独立的,因此组件与组件之间的传值就相当的重要。
vue组件与组件之间的关系可简单概括为:父子组件、兄弟组件、隔代组件
类型一:父子组件传值:
父组件向子组件传值通常采用绑定属性的方法。子组件通过props数组获取父组件的数据。
1、一个组件可以直接渲染vue里data中的数据。
2、子组件不能直接渲染父组件的数据。
3、如果子组件想要引用父组件的数据,父组件可以在引用子组建的时候,采用绑定属性的方式(v-bind:)将数据传递到子组件的内部。然后在子组件中将传递过来的数据在props数组中定义一下。
<div id='app'>
<com1 :parentmsg="msg"></com1>
</div>
<script>
var vm=new Vue({
el:'#app',
date:{
msg:'我是父组件的数据'
},
components:{
com1:{
data{ //子组件的data数据并不是从父组件传递过来的,而是子组件本身定义的。
ruturn{ //通过ajax请求数据也可以放在子组件的data中。
title:'yan', //data里的数据是双向的,可读可写的。
content:'123456'
}
},
template: '<h1 @click="change">这是子组件 {{parentmsg}}</h>'
props:['msg'],
mothods:{
change(){
this.msg="修改了";
}
}
}
}
})
</script>
1、 e m i t 子 组 件 通 过 事 件 向 父 组 件 传 值 , emit子组件通过事件向父组件传值, emit子组件通过事件向父组件传值,emit
父组件
<template>
<div>
<div class="title">{{title}}<div>
<child @changeTitle="parentTitle"></chaild>
</div>
</template>
<script>
import Child from "./compontent/child.vue"
export default {
data() {
return {
title: null
}
},
components: {
Child
},
methods: {
parentTitle(e) {
this.title = e
}
}
}
</srcipt>
子组件1
<template>
<div>
<button @click="childTitle">给父组件传值</button>
</div>
</template>
<script>
export default {
data() {
return {
key: ''
}
},
methods: {
childTitle() {
this.$emit('changeTitle',`我是第{{this.key}}次传值`)
this.key++
}
}
}
</script>
类型二: 任意组件传值。
通过一个空的vue实例,作为中央事件总线(事件中心),用它来触发事件,和监听事件,巧妙而轻量的实现了任何组件间的通信,包括父子组件,兄弟组件、跨级组件。
父组件
<template>
<div>
<child1 :Event="Event"></child1>
<child2 :Event="Event"></child2>
<child3 :Event="Event"></child3>
</div>
</template>
<script>
export default {
data() {
return {
Event: Event
}
},
components: {
Child1,
Child2,
Child3
}
}
</scrtip>
子组件一
<template>
<div class="center">
<button @click="send">给3组件赋值</button>
</div>
</template>
<script>
export default {
data() {
return {
name: 'yan'
}
},
props: {
Event
},
methods: {
send() {
this.Event.$emit('mes1',this.name)
}
}
}
</script>
子组件二
<template>
<div class="center">
<button @click="send">给组件3赋值</button>
</div>
</template>
<script>
export default {
data() {
return {
age: '23'
}
},
props: {
Event
},
methods: {
send() {
this.Event.$emit('mes2',this.age)
}
}
}
</script>
组件三
<template>
<div class="center">
我的名字是{{name}},今年{{age}}岁
</div>
</template>
<script>
export default {
date() {
return {
name: '',
age: ''
}
},
props: {
Event
},
mount() {
this.Event.$on('msg1',name => {
this.name = name
})
this.Event.$on('msg2',age => {
this.age = age
})
}
}
</script>
类型三 vuex
1、vuex的原理
vuex是单项数据流,在全局拥有一个state存放数据,当组件要更改state中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。当所有异步操作(调用后端接口异步跟新数据)或批量的同步操作需要走Action,但是Action也无法直接修改State,还需要Muation来修改State的数据。
2、个模块作用
Vue Components: Vue组件。执行dispatch方法,触发对应的acton进行回应。
dispatch: 操作行为触发方法,是唯一能执行action的方法。
action: 操作行为处理模块,由组件中的$store.dispatch(‘action名称’,date1)来触发。然后由commit()来触发mutaion的调用,间接的更新state。负责处理Vue Components接收的所有交互行为,按照注册的顺序依次触发。想后台API请求的操作就在这个模块进行,包括触发其他action以及提交mutation的操作,以支持action 的链式触发。
commit: 状态改变提交操作方式。对mutation 进行提交,是唯一能执行mutation 的方法。
mutation: 状态改变操作方法,由actions 中的commit(‘mutation名称’)来触发,是vuex修改state的唯一推荐方法,该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
state: 页面状态管理容器对象。集中存储Vue Commpents中data对象的零散数据,全局唯一,以进行统一的状态管理,页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据机制来进行高效的状态更新。
getters: state对象读取方法。通常在getter中对后端API请求来的数据进行过滤。
3、vuex与localStorage
Vuex是vue的状态管理器,存储的数据是响应式的。但并不会保存起来,刷新之前就会到来初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保留到localStorge里面,刷新之后,如果localStorge里有保存的数据,取出来再替换store里的state。
经典案例:登录时的token存储
import { login, logout } from "@/api/user";
import { getAccessToken, setAccessToken, removeAccessToken } from "@/utils/accessToken";
export default new Vuex.Store({
state: {
accessToken: getAccessToken(),
},
getters: {
accessToken: (state) => state.accessToken,
},
mutations: {
setAccessToken(state, accessToken) {
state.accessToken = accessToken;
}
},
actions: {
async login({commit}, userInfo) {
const { data } = await login(userInfo);
commit("setAccessToken", accessToken);
setAccessToken(accessToken);
}
async logout({ commit, dispatch }) {
await logout(state.accessToken);
removeAccessToken();
}
}
})
utils/accessToken.js
// 获取token
export function getAccessToken() {
return localStorage.getItem("Authorization");
}
// 存储token
export function setAccessToken(accessToken) {
return localStorage.setItem("Authorization", accessToken);
}
// 删除token
export function removeAccessToken() {
return localStorage.removeItem("Authorization")
}
方法四: 多级组件嵌套
多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但是如果仅仅是传递数据,而不做中间处理,使用vuex处理,未免有点大材小用。
$attrs:
包含父子作用域中不被prop识别的特性绑定(class和style除外)。当一个组件没有申明任何prop时,这里会包含所有父子作用域的绑定(class和style除外),并且可以通过v-bind="$attrs"
传入内部组件。通常配合 interitAttrs选项一起使用。
$listeners:
包含了父作用域中的(不含.native修饰器)v-on事件监听器,可以通过v-on="$listenters"
传入内部组件。在创建高层次的组件时非常有用。
父组件
<template>
<child :name="name" :age="age" :infoObj="infoObj" @updataInfo="updateInfo" :delInfo="delInfo"></child>
<template>
<script>
import Child from "../components/child.vue";
export default {
name: "father",
components: { Child },
data() {
return {
name: "cy",
age: "22",
infoObj: {
come: "xiangyang",
job: "IT"
},
};
},
methods: {
undateInfo() {
console.log("更新数据");
},
delInfo() {
console.log("删除数据");
},
}
}
</script>
子组件
<template>
// 通过$listeners将父作用域的事件,传入grandSon组件,使其可以获取到father中的事件
<grand-son :height="height" :weight="weight" @addInfo="addInfo" v-bind="$attrs" v-on="$listeners" />
</template>
<script>
import GrandSon from "../components/grandSon.vue";
export default {
name: "child",
components: { GrandSon },
props: ['name'],
data() {
return {
height: "156cm",
weight: "45kg",
}
},
created() {
console.log(this.$attrs); // age, infoObj 因为name被props接收了
console.log(this.$listeners) // undateInfo, delInfo
}
</script>
孙组件
<template>
<div>
{{ $attrs }} --- {{ $listeners }}
</div>
</template>
<script>
export default {
name: "grandSon"
props: ["weight"],
created() {
console.log(this.$attrs); // aga, infoObj, height
console.log(this.$listeners) // updataInfo, delInfo, addInfo,
this.$emit("updataInfo") // 触发父组件的函数
}
}
</script>
五、 $parent/ $root 与 $refs/ $children
这三种方法都可以得到组件实例,然后就可以直接调用组件里的方法或者数据。
父组件
<template>
<div>
<span>{{ name }}</span>
<child ref="child"/>
</div>
</template>
<script>
import Child from "./child";
export default {
name: "Father",
components: { Child },
data(){
return {
name: "cy",
}
}
mounted() {
console.log(this.$refs.child.Child_name);
console.log(this.$refs.child.getName());
// 效果相同
console.log(this.$children[0].Child_name);
console.log(this.$children[0].getName());
},
}
</script>
子组件
<template>
<div>
<span>{{ Child_name }}</span>
<grand-son ref="grandSon"/>
<div>
<template>
<script>
import { GrandSon } from "./grandfSon";
export default {
name: "Child",
components: {
GrandSon,
},
data() {
return {
Child_name: "caicai",
, }
},
mounted(){
console.log(this.$parent.name); // cy
console.log(this.$refs.grandSon.grandSon_name); // xiaocaicai
// 效果相同
console.log(this.$children.grandSon_name); // xiaocaicai
},
methods: {
getName() {
console.log(this.Child_name);
},
}
}
</script>
孙组件
<template>
<div>
<span>{{ grandSon_name }}</span>
<div>
<template>
<script>
export default {
name: "GrandSon",
data() {
return {
grandSon_name: "xiaocaicai",
}
},
mounted() {
console.log(this.$parent.child_name); // caicai
console.log(this.$root.name); // cy
}
}
</script>