一、数据共享与绑定
1、子组件调用父组件数据:.sync
<comp :foo.sync="bar"></comp>
会被扩展为:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:
this.$emit('update:foo', newValue)
猛一看不明白,下边我么通过一个实例(弹窗的关闭事件)来说明这个代码到底是怎么运用的。
<template>
<div class="details">
<myComponent :show.sync='valueChild' style="padding: 30px 20px 30px 5px;border:1px solid #ddd;margin-bottom: 10px;"></myComponent>
<button @click="changeValue">toggle</button>
</div>
</template>
<script>
import Vue from 'vue'
Vue.component('myComponent', {
template: `<div v-if="show">
<p>默认初始值是{{show}},所以是显示的</p>
<button @click.stop="closeDiv">关闭</button>
</div>`,
props:['show'],
methods: {
closeDiv() {
this.$emit('update:show', false); //触发 input 事件,并传入新值
}
}
})
export default{
data(){
return{
valueChild:true,
}
},
methods:{
changeValue(){
this.valueChild = !this.valueChild
}
}
}
</script>
2、父组件调用子组件函数$refs
当DOM渲染完成后,父组件可以通过 this.$refs[‘InspectionTable’]调用子组件的函数,但是子组件使用v-if的情况下不适用,需要子组件完成实例化即可调用。
// 父组件
<template>
<div>
<inspection-table ref="InspectionTable"/>
</div>
</template>
import InspectionTable from './components/InspectionTable'
<script>
export default {
components: {
InspectionTable
},
methods: {
ciick() {
console.log("执行")
const obj={}
this.$refs['InspectionTable'].tableRowClick(obj)
}
}
}
</script>
// 子组件文件名inspectionTable
<template>
<div>
子组件
</div>
</template>
<script>
export default {
methods: {
tableRowClick(obj) {
console.log(obj)
}
}
}
</script>
3、子组件调用父组件函数$emit
父组件通过@@to-detail=把函数传递给子组件,通过子组件 this.$emit(‘to-detail’, obj)触发父组件函数
// 父组件
<template>
<div>
<inspection-table @to-detail="changeRightPanel" />
</div>
</template>
import InspectionTable from './components/InspectionTable'
<script>
export default {
components: {
InspectionTable
},
methods: {
changeRightPanel(obj) {
console.log(obj)
}
}
}
</script>
// 子组件文件名inspectionTable
<template>
<div>
<el-button class="back" type="primary" size="small" plain icon="el-icon-arrow-left" @click="click()">返回</el-button>
</div>
</template>
<script>
export default {
methods: {
click() {
const obj={}
this.$emit('to-detail', obj)
}
}
}
</script>
简单例子
<hello @pfn="parentFn"></hello>
<script>
Vue.component('hello', {
template: '<button @click="fn">按钮</button>',
methods: {
// 子组件:通过$emit调用
fn() {
this.$emit('pfn', '这是子组件传递给父组件的数据')
}
}
})
new Vue({
methods: {
// 父组件:提供方法
parentFn(data) {
console.log('父组件:', data)
}
}
})
</script>
4、父与子和子与子的数据共享$on
子组件A:发送放使用$emit自定义事件把数据带过去。
<template>
<div>
<span>A组件-{{msg}}</span>
<input type="button" value="把A组件数据传递给B" @click="send">
</div>
</template>
<script>
import eventBus from './eventBus'; //需要引入父组件eventBus,可以理解为引入父组件实例
export default{
data(){
return{
msg:{
a:'111',
b:'222'
}
}
},
methods:{
send(){
eventBus.$emit('aevent',this.msg) // 通过父组件去广播
}
}
}
</script>
子组件B:接收方通过$on监听自定义事件的callback接收数据
<template>
<div>
<span>B组件,A传的数据为--{{msg}}</span>
</div>
</template>
<script>
import eventBus from './eventBus.vue' //需要引入父组件eventBus,可以理解为引入父组件实例
export default {
data(){
return{
msg:''
}
},
mounted(){
eventBus.$on('aevent',(val)=>{//监听事件aevent,回调函数要使用箭头函数。
console.log(val);//打印结果;我是a组件的数据。
})
}
}
</script>
父组件eventBus:
<template>
<div>
<childa></childa>
<br/>
<childb></childb>
</div>
</template>
<script>
import childa from './childa.vue';
import childb from './childb.vue';
export default{
componets:{
childa,
childb
},
data(){
return{
msg:''
}
},
created () {
this.$on('aevent',(val)=> { // 当然父组件也可以监听到
console.log(val)
})
},
}
</script>
5、vuex的数据共享和监听$store
store的定义,路径:src/store/modules/drainage-facilities/sluice-pump/storeFileName.js
const state = {
userInfo:{
id:' ',
name:' '
}
}
const mutations = {
setUserInfo(state, data) {
state.userInfo= data
}
}
const actions = {
}
export default {
namespaced: true,
state,
actions,
mutations
}
vue页面使用,路径:src/views/drainage-facilities/sluice-pump/problem-circulation/components/PumpPopup.vue
<template>
<div>
<span>{{userInfo1.name}}</span>
<imput v-model="userInfo2.name"></span>
</div>
</template>
<script>
import { mapState } from 'vuex' //需要引入
export default {
data(){
return{
userInfo3:''
}
},
computed: {
...mapState({ //第1种获取方法
userInfo: state => state.storeFileName.userInfo
}),
userInfo2:{ //第2种获取方法
get(){
console.log('取值时调用')
return this.$store.state.storeFileName.userInfo
},
set(value){
console.log('值改变时调用')
this.$store.commit('setPhoneNumber',value) //改变值,改变后--1,--2,---3都会调用,同一个内存地址
}
}
},
watch: {
'userInfo.name': function(val) {
console.log('监控值改变时调用')-----1
},
'userInfo2.name': function(val) {
console.log('监控值改变时调用')-----2
},
'$store.state.storeFileName.userInfo': function(val) {
console.log('监控值改变时调用')-----3
}
},
mounted(){
this.userInfo3=this.$store.state.storeFileName.userInfo
}
}
</script>
6、vuex的双向数据绑定$store set commit
我在vue项目使用store存储变量,在页面input进行属性的双向绑定时,报出Computed property “route” was assigned to but it has no setter的错误,查找很多原因,参考官方文件找到了 解决方法。要在computed中添加get和set两个方法。
<input type="text" v-model="phoneNumber">
computed:{
phoneNumber:{
get(){
console.log('取值时调用')
return this.$store.state.phoneNumber
},
set(value){
console.log('值改变时调用')
this.$store.commit('setPhoneNumber',value)
}
}
}
state: {
phoneNumber:'',
},
mutations: {
setPhoneNumber(state,val){
state.phoneNumber=val
}
}
7、检查组件是否绑定了事件
父组件
<ag-panel-box @header-click="showPopup()"></ag-panel-box>
子组件ag-panel-box
export default {
name: 'AgPanelBox',
computed: {
headerClick() {
// 检查是否绑定了事件
return Boolean(this.$listeners['header-click'])
}
},
}
8、组件的数据状态传递
父组件
<joint-duty-popup :visible.sync="dialogVisible" :row-data="dialogRowData" />
子组件
<template>
<el-dialog title="签到信息" :visible.sync="dialogVisible">
弹窗内容
<div class="btn-list">
<el-button size="mini" @click="cancelFun()">取消</el-button>
<el-button type="primary" size="mini" @click="confirmFun()">确定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'JointDutyPopup',
components: {
},
props: {
visible: {
type: Boolean,
default: true
},
rowData: {
type: Object,
default: () => {}
}
},
data() {
return {
}
},
computed: {
dialogVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
watch: {
visible: {
handler(val) {
this.dialogVisible = val
console.log(this.dialogVisible)
},
deep: true
},
rowData: { // 初始化
handler(val) {
console.log(val)
},
deep: true,
immediate: true
}
},
mounted() {
},
methods: {
cancelFun() {
this.dialogVisible = false
},
confirmFun() {
// if (this.checkNodes.length === 0) {
// this.$message.error('未选择任何内容!')
// } else {
// this.$emit('change', this.checkNodes)
// this.treeVisible = false
// }
}
}
}
</script>
<style lang="scss" scoped>
.btn-list {
width: 100%;
margin-top: 10px;
text-align: right;
}
</style>