Vue 组件封装,父组件传参给子组件,子组件调用父组件。

        在 Vue 开发中,组件化是提升代码复用性可维护性的重要手段。通过组件化,可以将常用的功能封装为独立的组件,并在需要的地方复用。本文将介绍如何在 Vue 中实现父组件与子组件之间的数据传递,以及子组件如何调用父组件的方法。

一、组件封装的基本思路

在 Vue 中,通常会将一些可复用的逻辑、UI 封装成单独的组件。比如一个表单,如果需要在多个地方使用,最好的做法是将其提取为一个子组件,而不是在多个地方重复编写相同的代码。

项目场景

        前端有一个页面,需要要 《新增》 与 《详情》 展示一个内容一样的表单窗口。为了代码复用,我们将表单窗口提取为一个子组件,并且嵌入到《新增》 与 《详情》的代码中复用。我们需要在父组件中控制这个表单的显示与隐藏,并在表单提交后关闭窗口并刷新父组件的数据。

二、父组件向子组件传递数据与子组件调用父组件方法

        在 Vue 中,父组件通过 props 向子组件传递数据。props 是一种单向数据流,从父组件流向子组件。子组件在执行保存表单后调用父组件的方法实现,关闭窗口与刷新父组件数据列表。我们来看以下实现代码:

1. 父组件

<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>Parent Component</h1>
    <button @click="openForm">Open Form</button>

    <!-- 新增窗口 -->
    <Drawer title="新增车辆"   :mask-closable=false
                :closable=true v-model="show_edit_win" width="900"
                style="position: relative">

                <!-- 使用 props 向子组件传递数据 -->
                <edit-form  @close-form="handleCloseForm" @refresh-data="refreshData" :brand-data="brandList" ></edit-form>

    </Drawer>

<Drawer title="车辆详情"    :mask-closable=false
                :closable=true v-model="show_detail_win" width="1200"
                style="position: relative">

            <Tabs value="sub_win_tab" style="height: 100%;">

                <TabPane label="车辆信息" name="1">
                    <edit-form :form-data="entity"  @refresh-data="refreshData" :brand-data="brandList" ></edit-form>
                </TabPane>


                <TabPane label="车辆使用记录" name="2">

                </TabPane>

                <TabPane label="车辆维修记录" name="3">

                </TabPane>
            </Tabs>


        </Drawer>



  </div>
</template>

<script>
import editForm from "./edit_form";

export default {
  components: {
    editForm 
  },
  data() {
    return {
      show_detail_win: false,  // 控制表单是否显示
      brandList:[] //车辆品牌
    };
  },
  methods: {
    openForm() {
      this.show_detail_win = true;
    },
  handleCloseForm() {
                 this.show_edit_win=false;
            },
            refreshData() {
                //业务处理,一般是重新调用拉列表数据
            },
  }
};
</script>

2. 子组件

<!-- edit_form.vue -->
<template>
    <div>
        <Form :label-width="90" :model="entity" ref="entity_edit" :rules="ruleValidate">

            <div><h4>车辆信息</h4></div>

            <Row :gutter="24">

                <Col span="8">
                    <FormItem label="车辆号码:" prop="code">
                        <Input v-model="entity.code" > </Input>
                    </FormItem>
                </Col>
                <Col span="8">
                    <FormItem label="车辆VIN:" prop="vinCode">
                        <Input v-model="entity.vinCode" > </Input>
                    </FormItem>
                </Col>
                <Col span="8">
                    <FormItem label="车辆品牌:">
                        <Select placeholder="车辆品牌" v-model="entity.brand"  clearable>
                            <Option v-for="item in brandList" :value="item.brand" :key="item.brand">{{item.brand}}</Option>
                        </Select>
                    </FormItem>
                </Col>

            </Row>

            <Row :gutter="24">
                <Col span="8">
                    <FormItem label="车辆系列:" prop="cardType">
                        <Input v-model="entity.series" > </Input>

                    </FormItem>
                </Col>

                <Col span="8">
                    <FormItem label="车辆型号:" prop="cardNo">
                        <Input v-model="entity.model" > </Input>
                    </FormItem>
                </Col>

                <Col span="8">
                    <FormItem label="车辆类型:" prop="cardType">
                        <Select v-model="entity.type" placeholder="请选择车辆类型"   clearable>
                            <Option v-for="item in typeList" :key="item.value" :value="item.value">{{item.label}}</Option>
                        </Select>
                    </FormItem>
                </Col>

            </Row>

            <Row :gutter="24">
                <Col span="24">
                    <FormItem label="备注" prop="remark">
                        <Input v-model="entity.remark" type="textarea" :autosize="{minRows: 5,maxRows: 8}"
                                style="width: 800px;"
                               placeholder="请输入备注信息..."> </Input>
                    </FormItem>
                </Col>
            </Row>
        </Form>
      

        <div style="text-align: center;padding-bottom: 10px;">
            <Button type="primary"  @click="doSave">保存</Button>
        </div>


    </div>
