vue组件通信

182 阅读2分钟

vue2

props

父组件向子组件传递数据

自定义事件

子组件向父组件传递数据

v-model

1.实现父子组件双向通信

父组件:

<template>
  <div>
    <CustomInput v-model="sysUserName"></CustomInput>
    {{sysUserName}}
  </div>
</template>
​
export default {
  data() {
    return {
      sysUserName: "张三"
    };
  },
}

子组件:

<template>
  <div>
    <input name="sysUserName" :value="value" @input="$emit('input',$event.target.value)"></input>
  </div>
</template>
​
export default {
  props: ['value'],
}

原理:

绑定数据+自定义事件

父组件:父组件自定义input事件

<template>
  <div>
    <CustomInput :sysUserName="sysUserName" @input="sysUserName = $event "></CustomInput>
    {{sysUserName}}
  </div>
</template>

数据:

data() {
    return {
        sysUserName: "张三"
    };
},

子组件:@input是原生DOM事件

<template>
  <div>
    <input name="sysUserName" :value="sysUserName" @input="$emit('input',$event.target.value)"></input>
  </div>
</template>
​
export default {
  props: ['sysUserName'],
}

2.实现表单数据双向绑定

<template>
  <div>
    <input name="sysUserName" v-model="formData.sysUserName"></input>
    {{formData.sysUserName}}
  </div>
</template>
​
data() {
    return {
      formData: {
        sysUserName: "张三"
      },
    };
  },

原理:

数据绑定 + input事件赋值

<template>
  <div>
    <input name="sysUserName" :value="formData.sysUserName" @input="formData.sysUserName = $event.target.value"></input>
    {{formData.sysUserName}}
  </div>
</template>
​
data() {
    return {
      formData: {
        sysUserName: "张三"
      },
    };
  },

sync修饰符

父组件:

<template>
  <div>
    小明的爸爸现在有{{money}}元
    <h2>使用sync修改符</h2>
    <Child :money.sync="money"></Child>
    <hr>
  </div>
</template><script type="text/ecmascript-6">
  import Child from './Child.vue'
  export default {
    name: 'SyncTest',
    components: {
      Child
    },
    data() {
      return {
        money:10000
      }
    },
    methods:{}
  }
</script>

子组件:

<template>
  <div style="background: #ccc; height: 50px;">
    <span>小明每次花100元</span>
    <button @click="$emit('update:money',money-100)">花钱</button>
    爸爸还剩{{money}}元
  </div>
</template><script type="text/ecmascript-6">
  export default {
    name: 'Child',
    props:['money']
  }
</script>

原理:

父组件可以不使用sync修饰符:

自定义事件@update:money

<Child :money="money"  @update:money="money = $event"></Child>

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”money + 100” 是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model

childrenchildren和parent

this.$refs可以操作子组件的数据和方法

this.$refs.button.size = 'max'

this.$children可以获取所有的子组件,并操作子组件数据

this.$parent可以获取父组件,并操作父组件数据

父组件:

<template>
  <div>
    <h2>BABA有存款: {{ money }}</h2>
    <button @click="borrowFromXM">找小明借钱100</button><br />
    <button @click="borrowFromXH">找小红借钱150</button><br />
    <button @click="borrowFromAll">找所有孩子借钱200</button><br /><br />
    <!-- ref:可以获取到真实DOM节点,可以获取相应组件的实例VC -->
    <!-- ref也算在一种通信手段:在父组件中可以获取子组件(属性|方法) -->
    <Son ref="son" /><br />
    <Daughter ref="dau" />
  </div>
</template><script>
import Son from "./Son";
import Daughter from "./Daughter";
​
export default {
  name: "ChildrenParentTest",
  data() {
    return {
      money: 1000,
    };
  },
​
  methods: {
    //小明借用100元
    borrowFromXM() {
      //父亲的钱加上100元
      this.money += 100;
      this.$refs.son.money -= 100;
    },
    borrowFromXH() {
      this.money += 150;
      this.$refs.dau.money -= 150;
    },
    borrowFromAll() {
      //VC:$children属性,可以获取当前组件的全部子组件[这个属性在用的时候很少用索引值获取子组件,因为没有办法确定数组里面的元素到底是哪一个子组件]
      this.money += 400;
      this.$children.forEach((item) => {
          item.money -= 200;
      });
    },
  },
​
  components: {
    Son,
    Daughter,
  },
};
</script><style>
</style>

子组件son:

<template>
  <div style="background: #ccc; height: 50px;">
    <h3>儿子小明: 有存款: {{money}}</h3>
    <button @click="giveMoney">给BABA钱: 50</button>
  </div>
</template><script>
export default {
  name: 'Son',
  data () {
    return {
      money: 30000
    }
  },
​
  methods: {
    giveMoney(){
       this.money-=50;
       //$parent,VC一个属性,可以获取当前组件(属性|方法)
       this.$parent.money+=50;
    }
  }
}
</script>

子组件:

