逐级传递传值的方法:
props,自定义事件( $ emit),$ router.push
跨组件传值的方法:
消息订阅与发布(pubsub),eventBus,vuex
1、props
可以是数组、对象或字符串,用于接收来自父组件的数据
自上而下的数据传递,即父 => 子 => 孙,只能逐级传递
props使用方法:
在父组件中导入子组件
import TableThead from '../components/TableThead'
components:{
TableThead
}
}
在父组件中调用子组件
//tbHeadArr:当前父组件的数据
//tbHeadFun:当前父组件的函数
//tbHead:变量名
<TableThead :tbHeadArr="tbHeadArr" :tbHeadFun="tbHeadFun">
<th slot="tbHeadOper">操作</th>
</TableThead>
在子组件中通过props得到tbHeadArr得值,并声明类型
<script>
export default {
name: "TableThead",
props:{
tbHeadArr:{
type:Array,
default:[]
},
tbHeadFun:{
type:Function
}
}
}
</script>
在页面中就可以直接使用变量tbHeadArr了
<template>
<thead>
<tr @click="tbHeadFun">
<th v-for="item in tbHeadArr">{{item}}</th>
<slot name="tbHeadOper"></slot>
</tr>
</thead>
</template>
2、自定义事件
可以是数组、对象或字符串,用于传值给父组件
自下而上的数据传递,即孙 => 子 => 父,只能逐级传递
自定义事件使用方法:
在调用子组件的时候,定义一个自定义事件
<!--custom自定义函数名-->
<componentOne :compOneName="indexName" @custom="changeName"></componentOne>
父组件中定义函数changeName,修改相应值
data(){
return {
indexName:"lhm"
}
},
methods:{
// obj:接受子组件传过来的数据
changeName(obj){
console.log(obj.name)
//修改相应数据
this.indexName=obj.name
}
}
在子组件中定义一个click事件,用于触发自定义事件
<button @click="changeFatherData">改变名字</button>
methods:{
changeFatherData(){
//触发自定义函数
// {name:'hello'}:欲修改的数据
this.$emit("custom",{name:'hello'})
}
}
3.消息订阅与发布
下载:npm install pubsub-js
订阅消息---------绑定事件监听
发布消息---------触发事件
在组件1订阅消息:
import PubSub from "pubsub-js" //导入模块
mounted(){
PubSub.subscribe('函数名', (msg,data)=> {
//数据操作
})
}
在组件2发布消息:
import PubSub from "pubsub-js" //导入模块
methods:{
myFunction(){
PubSub.publish('函数名',data)
}
}
4.eventBus
可以是数组、对象或字符串,用于传值给其他组件,可跨级传递
eventBus的使用方法
src根目录下新建文件bus.js,作为中转站
import Vue from "vue"
export default new Vue({})
以下例子实现:
通过组件1传值给组件2,且组件1值改变,组件2能跟着改变
组件1:
html代码:
<div>
<h3>{{age}}岁</h3>
<button @click="changeAge">改变年龄</button>
</div>
js代码:
<script>
//导入bus:`import bus from "../bus"`
import bus from "../bus"
export default {
name: "componentTwoChild",
data(){
return{
//初始值
age:20
}
},
methods:{
changeAge(){
this.age++
bus.$emit("getGrade",this.age)
}
},
//渲染dom节点的时候调用
mounted(){
bus.$emit("getGrade",this.age)
}
}
</script>
组件2:
html代码:
<div>
<h3>{{age}}岁</h3>
</div>
js代码:
<script>
//导入bus:`import bus from "../bus"`
import bus from "../bus"
export default {
name: "componentOne",
data(){
return{
age:0
}
},
beforeCreate(){
bus.$on("getGrade",(num)=>{
this.age = num
})
}
}
</script>
5.vuex
可以是数组、对象或字符串,用于传值给其他组件,可跨级传递,它采用集中式存储管理应用的所有组件的状态
vuex的使用
1、在src根目录下新建一个文件夹store
store下新建一个modules文件夹,该文件夹下可以建不同的功能模块,把容器分成几块,把状态和管理规则分类来装,每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
2、store下新建一个index.js文件
//导入vue
import Vue from 'vue'
//导入vuex
import Vuex from 'vuex'
//导入我的vuex模块
import vueStar from './modules/vueStar'
Vue.use(Vuex)
//公开对象的Store
export default new Vuex.Store({
modules:{
vueStar
}
})
或者直接动态引入
import { createStore } from 'vuex'
import "es6-promise/auto";
const modulesFiles = require.context("./module", true, /\.js$/);
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, "$1");
const value = modulesFiles(modulePath);
modules[moduleName] = value.default;
return modules;
}, {});
export default createStore({
state: {
},
mutations: {
},
actions: {
},
modules
});
3、修改main.js
//导入store
import store from './store/index'
new Vue({
router,
//实例使用store
store,
render: h => h(App)
}).$mount('#app')
4、store下新建一个modules文件夹,该文件夹下可以建不同的功能模块,把容器分成几块,把状态和管理规则分类来装
顺序依次是:组件1 》actions 》 mutations 》 state 》组件2
本案例先建一个vueStar.js文件
//存放公共的状态
const state={
classId:"1001",
login:false
}
//通过store.dispatch触发,存放如何更改状态,state和mutations的中转站,包含任意异步操作
//context是与 store 实例具有相同方法和属性的 context 对象,可以通过context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters
const actions={
setClassId(context,myClassId){
context.commit("setStateClassId",myClassId)
},
login(context,obj){
context.commit("setLogin",obj)
}}
// 可以通过store.commit ,或者actiocs中的context.commit 调用mutations中的方法来改变状态,同步函数
const mutations={
setStateClassId(state,myClassId){
state.classId=myClassId
},
setLogin(state,obj){
if(obj.name=='lhm'&&obj.pwd==333){
state.login=true;
}
}
}
// 从state中派生出状态,等同于计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
const getters={
login(state){
return state.login
}
}
//公开对象
export default{
state,
actions,
mutations,
getters
}
5、以下例子实现:
通过vuex作为仓库,存放相应数据,组件1和组件2可以任意调用或修改这些数据
组件1
html代码:
<button @click="changeClassId">修改班级</button>
<button @click="login">登录</button>
js代码:
<script>
export default {
name: "indexPage",
methods:{
changeClassId(){
//调用store中actions对象得setClassId函数,传值
this.$store.dispatch("setClassId","欲修改得值");
},
login(){
let user={
name:"lhm",
pwd:333
}
//调用store中actions对象得setClassId函数,传值
this.$store.dispatch("login",user)
}
}
}
</script>
组件2
html代码:
<div>
<h3>{{classId}}班</h3>
</div>
//组件1点击修改班级后,store中该数据改变,但是组件2页面并不会响应,需调用changeClassId函数进行响应,若想要实现直接响应,可调用watch方法
<button @click="changeClassId">改变班级</button>
<p>我的登录状态{{loginState}}</p>
js代码:
<script>
export default {
name: "componentOne",
data(){
return{
classId:""
}
},
computed:{
//计算属性,相关数据或属性(store数据)改变时,自动调用
loginState(){
return this.$store.getters.login
}
},
methods:{
changeClassId(){
//修改页面的数据
this.classId=this.$store.state.vueStar.classId
}
},
created(){
this.classId=this.$store.state.vueStar.classId
},
watch:{
//监听$store.state.vueStar.classId的改变
'$store.state.vueStar.classId'(){
this.classId=this.$store.state.vueStar.classId
}
}
}
</script>
6.$ router.push或$ router.replace
$ router.push:点击路由链接(可以回退到当前路由界面)
$ router.replace:用新路由替换当前路由(不可以回退到当前路由界面)
html代码:
<el-button type="primary"
plain size="mini"
@click="renewPay(scope.row)">续借</el-button>
js代码:
renewPay(obj){
obj.duzhexingming=this.readerInfo.xingming
obj.duzhebianhao=this.readerId
obj.caozuo="续借"
//传参 obj
this.$router.push({path:"/library/settleAccounts", query:obj})
}
router拦截并跳转至另一个组件
{
path:"/library/settleAccounts",
name:"settleAccounts",
component:()=>import('../../views/settleAccounts'),
}
在另一个组件中使用this.$route.query
<el-col :span="10"><p>图书编号:{{this.$route.query.shujibianhao}}</p></el-col>