</template>

<script>
    export default {
        name: "edit_form",
        props: {
            formData: { //父组件在修改时传入的原对象数据,传入的不是引用而是副本。
                type: Object,
                required: false
            },
            brandData: {  //父组件传入的品牌数据
                type: Array,
                required: true
            }
        },
        data() {
            return {
                brandList:[...this.brandData],//品牌列表
                typeList:[
                    {value:1,label:'公交车'},
                    {value:2,label:'私家车'},
                ],
                updateUrl: '/backend/resources/vehicle/edit',
                saveUrl: '/backend/resources/vehicle/save',
                entity:{...this.formData},
                ruleValidate: {
                    code: [ {required: true, message: '不能为空', trigger: 'blur'}],
                    vinCode: [ {required: true, message: '不能为空', trigger: 'blur'}],
                    contacts: [ {required: true, message: '不能为空', trigger: 'blur'}],
                    remark: [
                        {required: false, message: '', trigger: 'blur'},
                        {type: 'string', max: 30, message: '最多可录入30个字符', trigger: 'blur'}
                    ]
                }
            }
        },
        methods:{
            //增加或修改车辆
            doSave () {
                let self = this;
                self.$refs.entity_edit.validate((valid) => {
                    if (valid) {
                        let req = self.saveUrl;
                        if (self.$util.isNotEmpty(self.entity.id)) {
                            req = self.updateUrl;
                        }
                        self.$axios.post(req, self.entity).then(res => {

                            if(res.code==200){
                                self.$Message.success('操作成功!');
                                self.$emit('refresh-data');  // 触发刷新数据的事件
                                self.$emit('close-form');  // 触发关闭表单的事件
                            }else{
                                self.$Message.error(res.msg);
                            }

                        }).catch(e =>{
                            self.show_edit_win = true;
                        });
                    }
                });
            },
        }
    }
</script>

<style scoped>

</style>

3. 代码关键点解释

   1 父组件向子组件传递数据:
  • 父组件通过 props 向子组件传递数据。在这个例子中,父组件将 parentFormData 传递给了子组件 FormComponent,子组件通过 props 接收这个数据。

  • 子组件不能直接修改传入的 props,因为 props 是不可变的。如果子组件需要修改这些数据,通常会将 props 的数据复制到本地状态(如 localFormData),然后操作本地数据。

   2 子组件调用父组件方法

        子组件不能直接调用父组件的方法。但我们可以通过事件通信的方式,让子组件触发事件,父组件监听事件并调用相应的方法。这种通信方式是 Vue 框架推荐的做法,符合单向数据流的设计思想

     具体步骤:
  1. 父组件定义方法:父组件中定义关闭表单和刷新数据的方法。
  2. 子组件触发事件:子组件通过 $emit 触发自定义事件。
  3. 父组件监听事件:父组件通过事件监听器捕获子组件触发的事件,并执行对应的方法。
  • 子组件通过 $emit 触发自定义事件。在表单提交后,子组件使用 this.$emit('close-form') 触发事件,通知父组件关闭窗口;同样使用 this.$emit('refresh-data') 触发事件,通知父组件刷新数据。

  • 父组件通过事件监听器监听事件。父组件通过 @close-form="handleCloseForm"@refresh-data="refreshData" 监听子组件触发的事件,并在事件发生时执行相应的方法。

4. 实现后的效果

  以上代码实现的效果图如下:

父组件新增】使用子组件后如下:

 父组件详情】使用子组件后如下:

三、总结

        在 Vue 的组件化开发中,父组件与子组件的通信是常见需求。通过 props,父组件可以向子组件传递数据;通过 $emit 事件,子组件可以通知父组件执行相应的操作。这样的单向数据流和事件通信机制,保证了组件之间的解耦和代码的可维护性。

