精华内容
下载资源
问答
  • 通过父组件on监听子组件emit事件实现修改prop2. 通过父组件sync修饰符 + 子组件emit事件实现修改prop取巧方式3.通过赋值到data实现修改prop4.通过计算属性监听实现修改prop 前言 实际工作项目开发中,很经常会有...

    前言

    实际工作项目开发中,很经常会有父组件先传递值给子组件,再由子组件渲染展示的场景,下面我总结一下目前工作中遇到和用过的一些方式,也算是给大家一个实现方式和思路参考,如有理解不对or有其他方法欢迎在评论区留言指导~

    常用方式

    推荐,遵循prop单向传递的规则,基本数据类型和引用数据类型均可。

    1. 通过父组件on监听子组件emit事件实现修改prop

    原理:

    • 给子组件中的input标签绑定value属性赋值prop中的值,因为是用value而不是v-model,所以修改input值的时候并不会影响到prop。
    • 然后给input绑定input事件,每次输入内容都会触发input事件,在事件里通过this.$emit(‘父要监听的事件名’, 修改后的值)去将值向上传递。
    • 父组件中通过on监听子组件刚刚触发的emit事件,将事件传递过来的值更新到父组件的data中。
    • 父组件data中的值更新后,因为有通过prop传递给子组件,所以子组件也会同步更新prop值并渲染视图层。

    emit

    父组件代码如下:

    <template>
      <div style="background-color: skyblue;">
        <h3>通过父组件on监听子组件emit事件实现修改prop</h3>
        <div>父obj:{{ obj }}</div>
        <div>父msg:{{ msg }}</div>
        <!-- 父组件调用子组件时通过on监听子组件触发的emit事件,以接收值并更新用 -->
        <emitChild
          :obj="obj"
          :msg="msg"
          @update-obj="updateObj"
          @update-msg="updateMsg"
        />
      </div>
    </template>
    
    <script>
    import emitChild from './components/emitChild'
    
    export default {
      name: 'emitUpdate',
      components: {
        emitChild
      },
      data () {
        return {
          obj: {
            name: 'zhangsan',
            age: 18
          },
          msg: 'hello'
        }
      },
      methods: {
        // 监听子组件触发的事件并更新data中的obj
        updateObj (key, newVal) {
          this.obj[key] = newVal
        },
        // 监听子组件触发的事件并更新data中的msg
        updateMsg (newVal) {
          this.msg = newVal
        }
      }
    }
    </script>
    

    子组件代码如下:

    <template>
      <div style="background-color: pink;">
        <div>
          <span>修改name:</span>
          <!-- 这里绑定值用value,因为input在这主要用作展示prop数据,实际修改不在子组件,子组件只是作为修改触发源 -->
          <!-- 绑定input事件,作为触发源的入口 -->
          <input type="text" :value="obj.name" @input="updateObj($event, 'name')">
        </div>
        <div>
          <span>修改age:</span>
          <input type="text" :value="obj.age" @input="updateObj($event, 'age')">
        </div>
        <div>
          <span>修改msg:</span>
          <input type="text" :value="msg" @input="updateMsg($event.target.value)">
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'emitUpdateChild',
      props: {
        obj: {
          type: Object,
          default: () => {}
        },
        msg: {
          type: String,
          default: ''
        }
      },
      methods: {
        // 通知父组件更新obj
        updateObj ($event, key) {
          // 接收输入的值,和obj中对应需要更新值的属性,然后回传给父组件
          // 父组件就可以知道子组件需要更新obj中哪个属性的值
          this.$emit('update-obj', key, $event.target.value)
        },
        // 通知父组件更新msg
        updateMsg (newVal) {
          this.$emit('update-msg', newVal)
        }
      }
    }
    </script>
    

    2. 通过父组件sync修饰符 + 子组件emit事件实现修改prop

    原理:

    • 给子组件中的input标签绑定value属性赋值prop中的值,因为是用value而不是v-model,所以修改input值的时候并不会影响到prop。
    • 然后给input绑定input事件,每次输入内容都会触发input事件,在事件里通过this.$emit(‘父要监听的事件名’, 修改后的值)去将值向上传递。
    • 父组件调用子组件传递prop时,在prop后加上.sync即可将事件传递过来的值更新到父组件的data中,因为sync其实就相当于执行了@监听子触发的事件名 = "父data中的属性名 = emit传递的值(即$event)"这一段代码。
    • 父组件data中的值更新后,因为有通过prop传递给子组件,所以子组件也会同步更新prop值并渲染视图层。

    sync

    父组件代码如下:

    <template>
      <div style="background-color: skyblue;">
        <h3>通过父组件sync修饰符 + 子组件emit事件实现修改prop</h3>
        <div>父obj:{{ obj }}</div>
        <div>父msg:{{ msg }}</div>
        <!-- 父组件调用子组件传递prop时,在prop后加上.sync即可 -->
        <syncChild :obj.sync="obj" :msg.sync="msg" />
        <!--
          sync其实就相当于执行了
            @监听子触发的事件名 = "父data中的属性名 = emit传递的值(即$event)"
          这一段代码
        -->
        <!-- 效果相当于下面的代码,所以父组件methods中不需要再定义修改data数据的方法 -->
        <!--
          <syncChild
            :obj="obj"
            :msg="msg"
            @update-obj="obj = $event"
            @update-msg="msg = $event"
          />
        -->
      </div>
    </template>
    
    <script>
    import syncChild from './components/syncChild'
    
    export default {
      name: 'syncUpdate',
      components: {
        syncChild
      },
      data () {
        return {
          obj: {
            name: 'zhangsan',
            age: 18
          },
          msg: 'hello'
        }
      }
    }
    </script>
    

    子组件代码如下:

    <template>
      <div style="background-color: pink;">
        <div>
          <span>修改name:</span>
          <!-- 这里绑定值用value,因为input在这主要用作展示prop数据,实际修改不在子组件,子组件只是作为修改触发源 -->
          <!-- 绑定input事件,作为触发源的入口 -->
          <input type="text" :value="childObj.name" @input="updateObj($event, 'name')">
        </div>
        <div>
          <span>修改age:</span>
          <input type="text" :value="childObj.age" @input="updateObj($event, 'age')">
        </div>
        <div>
          <span>修改msg:</span>
          <input type="text" :value="msg" @input="updateMsg($event.target.value)">
        </div>
      </div>
    </template>
    
    <script>
    // 这里引入lodash工具库的cloneDeep深拷贝方法
    // 官方文档地址 https://www.lodashjs.com/
    import { cloneDeep } from 'lodash'
    
    export default {
      name: 'emitUpdateChild',
      props: {
        obj: {
          type: Object,
          default: () => {}
        },
        msg: {
          type: String,
          default: ''
        }
      },
      data () {
        return {
          // 这里通过深拷贝将prop的obj复制了一份,主要为了:
          // 1.区分2个对象(引用类型)用的不是同一个内存地址
          // 2.保留对象中所有的值,方便子组件渲染/修改/回传用
          childObj: cloneDeep(this.obj)
        }
      },
      methods: {
        // 通知父组件更新obj
        updateObj ($event, key) {
          // 接收输入的值,和childObj中对应需要更新值的属性
          // 然后更新childOBj后,回传给父组件
          // 父组件直接把拿到的childObj更新到data的obj即可
          this.childObj[key] = $event.target.value
          this.$emit('update:obj', this.childObj)
        },
        // 通知父组件更新msg
        updateMsg (newVal) {
          this.$emit('update:msg', newVal)
        }
      }
    }
    </script>
    

    取巧方式

    主要针对引用数据类型,绕过了vue对于prop的检测机制,具体看项目规范是否允许这样写。

    3.通过data实现修改prop

    前提:只有引用数据类型可以实现

    原理:

    • 将父组件传入的prop直接赋值给子组件的data,此时prop和data两边的变量指向的都是同一个内存地址,所以修改data等于修改prop。
    • vue2开始不允许直接修改prop,但此时我们表面修改的是data不是prop,因此vue不会抛出错误,相当于绕过了vue对于不允许修改prop的检测机制。

    data

    父组件代码如下:

    <template>
      <div style="background-color: skyblue;">
        <h3>通过赋值到data实现修改prop</h3>
        <div>父obj:{{ obj }}</div>
        <div>父msg:{{ msg }}</div>
        <dataChild :obj="obj" :msg.sync="msg" />
      </div>
    </template>
    
    <script>
    import dataChild from './components/dataChild'
    
    export default {
      name: 'dataUpdate',
      components: {
        dataChild
      },
      data () {
        return {
          obj: {
            name: 'zhangsan',
            age: 18
          },
          msg: 'hello'
        }
      }
    }
    </script>
    

    子组件代码如下:

    <template>
      <div style="background-color: pink;">
        <div>
          <span>修改name:</span>
          <!-- 这里因为我们直接把prop赋值给data了,所以可以直接用v-model双向绑定修改数据 -->
          <input type="text" v-model="dataObj.name">
        </div>
        <div>
          <span>修改age:</span>
          <input type="text" v-model="dataObj.age">
        </div>
        <div>
          <span>修改msg:</span>
          <!-- 这里提供另一种修改基本数据类型的思路,可以通过watch侦听器实现 -->
          <input type="text" v-model="dataMsg">
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'dataChild',
      props: {
        obj: {
          type: Object,
          default: () => {}
        },
        msg: {
          type: String,
          default: ''
        }
      },
      data () {
        return {
          // 引用数据类型直接赋值时是浅拷贝,只会复制内存地址,修改其中一个会影响另一个
          dataObj: this.obj,
          // 基本数据类型直接赋值时是复制值,修改其中一个不会影响另一个
          dataMsg: this.msg
        }
      },
      watch: {
        // 这里侦听data中复制过来的dataMsg,当修改时执行emit通知父组件进行更新
        dataMsg (newVal) {
          this.$emit('update:msg', newVal)
        }
      }
    }
    </script>
    

    4.通过计算属性computed实现修改prop

    前提:只有引用数据类型可以实现

    原理:

    • 在子组件中直接通过计算属性computed监听父组件传入的prop,此时计算属性computed和prop两边的变量指向的都是同一个内存地址,所以修改计算属性computed等于修改prop。
    • vue2开始不允许直接修改prop,但此时我们表面修改的是计算属性computed不是prop,因此vue不会抛出错误,相当于绕过了vue对于不允许修改prop的检测机制。

    computed

    父组件代码如下:

    <template>
      <div style="background-color: skyblue;">
        <h3>通过计算属性监听实现修改prop</h3>
        <div>父obj:{{ obj }}</div>
        <div>父msg:{{ msg }}</div>
        <computedChild :obj="obj" :msg.sync="msg" />
      </div>
    </template>
    
    <script>
    import computedChild from './components/computedChild'
    
    export default {
      name: 'computedUpdate',
      components: {
        computedChild
      },
      data () {
        return {
          obj: {
            name: 'zhangsan',
            age: 18
          },
          msg: 'hello'
        }
      }
    }
    </script>
    

    子组件代码如下:

    <template>
      <div style="background-color: pink;">
        <div>
          <span>修改name:</span>
          <!-- 这里因为我们直接通过计算属性computed监听prop了,所以可以直接用v-model双向绑定修改数据 -->
          <input type="text" v-model="computedObj.name">
        </div>
        <div>
          <span>修改age:</span>
          <input type="text" v-model="computedObj.age">
        </div>
        <div>
          <span>修改msg:</span>
          <!-- 这里提供另一种修改基本数据类型的思路,可以通过计算属性computed的setter实现 -->
          <input type="text" v-model="computedMsg">
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'computedChild',
      props: {
        obj: {
          type: Object,
          default: () => {}
        },
        msg: {
          type: String,
          default: ''
        }
      },
      computed: {
        computedObj () {
          // 这里直接return引用数据类型obj,此时computedObj相当于obj
          // 所以是浅拷贝,只会复制内存地址,修改其中一个会影响另一个
          return this.obj
        },
        computedMsg: {
          get () {
            // 这里prop每次更新时,都会触发计算属性的getter方法获取最新的值
            // 直接return基本数据类型时是复制值,修改其中一个不会影响另一个
            return this.msg
          },
          set (newVal) {
            // 这里利用计算属性的setter方法,监听到值修改时触发emit通知父组件更新值
            this.$emit('update:msg', newVal)
          }
        }
      }
    }
    </script>
    
    展开全文
  • 需求:父组件通过props传递给子组件 caseList 数组,这里需要遍历该数组来展示每个 case 元素的一些属性,其中就包括创建时间 create_time。但父组件传过来的 create_time 是一个时间戳,我们希望时间以年-月-日的...

    需求:父组件通过props传递给子组件 caseList 数组,这里需要遍历该数组来展示每个 case 元素的一些属性,其中就包括创建时间 create_time。但父组件传过来的 create_time 是一个时间戳,我们希望时间以年-月-日的形式来呈现。所以子组件需要想办法修改 props 值的一个属性。

    一、使用计算属性

    在 computed 中获取到 props,并通过 map 遍历数组来修改属性。

    // 子组件
    <template>
    	<ul>
            <li v-for="(item, index) in newCaseList" :key="index">
                <div class="img">
                    <img :src="item.cover" alt="" />
            	</div>
                <div class="text">{{ item.title }}</div>
                <div class="time">{{ item.create_time }}</div>
            </li>
    	</ul>
    </template>
    
    <script>
        export default {
            props: {
                caseList: {
                    type: Array,
                    default: [],
                },
            },
            computed: {
                newCaseList() {
                    return this.caseList.map((item) => {
                        item.create_time = this.format(item.create_time); //通过自定义format函数转换时间戳格式
                        return item;
                    });
                },
            },
        };
    </script>
    

    这就是我在项目中所采用的做法。而除了计算属性,还可以通过监听属性或 sync 修饰符来修改 props。以下只简单说明用法。

    二、使用监听属性

    在子组件data中拷贝一份,注意引用类型需要深拷贝,根据需求可以watch监听。

    data() {
        return {
            newCaseList: this.list.slice()
        }
    },
    watch: {
        list(caseList) {
            this.newCaseList = caseList
        }
    }
    

    三、使用 sync 修饰符

    父组件传入 props时加入.sync 修饰符,子组件通过 this.$emit('update:xxx', params);修改。

    // 父组件
    <todo-list :list.sync="list" />
     
    // 子组件
    methodName(index) {
        this.$emit('update:list', this.newList)
    }
    
    展开全文
  • 前端页面有时会出现在子组件修改父组件传过来的prop的值,如果直接在子组件修改该prop的值时控制台会报错。该如何在子组件修改prop的值呢? 一、在父组件中绑定的值加上.sync //使用子组件 <common :...

    前端页面有时会出现在子组件中修改从父组件传过来的prop的值,如果直接在子组件中修改该prop的值时控制台会报错。该如何在子组件中修改prop的值呢?

    一、在父组件中绑定的值加上.sync

    //使用子组件
    <common :foo.sync="foo"></common>
    
    //data
    data(){
        return {
            foo: true
        }
    }

    二、在子组件中修改数据时用this.$emit('update:foo',newValue)

    //标签
    <button @click="changeValue">修改prop的值</button>
    <div v-if="foo">哈哈哈哈哈</div>
    
    //props
    props:{
        foo:Boolean,
    }
    
    //methods函数
    changeValue() {
        this.$emit("update:foo",false)
    }

     

    展开全文
  • 报错信息: Avoid mutating a prop directly since the value will ...原因:报错原因:props传值是单向数据流,只能由父组件传递给子组件子组件被动接受,一旦子组件自己试图修改props中的值,就会报上述错误,这样

    报错信息: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value.
    原因:报错原因:props传值是单向数据流,只能由父组件传递给子组件,子组件被动接受,一旦子组件自己试图修改props中的值,就会报上述错误,这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
    解决方法:在父组件通过this.$refs.[子组件名].[子组件修改数据的方法] 实现更改父组件的传入的数据

    展开全文
  • 一般通过子组件修改父组件传递过来的值,我们就会采用props和$emit进行单向数据绑定 父组件: <template> <div> <test :value="value" @change="change"></test> </div> </...
  • 首先父组件通过props传值给子组件的值是无法通过子组件自行修改了,只能使用类似于$emit这样的方法启用触发父组件方法修改,不然会报错 不过通过对象传输给子组件,子组件在已有父组件对象上添加属性是可以改变父组件...
  • 组件传值给子组件props组件将props接受到的值用做v-model双向数据绑定 因为props是只读的,不能修改 直接修改会报下面的错误 Avoid mutating a prop directly since the value will be overwritten whenever...
  • vue不推荐直接在子组件修改父组件传来的props的值,会报错 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or...
  • 本来不能去改里面的内容,如果是复杂数据类型,可以在里面修改
  • vue子组件修改父组件的值 最近在写uniapp项目,ui库是 uview,再将模态框(u-modal)封装成组件的时候,遇到这种脑残问题,首先看报错。 使用了vue 的.sync 修饰符,但是完全没啥卵用。 这就不用说子组件emit...
  • vue 子组件修改props方法

    千次阅读 2021-03-07 19:58:18
    vue是单向数据流,组件通过props传值给子组件,如果在子组件中修改会报错,一般是不在子组件中修改props的,但偶尔有需要在子组件有修改props,这里介绍三种可以修改子组件props的方法。 1.组件用sync修饰,子...
  • vue子组件修改父组件传递过来的值的问题 问题:Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改父组件的状态,来避免应用的数据流变得难以理解。子组件...
  • 一、关于vue中watch的认识我们要监听一个属性的的变化就使用watch一般是父组件传递给子组件的时候•1、常见的使用场景...watch:{value(val) {console.log(val);this.visible = val;}}...•2、如果要一开始就执行......
  • 1. 修改父组件普通数据 使用v-mode语法,代替了vue2.x的.sync修饰符 父组件用ref() 定义一个普通数据为响应式变量,例 var test = ref(‘parent’) 父组件用v-mode将数据绑定到子组件上 <ChildComponent v-...
  • 5、如果子组件修改来自父组件的值,不能直接修改,要通过事件进行修改首先子组件中点击事件绑定方法,方法调用$emit()事件,通过这个方法发送请求给父组件,同时这个方法有两个参数,第一个是方法名(此方法名在...
  • <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>...
  • Vue子组件调用父组件的方法 Vue子组件调用父组件的函数 Vue中子组件调用父组件的方法,这里有三种方法提供参考 第一种方法是直接在子组件中通过this.$parent.event来调用父组件的方法 父组件 <template> <...
  • // 子组件: <template> <div> {{ val }} </div> </template> <script> name:'Child' props:{ val:String } methods:{ change(el){ // el是改变后的值 this.$emits...
  • 1.子组件内不允许直接修改父组件传过来的参数。错误实例:子组件代码直接对data参数进行修改,则会提示错误。vue.runtime.esm.js?2b0e:619 [Vue warn]: Avoid mutating a prop directly since the value will be ...
  • vue中子组件是不允许直接修改父组件传过来的数据,因为如果父组件传过来的数据如果是数组或者是对象的数据的话,在子组件中直接修改传过来数据的话,会影响到其他组件的数据,所以要在子组件data数据里定义一个...
  • //父组件 <template> <div> <child></child> </div> </template> <script> import child from '~/components/dam/child'; export default { components: { child ...
  • Prop being mutated: "checkedKeys" 在子组件修改父组件传来的props的值,报错 解决: props: { checked: { type: Array, default: () => null } }, data(){ return { checkedKeys:this.checked } }
  • 通常是这两种原因:prop作为初始值传入后,子组件想把它当作局部数据来用;prop作为初始值传入,由子组件处理成其它数据输出。对这两种原因,正确的应对方式是:定义一个局部变量,并用 prop 的值初始化它:props: ...
  • vue子组件直接修改props的值

    千次阅读 2021-04-09 16:41:57
    父组件: <son :num.sync="num"></son> 子组件: <script> export default { props: { num: { type: Number, default: 1 } }, methods: { addNum() { this.$emit('update:num',10);//...
  • 不更新原因:从 props 的 info 传递给 data 的 list ,只有一次操作,就是在 mounted 中,往后即使 props 的 info 发生了变化,data 也接收不到...(推荐):computed 重新计算属性 赋值到子组件 watch 监听props 变化 ...
  • 最近做了一个项目,前面开发的时候质量不是很好,一个很简单的菜单栏竟然每页都搞了一个,这要是修改菜单栏的图标什么的,不累死了哈,想到了vue组件的功能,站长就打算把菜单栏搞成组件的形式,然后每个页面调用这...
  • vue3.0 子组件调用父组件中的方法

    千次阅读 2021-07-31 17:45:17
    vue2中,子组件调用父组件,直接使用this.$emit()即可。 但是在vue3中,很显然使用this.$emit() 已经开始报错了,为什么会报错呢? 原因是:在vue3中setup是在声明周期beforeCreate和created前执行,此时vue对象还...
  • 简单记录,因为在vue2.x版本本,子组件一般会通过watch 对应的prop属性key去重新赋值给子组件data中定义的参数(用来接收父组件传的参数) 因为Vue3的提供了setup,我们通常会在里面使用watch()去监听,和Vue2.x会...
  • Vue.js父组件通过props如何向子组件传递方法详解发布于 2020-6-30|复制链接在Vue 中,可以使用 props子组件传递数据,下面前言本文主要给大家介绍了关于vue父组件通过props子组件传递方法的相关内容,分享出来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 81,555
精华内容 32,622
关键字:

vue子组件修改父组件props

vue 订阅