个人 Vue.js 学习日记 (十二) - props与$emit与.sync

上节回顾

上一节学习了父组件与子组件之间的简单通信,回想一下大体以下:javascript

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

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

本节目标

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

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

子组件修改父组件

Step 1. 直接修改props

SeaConch:先说好啊,这样作不对vuex

旁白:不对你为何还要写呢!?npm

SeaConch:由于我就是这样过来的啊...函数

既然父组件能够经过子组件定义的props属性传递对象,那为何不直接修改它来实现修改父组件呢?学习

SeaConch:好像颇有道理的样子!来试试~优化

不皮啦,好好记录!this

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

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,闲下来的时候去看一下怎么使用吧,下回见~

相关文章
相关标签/搜索