7

上节回顾

上一节学习了父组件与子组件之间的简单通讯,回想一下大致如下:

  • 父传子 -> props
  • 子传父 -> $emit

但是也存在一些遗留问题,比如:我想在父组件中点击行事件修改弹出框的显示隐藏
其实上一节已经实现了效果,只是同时也得到了一大串的大红字~满山红真的让人很脸红的说啊...

本节目标

今天不上班,有一整天的自由时间,时间真的是一个很珍贵的东西呀,所以但凡是与时间有关的产物都会很有价值!

回到正题吧,今天可以慢慢的想一下如何来完成上一次没有完成的功能。

子组件修改父组件

Step 1. 直接修改props

SeaConch:先说好啊,这样做不对

旁白:不对你为什么还要写呢!?

SeaConch:因为我就是这样过来的啊...

既然父组件可以通过子组件定义的props属性传递对象,那为什么不直接修改它来实现修改父组件呢?

SeaConch:好像很有道理的样子!来试试~

不皮啦,好好记录!

父组件代码稍多,最后在贴完整的吧。

student-list ()组件关键代码:

html:

<student-list-info
  ...
  :visible="this.display"
>
</student-list-info>

javascript:

  data () {
    return {
      ...
      display: false
    }
  },

student-list-info ()组件完整代码:

<template>
  <div>
    <el-button icon="el-icon-more" @click="changeDisplay(true)" circle></el-button>
    <el-dialog title="查询" :visible.sync="this.visible">
      <el-form :model="student">
        <el-form-item label="姓名">
          <el-input v-model="student.name"></el-input>
        </el-form-item>
        <el-form-item label="性别">
          <el-input v-model="student.sex"></el-input>
        </el-form-item>
        <el-form-item label="年龄">
          <el-input v-model.number="student.age" type="number"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="changeDisplay(false)">取 消</el-button>
        <el-button type="primary" @click="doConfirm(student)">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'student-list-info',

  props: [
    'student',
    'visible'/* 新增 */
  ],

  methods: {
    // 确认按钮
    doConfirm (student) {
      this.$emit('confirm', student)
      this.changeDisplay(false)
    },

    // 修改显示状态
    changeDisplay (value) {
      this.visible = value
    }
  }
}
</script>

<style scoped>

</style>

npm run dev

诶~居然可以用~

控制台:我笑了

打开控制台才发现,原来一切都是假的!看到那广阔的红色疆土了吗?那是朕为你打下的江山!

其实错误是在说vue不推荐这样修改prop的值,并且我们应该避免这样做,以免在父组件发生改变时获得一个惊喜

好吧好吧,你说的有理,并且成功的说服了我,我改。

Step 2. 通过$emit间接修改

既然不能再子组件中修改,那就转移到父组件中修改吧。

关键字当然是$emit啦。

1.修改子组件

子组件只修改一个地方就可以啦

// 修改显示状态
changeDisplay (value) {
  // this.visible = value
  this.$emit('switch', value)
}

2.修改父组件

父组件需要给子组件@一个switch事件供其触发

html:

<student-list-info
  ...
  :visible="this.display"
  @switch="onSwitch"
>
</student-list-info>

javascript:

// 切换显示状态
onSwitch (value) {
  this.display = value
}

好啦,run

再次查看效果,这次没有错误了

不过这样看来的话,关于组件之间的值传递有些麻烦...

经查阅,vuex好像可以很好的解决这个问题,但渐进式的vue允许我们暂时不用他,你会知道什么时候该使用vuex的,逼格满满~

不过似乎Step 2.也是可以优化的,再来个Step 3.

Step 3. 使用.sync触发式更新prop

.sync实际是一种简单化的方法,我们来应用一下吧。

1.父组件不再需要Step 2.中新增的switch事件了:

<student-list-info
  style="float: left"
  @confirm="onConfirm"
  :student="this.student"
  :visible.sync="display"
>
</student-list-info>

注意::visible.sync="display"这里display没有带this.并且也不可以带this.带上会报错,错误看不太明白,不过既然带上this.会出错,那可能和更新事件的作用域有关系吧。

2.子组件中只需要修改一下changeDisplay函数

// 修改显示状态
changeDisplay (value) {
  // this.visible = value
  // this.$emit('switch', value)
  this.$emit('update:visible', value)
}

run 一下

结果是成功的。

点击弹出框的X好像报错,我去看一下。

改好了,把他原本的关闭事件屏蔽掉啦。

父组件完整代码:

<template>
  <div>
    <el-row>
    <student-list-info
      style="float: left"
      @confirm="onConfirm"
      :student="this.student"
      :visible.sync="display"
    >
    </student-list-info>
    </el-row>
    <hr>
    <h3>学员列表</h3>
  <el-table
    :data="tableData"
    @row-click="onRowClick"
    border
    stripe
    style="width: 100%">
    <el-table-column
      prop="name"
      label="姓名"
      width="180">
    </el-table-column>
    <el-table-column
      prop="sex"
      label="性别"
      width="180">
    </el-table-column>
    <el-table-column
      prop="age"
      label="年龄">
    </el-table-column>
  </el-table>
  </div>
</template>

<script>
import studentListInfo from './student-list-info'

export default {
  name: 'student-list',

  // 组件
  components: {
    studentListInfo
  },

  data () {
    return {
      tableData: [{
        name: '张楚岚',
        sex: '男',
        age: '23'
      },
      {
        name: '冯宝宝',
        sex: '女',
        age: '99'
      },
      {
        name: '赵方旭',
        sex: '男',
        age: '59'
      },
      {
        name: '肖自在',
        sex: '男',
        age: '36'
      }
      ],
      student: {
        name: '',
        sex: '',
        age: 0
      },
      display: false /* 新增 */
    }
  },

  // 方法集
  methods: {
    // 确认事件
    onConfirm (item) {
      this.tableData.push(item)
    },

    // 点击行事件
    onRowClick (row) {
      this.display = true
      this.student = {
        name: row.name,
        sex: row.sex,
        age: row.age
      }
    }
  }
}
</script>

<style scoped>

</style>

子组件完整代码:

<template>
  <div>
    <el-button icon="el-icon-more" @click="changeDisplay(true)" circle></el-button>
    <el-dialog title="查询" :visible="visible" @close='onClosed'>
      <el-form :model="student">
        <el-form-item label="姓名">
          <el-input v-model="student.name"></el-input>
        </el-form-item>
        <el-form-item label="性别">
          <el-input v-model="student.sex"></el-input>
        </el-form-item>
        <el-form-item label="年龄">
          <el-input v-model.number="student.age" type="number"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="changeDisplay(false)">取 消</el-button>
        <el-button type="primary" @click="doConfirm(student)">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'student-list-info',

  props: [
    'student',
    'visible'/* 新增 */
  ],

  methods: {

    // 确认按钮
    doConfirm (student) {
      this.$emit('confirm', student)
      this.changeDisplay(false)
    },

    // 修改显示状态
    changeDisplay (value) {
      this.$emit('update:visible', value)
    },

    // 对话框关闭事件
    onClosed () {
      this.$emit('update:visible', false)
    }
  }
}
</script>

<style scoped>

</style>

效果图

现在可以点击行,弹出对话框查看啦~
图片描述

小节

本节主要是记录了我想要从子组件修改父组件的属性的一个过程,这里也首次出现了vuex,闲下来的时候去看一下怎么使用吧,下回见~


youbei
318 声望70 粉丝