修改props

1.传统方式

Vue父传子可以使用props,子组件接收到后就可以使用了。但是如果子组件中需要对props进行修改,是不能在子组件中直接进行修改的,需要使用 $emit() 触发父组件的方法并传值过去,在父组件中接收传过来的数据然后进行修改。

父组件:

xml
复制代码
<template> <div class="app"> <!-- 方式1: 监控子组件是否触发changeTitle方法,触发则执行handleTitle事件 从而实现子组件点击按钮修改父组件数据 --> <info :title="title" @changeTitle="handleTitle"></info> </div> </template> <script> import Info from './components/Info.vue' export default { name: 'App', data() { return { title: '初始标题', } }, methods: { handleTitle(title) { this.title = title }, }, components: { Info, }, } </script>

子组件:

xml
复制代码
<template> <div class="info"> <div class="title">{{ title }}</div> <div class="content"></div> <div class="buttons"> <button @click="changeTitle">修改标题</button> </div> </div> </template> <script> export default { name: 'Info', props: { title: { type: String, }, }, methods: { // 触发自定义事件changeTitle并传值 changeTitle(){ this.$emit('changeTitle', '新的标题') }, }, } </script>

效果:

Images_1629706196610.GIF

2.代码简化

可以看到,父组件中是创建了 handleTitle 方法来进行修改的。而这是可以简化的。

父组件:

将父组件中的第8行代码(子组件标签)简单修改一下,然后删除父组件 methods 中的 changeTitle() 方法。

没错,这样写就不需要在父组件的 methods 中另写一个方法用于修改了,父组件直接一行代码搞定。

xml
复制代码
<!-- 方式2: vue内置了 @update:变量名="变量名=$event" 的方法,可以实现与方式1同样的功能 该方法并不需要在父组件的methods中定义修改方法 $event接收通过$emit传过来的参数,并通过赋值语句实现父组件title的修改 --> <info :title="title" @update:title="title = $event"></info>

子组件:

子组件中 $emit() 的触发方法名修改为 update:title

javascript
复制代码
changeTitle() { // 这里的触发方法必须是 update:变量名 的方式,这是固定写法 this.$emit('update:title', '新的标题') },

效果和之前一样。

3.使用.sync修饰符

你以为这就简化完成了?不不不,它还可以更简化。

子组件需要修改父组件 props 时,使用 .sync 修饰符可以不必单独在父组件中写修改方法。只需要在子组件中 $emit 触发方法 update:变量名 并传值,即可完成修改。

2. 的基础上,使用 .sync 修饰符进行改写,代码更短

父组件:

xml
复制代码
<!-- 方式3: 此方式是方式2的简写形式 使用 .sync 修饰符即可实现 @update:变量名="变量名=$event" 一样效果 --> <info :title.sync="title"></info>

子组件:

2.2 一样,保存不变。

最后效果与前两个方式的效果是一样的,均能成功修改。

4.若props是对象呢

若传的 props 是一个对象,里面有多个值。

4.1参考方式1

那么按照 1. 的做法,直接将对象 doc 传过去,子组件接收,使用 doc.属性名 直接使用。

这当然没问题。但是这样,你就需要在父组件中为每一个属性写一个修改方法,很显然,代码量有点大。

4.2参考方式2

根据 2. 的做法,将需要用到的 doc 中的属性分别传过去,子组件分别接收。

父组件:

xml
复制代码
<template> <div class="app"> <!-- 方式4: 与方式2一样,但是若此时传的是一个对象,若用方式2的写法,代码将会很长... 毕竟每一个需要修改的变量都需要这样写一遍,变量越多,代码也就越长。 --> <info :title="doc.title" :content="doc.content" @update:title="doc.title = $event" @update:content="doc.content = $event" ></info> </div> </template> <script> import Info from './components/Info.vue' export default { name: 'App', data() { return { doc: { title: '初始doc标题', content: '初始doc内容', }, } }, components: { Info, }, } </script>

子组件:

xml
复制代码
<template> <div class="info"> <div class="title">{{ title }}</div> <div class="content">{{ content }}</div> <div class="buttons"> <button @click="changeTitle">修改标题</button> <button @click="changeContent">修改内容</button> </div> </div> </template> <script> export default { name: 'Info', // 直接接收doc对象不可行 // 那就分别接收doc对象中每一个需要用到的属性 props: { title: { type: String, }, content: { type: String, }, }, methods: { // 子组件触发默认方法 update:变量名 并传值 changeTitle(){ this.$emit('update:title', '新的标题') }, changeContent() { this.$emit('update:content', '新的内容') }, }, } </script>

效果:

Images_1629709963463.GIF

很好,效果满足预期。但是,如果要传的数据很多怎么办?总不能每一项都写一遍吧。父组件就传了两个数据,代码就长这样了:

bash
复制代码
<info :title="doc.title" :content="doc.content" @update:title="doc.title = $event" @update:content="doc.content = $event" ></info>

多了还得了?

4.3参考方式3

那试试 3. 的方法,也是传 doc 对象过去,然后使用 .sync 修饰符如何?

但事实上, <info :doc.sync="doc"></info> 的写法是错误的,子组件通过 props 接收不到这个 doc 对象,会报错哒。

难道无解了?并没有,思路对了,写法错了...

绑定对象内多个属性,应使用如下语法: v-bind.sync = object

父组件:

xml
复制代码
<info v-bind.sync="doc"></info>

子组件:

4.2 一样,保持不变。

就这样,又是一行简短的代码,效果与 4.2 并无不同。

注意:

虽然父组件这里看着传的是 doc 对象,但是在子组件中可看到props接收的是 doc 对象中的指定属性,而不是直接接收 doc 对象本身。

因为该方式可以看做是将 doc 对象解构(es6语法)然后分别将解构得到的每一项属性传给了子组件。

所以子组件props接收到的不是一个 doc 对象,而是一个个通过 doc 解构后得到的属性。

分类: Vue 标签: 暂无标签

评论

全部评论 1

  1. dsapr
    dsapr
    FireFox Windows 10
    最近在学前端吗

目录