下面是vue官网的介绍
在多个子组件项目中使用这个非常好用。子组件数据传递,我们可能先想到先把子组件数据传到父组件,再由父组件传给另一个子组件,这样使很麻烦的。
现在我们建立一个js文件,让两个子组件或多个子组件共享这里的数据,这里提供读取和修改方法。我在真实的项目中用到这些,用到了elementUI组件,两个Dialog弹窗的嵌套。下面我这个demo的结构跟我真实项目一致,只是数据不同。
父组件
<template>
<div id="observable-box">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="number" label="学生证编号" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="professional" label="专业" width="180" />
<el-table-column prop="theClass" label="班级" />
<el-table-column
prop="clubMember"
label="俱乐部"
:formatter="formatter"
/>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
type="primary"
size="mini"
@click="modify(scope.row)"
>修改</el-button
>
<el-button
type="primary"
size="mini"
:disabled="scope.row.clubMember !== 1"
@click="applyQualification(scope.row)"
>申请会员</el-button
>
</template>
</el-table-column>
</el-table>
<el-dialog
title="修改个人信息"
:visible.sync="dialogVisible"
width="800px"
>
<Modify
:modify="needModifyObj"
@modifyFinish="modifyFinish"
@closeDialog="closeDialog"
/>
<MoreInfo />
</el-dialog>
</div>
</template>
<script>
import { students } from '@/mook/observableData.js'
import Modify from '@/components/vueObservable/modify.vue'
import MoreInfo from "@/components/vueObservable/moreInfo.vue"
export default {
name: 'Observable',
components: {
Modify,
MoreInfo
},
data() {
return {
tableData: students,
dialogVisible: false,
needModifyObj: {}
}
},
methods: {
modify(row) {
console.log("11:", row);
this.dialogVisible = true;
this.needModifyObj = { ...row }
},
// 申请会员资格
applyQualification(row) {
console.log(row);
},
formatter(row) {
return row.clubMember === 1 ? "非会员" : "会员"
},
modifyFinish(data) {
this.tableData.forEach(item => {
if (item.number === data.number) {
const { professional, name, theClass } = data
item.professional = professional;
item.name = name;
item.theClass = theClass;
}
})
},
closeDialog() {
this.dialogVisible = false;
}
},
}
</script>
核心代码就是子组件Modify和MoreInfo
子组件Modify
<template>
<div class="observable-motify">
<el-form ref="form" :model="form" label-width="100px">
<el-form-item label="学生证编号:">
<el-input v-model="form.number" disabled></el-input>
</el-form-item>
<el-form-item label="姓名:">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="专业:">
<el-input v-model="form.professional"></el-input>
</el-form-item>
<el-form-item label="班级:">
<el-input v-model="form.theClass"></el-input>
</el-form-item>
<el-form-item label="个人成就:">
<el-button @click="moreInfo" type="primary">添加</el-button>
<el-table :data="achievementData" style="width: 100%">
<el-table-column prop="time" label="时间" width="180" />
<el-table-column prop="type" label="成就" width="180" />
<el-table-column label="操作">
<template>
<el-button type="text" size="mini" @click="remove"
><i class="el-icon-close"></i
></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<el-row type="flex" justify="center">
<el-button type="primary" @click="confirm">确 定</el-button>
<el-button type="primary" @click="cancel">取 消</el-button>
</el-row>
</div>
</template>
<script>
import { isEmptyObject } from '@/utils/common.js'
import { store, mutations, resetStore } from './bus.js'
export default {
props: {
modify: {
type: Object,
default: () => { }
},
},
data() {
return {
form: {
number: '',
name: '',
professional: '',
theClass: '',
}
}
},
computed: {
// 该数据是moreInfo.vue选中之后保存在store.achievementList里,这里直接读取就ok
achievementData() {
return store.achievementList
}
},
created() {
this.init()
},
methods: {
init() {
// 如果不是{}就赋值
if (!isEmptyObject(this.modify)) {
this.form = { ...this.modify }
}
},
// 确定
confirm() {
if(this.achievementData && this.achievementData.length){
// 把一条个人成就插入到form表单中
this.$set(this.form,"oneAchievement",this.achievementData)
}
// 派发事件,修改完把数据回传
this.$emit("modifyFinish", this.form);
this.$emit('closeDialog');
console.log(JSON.parse(JSON.stringify(this.form)));
},
cancel() {
this.$emit('closeDialog');
},
moreInfo() {
// 重置一下数据
resetStore.resetFunc();
// 打开弹窗
mutations.setMoreInfoVisible(true)
},
// 移除数据
remove() {
mutations.setAchievementList([])
}
},
}
</script>
子组件MoreInfo
<template>
<div class="observable-motify">
<el-dialog
append-to-body
title="荣耀时刻"
:visible.sync="dialogVisible"
:before-close="beforeClose"
@open="openDialog"
width="800px"
>
<el-form ref="form" :model="form" label-width="100px" inline>
<el-form-item label="时间段">
<el-input v-model.trim="form.time"></el-input>
</el-form-item>
<el-form-item label="获得成就">
<el-input v-model.trim="form.type"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="search" type="primary">搜索</el-button>
</el-form-item>
</el-form>
<el-table :data="searchResult" style="width: 100%">
<el-table-column prop="time" label="时间" />
<el-table-column prop="type" label="成就" />
<el-table-column label="选择" center>
<template slot-scope="scope">
<el-radio
v-model="radio"
:label="scope.$index"
@change.native="getCurrentRow(scope.row)"
style="
color: #fff;
padding-left: 10px;
margin-right: -25px;
"
>{{ "" }}
</el-radio>
</template>
</el-table-column>
</el-table>
<el-row type="flex" justify="center" style="margin-top: 20px">
<el-button type="primary" @click="confirm">确 定</el-button>
<el-button type="primary" @click="cancel">取 消</el-button>
</el-row>
</el-dialog>
</div>
</template>
<script>
import { achievement } from '@/mook/observableData.js'
import { store, mutations } from './bus.js'
export default {
data() {
return {
form: {
time: '',
type: ''
},
searchResult: [],
radio: '',
selectSearch: []
}
},
computed: {
dialogVisible() {
return store.moreInfoVisible
}
},
methods: {
// 模拟搜索接口,模拟模糊查询
search() {
this.searchResult = [];
if (!this.form.time && !this.form.type) {
this.$message.error('请输入查询条件');
} else if (this.form.time && this.form.type) {
achievement.forEach(item => {
if (item.time.includes(this.form.time) && item.type.includes(this.form.type)) {
this.searchResult.push(item)
}
})
} else if (this.form.time && !this.form.type) {
achievement.forEach(item => {
if (item.time.includes(this.form.time)) {
this.searchResult.push(item)
}
})
} else if (!this.form.time && this.form.type) {
achievement.forEach(item => {
if (item.type.includes(this.form.type)) {
this.searchResult.push(item)
}
})
}
},
cancel() {
// 关闭弹窗
mutations.setMoreInfoVisible(false);
},
// 选中数据后,确认
confirm() {
// 如果没有选中,有报错提示
if (!this.selectSearch.length) {
this.$message.error('请先选中后再提交');
return;
}
// 把数据存放到store
mutations.setAchievementList(this.selectSearch);
// 关闭弹窗
mutations.setMoreInfoVisible(false);
},
// 选中搜索出来的数据(单选)
getCurrentRow(row) {
this.selectSearch = [];
this.selectSearch.push({ ...row })
},
// 关闭弹窗触发的回调
beforeClose() {
mutations.setMoreInfoVisible(false);
},
// 打开弹窗触发的回调
openDialog() {
// 初始化
this.searchResult = [];
this.selectSearch = [];
}
},
}
</script>
<style scoped lang="less">
/deep/.el-radio__input.is-checked + .el-radio__label {
color: #fff;
}
</style>
bus.js
import Vue from 'vue';
// 读取
const store =Vue.observable(
{
moreInfoVisible: false,
achievementList:[],
});
// 修改
const mutations = {
setMoreInfoVisible(val){
store.moreInfoVisible = val;
},
setAchievementList(array){
store.achievementList = array;
}
}
// 重置
const resetStore = {
resetFunc(){
store.moreInfoVisible = false;
store.achievementList = [];
}
}
export {
store,
mutations,
resetStore
}
核心代码分析
组件MoreInfo弹窗的打开要依赖组件Modify的添加按钮。我把控制组件MoreInfo关闭的moreInfoVisible放在了bus.js里,引入了bus.js, 组件Modify页面就直接改变moreInfoVisible,组件MoreInfo可以直接读取moreInfoVisible来决定自己的打开和关闭。
对应参数achievementList也是同理,我需要在组件MoreInfo获取,然后存到bus.js的observable里,组件Modify监听bus.js里面的achievementList
最后想看我的源代码在github上:https://github.com/ineedyou1024/front-end-knowledge.git
最后可以互相fork一下,互相学习。