<template>
  <div style="background: #ccc; height: 50px;">
    <h3>女儿小红: 有存款: {{money}}</h3>
    <button @click="giveMoney">给BABA钱: 100</button>
  </div>
</template><script>
export default {
  name: 'Daughter',
  data () {
    return {
      money: 20000
    }
  },
​
  methods: {
    giveMoney(){
       this.money-=100;
       this.$parent.money+=100;
    }
  }
}
</script>

attrsattrs和listeners

父组件:

<template>
  <div>
     <h1>对于el-button进行二次封装</h1>
     <hintButton type="warning" icon="el-icon-s-help" size="mini" tip="豪哥提示信息" @click="handler"></hintButton>
  </div>
</template><script type="text/ecmascript-6">
  export default {
    name: 'AttrsListenersTest',
    methods: {
        handler(){
            console.log("自定义事件");
        }
    },
  }
</script>

子组件:

<template>
  <div :tip="$attrs.tip">
    <el-button :type="$attrs.type" :icon="$attrs.icon" :size="$attrs.size" v-on="$listeners">警告按钮</el-button>
  </div>
</template>
​
<script>
export default {
  name: "hintButton",
};
</script>
​

也可以简写:

<template>
  <div :tip="$attrs.tip">
    <el-button v-bind="$attrs" v-on="$listeners">警告按钮</el-button>
  </div>
</template>

<script>
export default {
  name: "hintButton",
};
</script>

attrsprops都可以接收父组件传递过来的数据,如果使用props接收数据,那么attrs和props都可以接收父组件传递过来的数据,如果使用props接收数据,那么attrs中就接收不到数据了

vue3

props

子组件接收:

对象式

const props = defineProps({
    modelValue: {
        type: String,
    },
    type: {
        type: String,
        default: 'text',
    },
    width: {
        type: [Number, String],
        default: '300px',
    },
})

数组形式:

const props = defineProps(['modelValue','type','width']);

自定义事件

子组件向父组件传递数据

父组件

<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />

子组件:

//定义事件
const emit = defineEmits(['sizeChange', 'currentChange']);
//触发事件
const sizeChangeHandle = (val: number) => {
    emit('sizeChange', val);
};
// 分页改变
const currentChangeHandle = (val: number) => {
    emit('currentChange', val);
};

v-model

父组件

<right-toolbar v-model:showSearch="showSearch"></right-toolbar>
                    
const showSearch = ref(true);                   

子组件:

<el-tooltip :content="showSearch ? '隐藏搜索' : '显示搜索'">
<el-button circle icon="Search" @click="toggleSearch()" />
const props = defineProps({
    /**
     * 是否显示搜索框
     */
    showSearch: {
        type: Boolean,
        default: true,
    }
})
const emits = defineEmits(['update:showSearch']);
const toggleSearch = () => {
    emits('update:showSearch', !props.showSearch);
};

多个 v-model 绑定

父组件:

<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>

子组件:

<script>
export default {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['update:firstName', 'update:lastName']
}
</script>
​
<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>

$attrs

父向子传递数据

父组件:

<child type="primary" size="large"></child>

子组件:

<template>
  <div>
    <el-button :type="$attrs.type" :size="$attrs.size">开关</el-button>
    <el-button v-bind="$attrs">开关</el-button>
    <el-button :="$attrs">开关</el-button>
  </div>
</template>

或者

<el-button :type="attrs.type" :size="attrs.size">开关</el-button>
<el-button v-bind="attrs">开关</el-button>
<el-button :="attrs">开关</el-button><script>
    import {useAttrs}  from "vue";
    const attrs = useAttrs();
</script>

attrsprops都可以接收父组件传递过来的数据,如果使用props接收数据,那么attrs和props都可以接收父组件传递过来的数据,如果使用props接收数据,那么attrs中就接收不到数据了

ref和$parents

子向父传递数据

父组件:

<script setup lang="ts">
import Child from '/@/views/test/child/index.vue'const money = ref(1000)
const child = ref()
const withdraw = () => {
  money.value += 100
  child.value.money -= 100
  child.value.withdraw();
}
</script><template>
<div>
  <h1>父组件余额:{{money}}</h1>
  <Child ref="child"></Child>
  <br>
  <br>
  <button @click="withdraw">向子组件借100</button>
</div>
</template>

子组件:

<script setup lang="ts" >
const money = ref(500)
const withdraw = () => {
  console.log("子组件向父组件借了100元")
}
defineExpose({money,withdraw})
</script><template>
  <div>
    <h1>子组件余额: {{ money }}</h1>
  </div>
</template>

provide和inject

provide可以为后代组件传递数据

组件:

<script setup lang="ts">
    import {provide} from 'vue'
    provide('money', money)
</script>

在app组件上提供的数据在该应用内的所有组件中都可以注入。

const app = createApp({})
app.provide( 'message',  'hello!')

inject获取数据:

<script setup lang="ts">
import {inject} from 'vue'
const money = inject('money')
</script>