Vue實現組件props雙向綁定解決方案

注意: 子組件不能直接修改prop過來的數據,會報錯html

方案一:vue

  1. 用data對象中建立一個props屬性的副本app

  2. watch props屬性 賦予data副本 來同步組件外對props的修改ide

  3. watch data副本,emit一個函數 通知到組件外函數

HelloWorld組件代碼以下:(代碼裏面有相應的註釋)測試

<template>
  <div class="hello">
    <h1 v-show="visible">測試顯示隱藏</h1>
    <div @click="cancel">點我點我</div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
      value: {
        type: Boolean,
        default:false
      }
    },
  data () {
    return {
      visible: false
    }
  },
  watch:{
    value(val) {
      this.visible = val;
    },
// 只有這一步 才觸發父組件的方法 由父組件的
paretnVisibleChange 方法去改變父組件的數據
  visible(val) { this.$emit("paretnVisibleChange",val); } },
  // 子組件修改的只能是子組件 自己的data數據 methods:{ cancel(){
this.visible = !this.visible; } },
// 注意這段代碼 爲了同步父組件的數據 mounted() {
if (this.value) { this.visible = true; } } } </script> <style scoped> </style>

父組件代碼以下:ui

<template>
  <div id="app">
    <HelloWorld :value = 'visible' @paretnVisibleChange="visibleChange" />
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  components: {
    HelloWorld
  },
  data () {
    return {
      visible: true
    }
  },
  methods:{
// 父子組件就是靠的這個方法改變數據的 visibleChange(val){
this.visible = val; } } } </script>

方案一 的缺點就是 父組件必須有個 visibleChange 這樣的方法,有點累贅。this

 

這時候 想到了 v-model spa

由於code

<input v-model = 'someThing'>

是下面這段代碼的語法糖

<input :value = 'someThing'  @input = 'someThing = $event.target.value'>

也就是說 v-mode 自帶了 一個改變父組件的方法 相似方案一的   paretnVisibleChange

可是使用 v-model 的時候 須要注意兩點:

1. 子組件要接受  value  屬性

2. value改變時 要觸發input 事件

 

方案二:

HelloWorld 子組件的代碼以下;

<template>
  <div class="hello">
    <h1 v-show="visible">測試顯示隱藏</h1>
    <div @click="cancel">點我點我</div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
      value: {
        type: Boolean,
        default:true
      }
    },
  data () {
    return {
      visible: false
    }
  },
  watch:{
    value(val) {
      this.visible = val;
    },
// 子組件 改變的就是這段代碼 visible(val) {
this.$emit("input",val); } }, methods:{ cancel(){ this.visible = !this.visible; } }, mounted() { if (this.value) { this.visible = true; } } } </script>

父組件代碼以下:(父組件省去了 paretnVisibleChange 方法)

<template>
  <div id="app">
    <HelloWorld v-mode = 'visible'/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  components: {
    HelloWorld
  },
  data () {
    return {
      visible: true
    }
  }
}
</script>

 

方案三:

vue 2.3.0以後新增了 .sync 屬性 使用方法跟 v-model  相似 具體 請參考 : https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-修飾符

下面我寫了一個簡單的sync 的使用實例:

父組件的代碼以下:

     <li
        is="DragCompent"
        v-for="(item, index) in layoutItem"
        :item="item"
        v-model="cloneLeftItemText"
        :leftDragItemIsDraged.sync = 'leftDragItemIsDraged'
        :key="index"></li>

子組件的代碼以下:

props: {
    leftDragItemIsDraged: {
      type: Boolean,
      default: false
    }
  },
watch:{
    leftDragItemIsDraged(val) {
    this.thisLeftDragItemIsDraged = val;
},
thisLeftDragItemIsDraged(val){
    this.$emit('update:leftDragItemIsDraged', val)
}
}

效果以下:

相關文章
相關標籤/搜索