個人 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,閒下來的時候去看一下怎麼使用吧,下回見~

相關文章
相關標籤/搜索