vue组件数据自动更新sync

2019-04-29  本文已影响0人  索哥来了

首先说下 父子组件传递值的问题:
父页面传给子组件使用 props
子组件传回给父页面使用 emit
在以前的时候,子组件的值传回来后,父页面需要写一个事件用来赋值,做不到自动更新。(具体怎么使用组件这里就不多说了)
本文就是为了解决这个麻烦的问题,效果就是,子组件封装好后,父组件只需要使用 不需要做其他处理。

根据上面的问题,下面写一个组件用来计数textarea输入的值的长度,有限制字数的功能

(下面是基于vue element框架,ps:element里面有这个功能,但是有些许不一样)
element使用如下:

<el-input
  type="textarea"
  placeholder="请输入内容"
  v-model="textarea"
  maxlength="30"
  show-word-limit
>
</el-input>

具体可查看element的文档https://element.eleme.cn/#/zh-CN/component/input

下面介绍下本人自己写的组件:(代码为了可以直接拿去使用,有些冗余,可以直接滑到最底下看注意点)

//子组件完整代码
<template>
<div class="mytextarea_wrap">
    <div @mouseenter="ishover = true" @mouseleave="ishover = false" :class="{focusPar:isfocus,hoverPar:ishover}">
    <el-input type="textarea"
        v-model="value" 
        :autosize="autosize"
        @input="changeFun"
        @focus="isfocus = true"
        @blur="isfocus = false"
        :placeholder="placeholder">
    </el-input>
    <span class="mytextarea_count" :class="{focus:isfocus,hover:ishover}">{{value.length}}/{{limit}}</span>

    </div>
    <span class="mytextarea_tips" v-show="value.length>limit">输入字符不能超过{{limit}}个字符</span>
</div>
</template>

<script>
export default {
    data(){
        return{
           value : this.val || '',
           isfocus : false,
           ishover : false,
        }
    },
    watch: {
        val(nv){
            this.value = nv;
        }
    },
    props: {
        autosize : {
            type : Object,//Array 和 Object 默认值必须使用函数return回来
            default : function () {
                return { minRows: 4, maxRows: 6 }
            }
        },
        placeholder : String,
        limit : {
            type : [String, Number],
            default : 500,
        },

        val : String,
    },
    methods:{
        changeFun(){
            this.$emit('update:val',this.value);
        }
    }
}
</script>

<style lang="scss">
@import '../sass/color';
.mytextarea_wrap{
    .el-textarea__inner{
        border-radius: 4px 4px 0 0;
        border-bottom: none;
        resize: none;
    }
    .mytextarea_count{
        display: block;
        width: 100%;
        box-sizing: border-box;
        font-size: 12px;
        padding: 0 15px;
        height: 24px;
        line-height: 24px;
        text-align: right;
        border-radius: 0 0 4px 4px;
        border: 1px solid #dcdfe6;
        border-top: 0;
        color: #999;
        transition: border-color .2s cubic-bezier(.645,.045,.355,1);
    }
    .mytextarea_count.focus{
        border-color: $pageColor_blue !important;
    }
    .mytextarea_count.hover{
        border-color: #C0C4CC;
    }
    .hoverPar{
        textarea{
            border-color: #C0C4CC;
        }
    }
    .focusPar{
        textarea{
            border-color: $pageColor_blue !important;
        }
    }
    .mytextarea_tips{
        display: block;
        height: 24px;
        line-height: 24px;
        color: $pageColor_red;
        font-size: 12px;
    }
}
</style>

父页面使用如下:

<textarea-limitnew 
    :val.sync="applyServiceData.reason"
    placeholder="请描述申请售后服务的具体原因"
    limit="50"
></textarea-limitnew>

需要注意的几个位置:

1.props 里面给默认值的时候,如果type是Array 或 Object,需要使用函数return回来,如上代码props里面autosize
2.props 如果type是多个类型,可用数组表示,如上代码props里面limit
3.props传进来的值 不能被更改,所以传进来的val, 我们使用value保存一下,然后操作value。另外有个问题,组件只会在创建的时候 赋值一次,所以我在页面加了个watch监听val,避免出现如下问题:比如我们有个弹框使用的是v-show,没用v-if。弹框里面有这个组件,当我们第一次打开弹框的时候val和value都为空,我们编辑后val和value都有值了,然后在父页面关掉弹框,并且重置值。接下来再打开弹框的时候,会发现val在父页面被清空了,但是value在子组件里面还是上次的值,所以需要加个watch再赋值一遍。(用v-if的话忽略这点)
4.如果想在父组件调用子组件里面的方法(比如函数名为childFun),可以给子组件加上ref="test",在父组件中使用this.$refs.test.childFun()就可以调用到了
5.接下来这点就是本文的主题了。使用组件的时候带上.sync修饰符,然后在子组件里面emit的时候写法如上代码this.$emit('update:val',this.value);
update:val里面的val是传进来的值的字段名字。这样子在父页面就不需要赋值一次了。

最后效果如下:


image.png image.png image.png
上一篇下一篇

猜你喜欢

热点阅读