zoukankan      html  css  js  c++  java
  • 实现组件props双向绑定解决方案

    注意: 子组件不能直接修改prop过来的数据,会报错

    方案一:

    1. 用data对象中创建一个props属性的副本

    2. watch props属性 赋予data副本 来同步组件外对props的修改

    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>
    复制代码

    父组件代码如下:

    复制代码
    <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 这样的方法,有点累赘。

    这时候 想到了 v-model 

    因为

    <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)
    }
    }
    复制代码

    效果如下:

  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/amujoe/p/11769269.html
Copyright © 2011-2022 走看看