### 回答1: 在 Vue 中,组件组件传参可以通过自定义事件的方式实现。具体步骤如下: 1. 在组件中定义一个方法,该方法用于触发自定义事件并传递参数。 2. 在组件中使用 `$emit` 方法触发自定义事件,该方法接收两个参数,第一个参数是自定义事件的名称,第二个参数是要传递的参数。 3. 在组件中通过 `v-on` 指令监听自定义事件,该指令可以缩写为 `@`。 4. 在组件的方法中,可以通过 `$event` 参数来获取组件传递过来的参数。 下面是一个示例代码: 组件: ``` <template> <button @click="sendData">传递数据</button> </template> <script> export default { methods: { sendData() { const data = 'hello world'; this.$emit('send-data', data); } } } </script> ``` 组件: ``` <template> <div> <child-component @send-data="handleData"></child-component> </div> </template> <script> export default { methods: { handleData(data) { console.log(data); // 输出:hello world } } } </script> ``` 在上面的代码中,组件中定义了一个 `sendData` 方法,该方法通过 `$emit` 方法触发了一个名为 `send-data` 的自定义事件,并传递了一个字符串参数。 在组件中,使用 `v-on` 指令监听了组件触发的 `send-data` 事件,并调用了 `handleData` 方法来处理传递过来的参数。在 `handleData` 方法中,可以通过 `$event` 参数来获取组件传递过来的参数。 ### 回答2: Vue 组件组件传参的方法有多种。 1. 使用 `$emit` 方法:组件通过 `$emit` 触发自定义事件,并传递参数给组件组件在模板中通过 `v-on` 接收传递的参数。具体步骤如下: - 在组件中定义一个方法,使用 `$emit` 触发自定义事件,并传递参数。例如:`this.$emit('customEvent', yourData)` - 在组件的模板中,使用 `v-on` 监听组件传递的自定义事件,并接收参数。例如:`<child-component v-on:customEvent="yourMethod"></child-component>` 2. 使用 `.sync` 修饰符: `.sync` 修饰符可以简化组件组件传递参数的过程。具体步骤如下: - 在组件中使用 `<child-component :yourProp.sync="yourData"></child-component>`,其中 `yourProp` 是组件的接收参数,`yourData` 是组件中数据的名称。 - 在组件中使用 `this.$emit('update:yourProp', newValue)` 更新组件的数据。 3. 使用 `.sync` 修饰符的替代方法: 在组件中使用 `:yourProp="yourData" @update:yourProp="yourData = $event"`,其中 `yourProp` 是组件的接收参数,`yourData` 是组件中数据的名称。 总结:Vue 组件组件传参的常见方法有使用 `$emit` 方法触发自定义事件,使用 `.sync` 修饰符以及使用 `.sync` 修饰符的替代方法。根据具体的使用场景,选择合适的方法进行传参。 ### 回答3: 在Vue中,组件组件传参有两种常用的方式:使用props和使用自定义事件。下面我将分别介绍这两种方式。 1. 使用props: 在组件中,可以通过在组件上定义props来接收组件传递的参数。在组件中,通过在标签上使用v-bind指令将需要传递的参数绑定到组件的数据上,然后在组件中,可以通过props选项来接收组件传递的参数。 例如,在组件中: ``` <template> <div> <button @click="sendData">传递参数</button> </div> </template> <script> export default { methods: { sendData() { this.$emit('child-event', 'hello') } } } </script> ``` 在组件中: ``` <template> <div> <child-component @child-event="receiveData"></child-component> </div> </template> <script> export default { methods: { receiveData(data) { console.log(data) // 输出 hello } } } </script> ``` 2. 使用自定义事件: 在组件中,可以通过在组件的方法中使用$emit方法触发自定义事件,并将需要传递的参数作为参数传递给自定义事件。在组件中,通过在组件标签上使用@监听自定义事件,并在组件的方法中接收传递的参数。 例如,在组件中: ``` <template> <div> <button @click="sendData">传递参数</button> </div> </template> <script> export default { methods: { sendData() { this.$emit('child-event', 'hello') } } } </script> ``` 在组件中: ``` <template> <div> <child-component @child-event="receiveData"></child-component> </div> </template> <script> export default { methods: { receiveData(data) { console.log(data) // 输出 hello } } } </script> ``` 以上是组件组件传参的两种常用方式,根据实际需要选择适合的方式即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qyhua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值