v-model 用在组件中

官方文档:

  使用自定义事件的表单输入组件

官方也说明了,v-model只不过是一个语法糖而已,真正的实现靠的还是

1.  v-bind :  绑定响应式数据
2.  触发 input 事件 并传递数据  (核心和重点)

大体就是:

   监听原生组件的事件, 当获取到原生组件的值后把值通过调用 $emit('input' ,data) 方法去触发 input事件 
 
demo:
  父组件代码:
<template>
  <div class="hello">
       <button @click="ifShow=!ifShow">点击显示</button>
       <show-alert v-model="ifShow"></show-alert>
  </div>
</template>

<script>
import showAlert from './showAlert.vue'
export default {
  name: 'HelloWorld',
  components:{
      showAlert,
  },
  data () {
    return {
            ifShow:false,
    }
  }
}
</script>

  子组件代码:

<template>
    <div id="showAlert" :value="value" v-if="ifValue">
        <div>showAlert 内容</div>
        <button class="close" @click="ifValue=false">关闭</button>
    </div>
</template>

<script>
    export default{
        props:{
            value:{
                type:Boolean,
                default:false,
            }
        },
        data:function(){
            return{
                ifValue:false,
            }
        },
        watch:{
            value(bool){
                this.ifValue=bool;
                console.log('bool='+ bool);
            },
            ifValue(val){
                /*使用了v-model的组件会自动监听 input 事件, 
                 * 并把这个input事件所携带的值 传递给v-model所绑定的属性,
                 * 这样组件内部的值就给到了父组件了
                 */
                this.$emit('input',val);//传值给父组件, 让父组件监听到这个变化
            }
        },
    }
</script>

<style scoped>
    .close{
        background:red;
        color:white;
    }
</style>

    实现效果:

  点击显示按钮以后:

  前提: this.$emit('input',data);

  点击子组件关闭按钮后:

  如果未加this.$emit('input',data);

  点击子组件关闭按钮后:

  如果未通过$emit把值传到父组件, 则父组件监听不到子组件的变化.

 

 

====================================================================

封装一个可复用的弹窗组件

<!-- 
    弹出窗口组件,
    调用方法:
    父组件import 当前vue文件, 在对应的components中注册即可使用,
    注意:
    需要在父组件给一个boolean的属性 通过v-model的形式关联即可
    其他属性看下方注释,

    params(父组件调用 标签属性):
    title-info      弹出框显示文字
    left-button     左边按钮文字
    right-button    右边按钮文字
    left-click      左边按钮点击回调函数
    right-click     右边按钮点击回调函数

    中间部分可以从父元素自定义设置通过slot放入
    例子:
    <show-model>
        <p slot="reference">111</p>
    </show-model>

    例子:
    <show-model 
        v-model="flag" 
        title-info="优惠码输入错误,请重试"
        left-button="取消"
        right-button="确定"
        @left-click="left_button"
        @right-click="right_button"></show-model>

    ****
    watch中增加.
    当弹出窗弹出时,阻止后面页面可以滚动的问题
 -->
<template>
    <div class="model-wrapper" :value="value" v-if="ifValue">
        <div class="mask" @click="close_click"></div>
        <div class="model-content">
            <p v-if="titleInfo">{{titleInfo}}</p>
            <div class="button-group" v-if="leftButton || rightButton">
                <div v-if="leftButton" @click="left_click">{{leftButton}}</div>
                <div v-if="rightButton" @click="right_click">{{rightButton}}</div>
            </div>
        </div>
    </div>
</template>

<script>
    export default{
        props:{
            value:{
                type:Boolean,
                default:false
            },
            titleInfo:{
                type:String,
                default:''
            },
            leftButton:{
                type:String
            },
            rightButton:{
                type:String
            }
        },
        data:function(){
            return {
                ifValue:false,
            }
        },
        methods:{
            close_click:function(){
                this.$emit('close-click');
            },
            left_click:function(){
                this.$emit('left-click');
            },
            right_click:function(){
                this.$emit('right-click');
            }
        },
        watch:{
            value(bool){
                this.ifValue=bool;
            },
            ifValue(val){
                this.$emit('input',val);
            }
        }
    }
</script>

<style scoped>
    .model-wrapper{
        width:100%;
        height:100%;
        position:fixed;
        top:0;
        left:0;
        z-index:999;
    }
    .mask{
        width:100%;
        height:100%;
        position:absolute;
        left:0;
        top:0;
        z-index:1;
        background-color:rgba(0,0,0,0.5);
    }
    .model-content{
        width:80%;
        background:white;
        position:absolute;
        top:50%;
        left:50%;
        transform:translate(-50%,-50%);
        z-index:10;
    }
    .button-group{
        margin-top:40px;
        display:flex;
        padding:0 10px 10px;
    }
    .button-group div{
        flex:1;
        height:40px;
        line-height:40px;
        box-sizing:border-box;
        cursor:pointer;
    }
    .button-group div:first-child{
        background:#000;
        color:#fff;
    }
    .button-group div:last-child{
        border:1px solid gray;
    }
</style>

在首页调用

    <button @click="showModel">点击显示弹窗</button>
    <show-model v-model="ifShowModel" titleInfo="嘿嘿嘿" leftButton="确定" rightButton="取消" @close-click="close_click" @left-click="left_click" @right-click="right_click"     ></show-model>
    showModel:function(){
          this.ifShowModel=true;
          
      },
      close_click:function(){
          this.ifShowModel=false;
      },
      left_click:function(){
          this.ifShowModel=false;
      },
      right_click:function(){
          this.ifShowModel=false;
      }

posted @ 2018-04-25 14:11  rachelch  阅读(9021)  评论(0编辑  收藏  举报